commit 689276ea7dbe405be04ad5ef6004ab8d7aa31ab1 Author: Fox Date: Tue Jun 23 17:47:07 2026 +0100 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0808c4a --- /dev/null +++ b/.gitignore @@ -0,0 +1,482 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from `dotnet new gitignore` + +# dotenv files +.env + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +# but not Directory.Build.rsp, as it configures directory-level build defaults +!Directory.Build.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +.idea/ + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# content below from: https://github.com/github/gitignore/blob/main/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/main/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Vim temporary swap files +*.swp diff --git a/README.md b/README.md new file mode 100644 index 0000000..22517a5 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# README + diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..f0dfe09 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,16 @@ +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build +WORKDIR /App + +# Copy everything +COPY . ./ +# Restore as distinct layers +RUN dotnet restore +# Build and publish a release +RUN dotnet publish -o out + +# Build runtime image +FROM mcr.microsoft.com/dotnet/aspnet:10.0 +VOLUME /data +WORKDIR /App +COPY --from=build /App/out . +ENTRYPOINT ["dotnet", "SolicitorsApi.dll"] \ No newline at end of file diff --git a/backend/SolicitorsApi.slnx b/backend/SolicitorsApi.slnx new file mode 100644 index 0000000..f7accb8 --- /dev/null +++ b/backend/SolicitorsApi.slnx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/backend/SolicitorsApi/Program.cs b/backend/SolicitorsApi/Program.cs new file mode 100644 index 0000000..c03d35d --- /dev/null +++ b/backend/SolicitorsApi/Program.cs @@ -0,0 +1,176 @@ +using System.ComponentModel; +using Microsoft.AspNetCore.Mvc; +using Solicitors.CacheBuild; +using Solicitors.Core; +using Solicitors.Core.Misc; +using Solicitors.Core.Models; +using Solicitors.Data; +using Solicitors.Data.RepositorySetup.Sqlite; +using Solicitors.HtmlParsing; + + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddOpenApi(); +builder.Services.AddCore(); +builder.Services.AddData(new SqliteDbSetupOptions("demo")); +builder.Services.AddCacheBuild(); +builder.Services.AddHtmlParsing(); +builder.Services.AddHttpClient(); +builder.Services.AddCors(options => +{ + options.AddDefaultPolicy(policy => policy.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin()); +}); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.MapOpenApi(); +} + +app.UseHttpsRedirection(); +app.UseCors(); + +app.MapGet( + "/conveyancors", + ( + [FromServices] IReadOnlySolicitorService solicitorService, + CancellationToken cancellationToken, + [FromQuery] uint pageNumber = 1, + [FromQuery] uint pageSize = 20, + [FromQuery] string? nameFilter = null, + [FromQuery] decimal minRating = 0, + [FromQuery] string[]? cities = null, + [FromQuery] string ratingsProvider = "Solicitors.com", + [FromQuery] string? orderingType = null) => + { + IFilter? filter = null; + + if (!string.IsNullOrEmpty(nameFilter)) + filter = new WrapperFilter(filter, solicitor => solicitor.Name.Contains(nameFilter)); + + if (cities is not null && cities.Length > 0) + filter = new WrapperFilter(filter, solicitor => cities.Any(city => solicitor.Cities.Any(solCity => solCity.Name == city))); + + if (minRating > 0) + filter = new WrapperFilter( + filter, + solicitor => solicitor.Ratings.Any(rating => (rating.Provider == ratingsProvider) && (rating.Value / rating.Maximum >= minRating / 5.0m))); + + IComparer? ordering = orderingType switch + { + "rating-asc" => new RatingComparer(ratingsProvider, true), + "rating-desc" => new RatingComparer(ratingsProvider, false), + "alphabet-asc" => new NameComparer(true), + "alphabet-desc" => new NameComparer(false), + _ => null + }; + + return solicitorService.GetSolicitorSummariesAsync( + new Pagination(pageNumber, pageSize), + ratingsProvider, + filter, + ordering, + cancellationToken: cancellationToken); + } +); + +app.MapGet( + "/cities", + ( + [FromServices] IReadOnlyCitiesService citiesService, + CancellationToken cancellationToken) => + { + return citiesService.GetAllCitiesAsync(cancellationToken); + } +); + +app.MapGet( + "/conveyancors/{id}", + ( + [FromServices] IReadOnlySolicitorService solicitorService, + [FromRoute] Guid id, + CancellationToken cancellationToken + ) => solicitorService.GetSolicitorInfoByIdAsync(id, cancellationToken) +); + +app.MapGet( + "/ratingsProviders", + ( + [FromServices] IRatingsProviderService service, + CancellationToken cancellationToken + ) => + { + return service.GetRatingsProvidersAsync(cancellationToken); + } +); + +using (var scope = app.Services.CreateScope()) +{ + var solicitors = scope.ServiceProvider.GetRequiredService(); + var first = await solicitors + .GetSolicitorSummariesAsync( + new Pagination(1, 1), + "Solicitors.com", + cancellationToken: CancellationToken.None); + if (first.Data.Length == 0) + await scope.ServiceProvider + .GetRequiredService() + .RunFullImport(CancellationToken.None); +} + +app.Run(); + +public class RatingComparer(string ratingsProvider, bool ascending) : IComparer +{ + public int Compare(Solicitor? x, Solicitor? y) + { + var xRating = x?.Ratings?.FirstOrDefault(r => r.Provider == ratingsProvider); + var yRating = y?.Ratings?.FirstOrDefault(r => r.Provider == ratingsProvider); + + decimal compare; + + if (xRating is null) + compare = yRating is null ? 0 : 1; + else if (yRating is null) + compare = -1; + else + { + compare = (xRating.Value / xRating.Maximum) - (yRating.Value / yRating.Maximum); + + if (!ascending) + compare *= -1; + } + + if (compare >= 0) + return (int)Math.Ceiling(compare); + else + return (int)Math.Floor(compare); + + } +} + +public class NameComparer(bool ascending) : IComparer +{ + public int Compare(Solicitor? x, Solicitor? y) + { + int compare; + if (ReferenceEquals(x, y)) + compare = 0; + else if (y is null) + compare = 1; + else if (x is null) + compare = -1; + else + { + compare = string.Compare(x.Name, y.Name, StringComparison.OrdinalIgnoreCase); + + if (!ascending) + compare *= -1; + } + + return compare; + } +} \ No newline at end of file diff --git a/backend/SolicitorsApi/Properties/launchSettings.json b/backend/SolicitorsApi/Properties/launchSettings.json new file mode 100644 index 0000000..3abbdbf --- /dev/null +++ b/backend/SolicitorsApi/Properties/launchSettings.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "http://localhost:5084", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "https://localhost:7128;http://localhost:5084", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/backend/SolicitorsApi/SolicitorsApi.csproj b/backend/SolicitorsApi/SolicitorsApi.csproj new file mode 100644 index 0000000..28d473a --- /dev/null +++ b/backend/SolicitorsApi/SolicitorsApi.csproj @@ -0,0 +1,24 @@ + + + + net10.0 + enable + enable + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + diff --git a/backend/SolicitorsApi/SolicitorsApi.http b/backend/SolicitorsApi/SolicitorsApi.http new file mode 100644 index 0000000..a6c02e2 --- /dev/null +++ b/backend/SolicitorsApi/SolicitorsApi.http @@ -0,0 +1,6 @@ +@SolicitorsApi_HostAddress = http://localhost:5084 + +GET {{SolicitorsApi_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/backend/SolicitorsApi/appsettings.Development.json b/backend/SolicitorsApi/appsettings.Development.json new file mode 100644 index 0000000..ff66ba6 --- /dev/null +++ b/backend/SolicitorsApi/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/backend/SolicitorsApi/appsettings.json b/backend/SolicitorsApi/appsettings.json new file mode 100644 index 0000000..4d56694 --- /dev/null +++ b/backend/SolicitorsApi/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/backend/Tester/Program.cs b/backend/Tester/Program.cs new file mode 100644 index 0000000..1d6f986 --- /dev/null +++ b/backend/Tester/Program.cs @@ -0,0 +1,10 @@ +using Microsoft.Extensions.DependencyInjection; +using Solicitors.HtmlParsing; + +var _html = File.ReadAllText("/var/home/fox/main.html"); +var services = new ServiceCollection(); +services.AddHtmlParsing(); +var parser = services.BuildServiceProvider().GetRequiredService(); + +var htmlNodes = parser.ParseHtml(_html).ToArray(); +Console.ReadKey(); \ No newline at end of file diff --git a/backend/Tester/Tester.csproj b/backend/Tester/Tester.csproj new file mode 100644 index 0000000..dd248af --- /dev/null +++ b/backend/Tester/Tester.csproj @@ -0,0 +1,24 @@ + + + + Exe + net10.0 + enable + enable + + + + + ..\..\..\..\..\..\..\..\var\home\fox\.dotnet\shared\Microsoft.AspNetCore.App\10.0.7\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + + + + + + + + + + + diff --git a/backend/libs/Solicitors.CacheBuild/DIExtensions.cs b/backend/libs/Solicitors.CacheBuild/DIExtensions.cs new file mode 100644 index 0000000..4b8ab16 --- /dev/null +++ b/backend/libs/Solicitors.CacheBuild/DIExtensions.cs @@ -0,0 +1,15 @@ +using System.Diagnostics.CodeAnalysis; +using Microsoft.Extensions.DependencyInjection; + +namespace Solicitors.CacheBuild; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +public static class DIExtensions +{ + public static IServiceCollection AddCacheBuild(this IServiceCollection services) + { + return services + .AddScoped() + .AddScoped(); + } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.CacheBuild/ISolicitorImporter.cs b/backend/libs/Solicitors.CacheBuild/ISolicitorImporter.cs new file mode 100644 index 0000000..791c72c --- /dev/null +++ b/backend/libs/Solicitors.CacheBuild/ISolicitorImporter.cs @@ -0,0 +1,6 @@ +namespace Solicitors.CacheBuild; + +public interface ISolicitorImporter +{ + Task RunFullImport(CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/backend/libs/Solicitors.CacheBuild/ISolicitorParser.cs b/backend/libs/Solicitors.CacheBuild/ISolicitorParser.cs new file mode 100644 index 0000000..0119a8c --- /dev/null +++ b/backend/libs/Solicitors.CacheBuild/ISolicitorParser.cs @@ -0,0 +1,9 @@ +using Solicitors.Core.Models.Imports; + +namespace Solicitors.CacheBuild; + +internal interface ISolicitorParser +{ + Task GetSolicitorsAsync( + CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/backend/libs/Solicitors.CacheBuild/SolicitorImporter.cs b/backend/libs/Solicitors.CacheBuild/SolicitorImporter.cs new file mode 100644 index 0000000..348be45 --- /dev/null +++ b/backend/libs/Solicitors.CacheBuild/SolicitorImporter.cs @@ -0,0 +1,29 @@ +using Solicitors.Core.Data; +using Solicitors.Core.Models.Imports; + +namespace Solicitors.CacheBuild; + +internal class SolicitorImporter : ISolicitorImporter +{ + private readonly ISolicitorParser _parser; + private readonly ISolicitorRepository _repository; + + public SolicitorImporter( + ISolicitorParser parser, + ISolicitorRepository repository) + { + _parser = parser; + _repository = repository; + } + + public async Task RunFullImport(CancellationToken cancellationToken) + { + foreach (var solicitor in await _parser.GetSolicitorsAsync(cancellationToken)) + { + await RunImport(solicitor, cancellationToken); + } + } + + private Task RunImport(SolicitorData solicitor, CancellationToken cancellationToken) + => _repository.AddOrUpdateSolicitorAsync(solicitor, cancellationToken); +} \ No newline at end of file diff --git a/backend/libs/Solicitors.CacheBuild/Solicitors.CacheBuild.csproj b/backend/libs/Solicitors.CacheBuild/Solicitors.CacheBuild.csproj new file mode 100644 index 0000000..66de5d2 --- /dev/null +++ b/backend/libs/Solicitors.CacheBuild/Solicitors.CacheBuild.csproj @@ -0,0 +1,18 @@ + + + + net10.0 + enable + enable + + + + + + + + + + + + diff --git a/backend/libs/Solicitors.CacheBuild/SolicitorsDotCom/Consts.cs b/backend/libs/Solicitors.CacheBuild/SolicitorsDotCom/Consts.cs new file mode 100644 index 0000000..b6c3840 --- /dev/null +++ b/backend/libs/Solicitors.CacheBuild/SolicitorsDotCom/Consts.cs @@ -0,0 +1,14 @@ +namespace Solicitors.CacheBuild.SolicitorsDotCom; + +internal static class Consts +{ + public const string BaseUrl = "https://www.solicitors.com"; + public static readonly string[] Locations = + [ + "london", "birmingham", "leeds", "manchester", "sheffield", "bradford", "liverpool", "bristol" + ]; + + public const decimal MaxRating = 5.0m; + public const string Name = "Solicitors.com"; + public const string IconPath = "/images/logo.svg"; +} \ No newline at end of file diff --git a/backend/libs/Solicitors.CacheBuild/SolicitorsDotCom/SolicitorBuilder.cs b/backend/libs/Solicitors.CacheBuild/SolicitorsDotCom/SolicitorBuilder.cs new file mode 100644 index 0000000..d7c290c --- /dev/null +++ b/backend/libs/Solicitors.CacheBuild/SolicitorsDotCom/SolicitorBuilder.cs @@ -0,0 +1,31 @@ +namespace Solicitors.CacheBuild.SolicitorsDotCom; + +internal class SolicitorBuilder +{ + private readonly HashSet _baseLocations = []; + + public SolicitorBuilder( + string name, + string path, + string? shortDesc, + string baseLocation) + { + Name = name; + ShortDescription = shortDesc; + _baseLocations.Add(baseLocation); + + Path = path; + } + + public void AddBaseLocation(string baseLocation) + { + _baseLocations.Add(baseLocation); + } + + public string Path { get; } + public string Name { get; } + + public string? ShortDescription { get; } + + public string[] BaseLocations => _baseLocations.ToArray(); +} \ No newline at end of file diff --git a/backend/libs/Solicitors.CacheBuild/SolicitorsDotCom/SolicitorParser.cs b/backend/libs/Solicitors.CacheBuild/SolicitorsDotCom/SolicitorParser.cs new file mode 100644 index 0000000..76b56b1 --- /dev/null +++ b/backend/libs/Solicitors.CacheBuild/SolicitorsDotCom/SolicitorParser.cs @@ -0,0 +1,316 @@ +using System.Diagnostics.CodeAnalysis; +using System.Net.Http.Headers; +using Solicitors.Core.Misc; +using Solicitors.Core.Models.Imports; +using Solicitors.HtmlParsing; +using Solicitors.HtmlParsing.Models; + +namespace Solicitors.CacheBuild.SolicitorsDotCom; + +internal class SolicitorParser : ISolicitorParser +{ + private readonly HttpClient _client; + private readonly IHtmlParser _htmlParser; + + public SolicitorParser( + HttpClient client, + IHtmlParser htmlParser) + { + _client = client; + _client.BaseAddress = new Uri(Consts.BaseUrl); + + _htmlParser = htmlParser; + } + + public async Task GetSolicitorsAsync( + CancellationToken cancellationToken = default) + { + var builders = new Dictionary(); + + foreach (var location in Consts.Locations) + { + var httpRequest = new HttpRequestMessage(HttpMethod.Get, $"/conveyancing+{location}.html"); + httpRequest.Headers.Add("User-Agent", "Solicitors API Cache"); + var httpResponse = await _client.SendAsync(httpRequest, cancellationToken); + var html = await httpResponse.Content.ReadAsStringAsync(cancellationToken); + var nodes = _htmlParser.ParseHtml(html); + IHtmlNode? mainNode = null; + foreach (var node in nodes) + if (node.TryGetByTagName("main", out mainNode)) + break; + + if (TryGetResultSection(mainNode, out var results)) + ParseResultsSection(results, location, builders); + } + + var batches = builders.Values + .Select(builder => GetFullSolicitorDataAsync(builder, cancellationToken)) + .Batch(5); + + var solicitors = new List(); + foreach (var batch in batches) + solicitors.AddRange(await Task.WhenAll(batch)); + + return solicitors + .Where(x => x is not null) + .Cast() + .ToArray(); + } + + private bool TryGetResultSection( + IHtmlNode? mainNode, + [NotNullWhen(true)] out IEnumerable? results) + { + results = null; + + // going one level at a time helps a little with performance here, at the cost of messier code + return mainNode is not null + && mainNode.TryGetByTagNameAndClass("div", "content-holder", out var contentHolderNode) + && contentHolderNode.TryGetByTagNameAndClass("div", "container", out var containerNode) + && containerNode.TryGetByTagNameAndClass("div", "content", out var contentNode) + && contentNode.TryGetByTagNameAndClass("div", "result-section", out var resultSectionNode) + && resultSectionNode.TryGetChildren(out results); + } + + private void ParseResultsSection( + IEnumerable results, + string location, + Dictionary builders) + { + foreach (var result in results) + { + if (result.TryGetByClass("result-item", out var resultItem, true) + && TryParseToNewBuilder(resultItem, location, out var builder)) + { + if (!builders.TryAdd(builder.Path, builder)) + builders[builder.Path].AddBaseLocation(location); + } + } + } + + private bool TryParseToNewBuilder( + IHtmlNode resultItemNode, + string baseLocation, + [NotNullWhen(true)] out SolicitorBuilder? builder) + { + builder = null; + if (!resultItemNode.TryGetByTagNameAndClass("a", "link-map", out var linkMapNode) + || !linkMapNode.TryGetAttributeValue("href", out var uniqueUrl) + || !resultItemNode.TryGetByTagNameAndClass("span", "h2", out var titleNode) + || !titleNode.TryGetChildren(out var titleChildren)) + return false; + + string? name = null; + foreach (var child in titleChildren) + if (child.TryGetText(out name)) + break; + + if (name is null) + return false; + + string? shortDesc = null; + if (resultItemNode.TryGetByTagName("p", out var pNode) + && pNode.TryGetChildren(out var pChildren)) + foreach (var child in pChildren) + if (child.TryGetText(out shortDesc)) + break; + + builder = new SolicitorBuilder(name, uniqueUrl, shortDesc, baseLocation); + return true; + } + + private async Task GetFullSolicitorDataAsync( + SolicitorBuilder builder, + CancellationToken cancellationToken) + { + + var httpRequest = new HttpRequestMessage(HttpMethod.Get, builder.Path); + httpRequest.Headers.Add("User-Agent", "Solicitors API Cache"); + var httpResponse = await _client.SendAsync(httpRequest, cancellationToken); + var html = await httpResponse.Content.ReadAsStringAsync(cancellationToken); + var nodes = _htmlParser.ParseHtml(html); + IHtmlNode? mainNode = null; + foreach (var node in nodes) + if (node.TryGetByTagName("main", out mainNode)) + break; + + if (mainNode is null || !mainNode.TryGetByTagNameAndClass("div", "content-block", out var contentBlockNode)) + return null; + + Location[] offices = []; + if (contentBlockNode.TryGetByTagNameAndClass("div", "office-item", out var officeItemNode) + && officeItemNode.TryGetChildren(out var officeItems)) + { + offices = ParseOffices(officeItems); + } + + Rating[] ratings = []; + string? phone = null; + string? email = null; + string? website = null; + if (mainNode.TryGetByTagNameAndClass("div", "side-holder", out var sidebarNode) + && sidebarNode.TryGetChildren(out var sidebarChildren)) + { + ParseSidebar(sidebarChildren, out phone, out email, out website, out ratings); + } + + return new SolicitorData() + { + Name = builder.Name, + UrlPath = builder.Path, + ShortDescription = builder.ShortDescription, + Phone = phone, + Email = email, + Website = website, + Ratings = ratings, + Offices = offices, + Cities = builder.BaseLocations + }; + } + + Location[] ParseOffices(IEnumerable officeNodes) + => officeNodes + .Select(ParseOffice) + .Where(x => x is not null) + .Cast() + .ToArray(); + + Location? ParseOffice(IHtmlNode officeNode) + { + if (!officeNode.TryGetChildren(out var officeChildren) + || !officeNode.TryGetByTagName("address", out var addressNode) + || !addressNode.TryGetChildren(out var addressLines)) + return null; + + Location? location = null; + string? address = ""; + foreach (var line in addressLines) + { + if (line.TryGetText(out var lineText)) + address += lineText; + else if (line.TryGetByTagName("br", out _, true)) + address += "\n"; + } + + if (string.IsNullOrWhiteSpace(address)) + address = null; + + string? phone = null; + foreach (var child in officeChildren) + { + if (child.TryGetByTagName("a", out var anchor) + && anchor.TryGetAttributeValue("href", out var telString) + && telString.StartsWith("\"tel:") + && telString.Length > 5) + { + phone = telString.Substring(5, telString.Length - 6); + break; + } + } + + if (address is not null && phone is not null) + location = new Location(address, phone, []); + + return location; + } + + void ParseSidebar( + IEnumerable sidebarChildren, + out string? phone, + out string? email, + out string? website, + out Rating[] ratings) + { + List ratingsList = []; + phone = null; + website = null; + email = null; + + foreach (var node in sidebarChildren) + { + var isRevCount = node.TryGetByTagNameAndClass("div", "rev-count", out _, true); + var isLinksHolder = node.TryGetByTagNameAndClass("div", "links-holder", out _, true); + if ((!isRevCount && !isLinksHolder) + || !node.TryGetChildren(out var children)) + continue; + + if (isLinksHolder) + { + if (node.TryGetByTagNameAndClass("a", "website", out var websiteNode) + && websiteNode.TryGetAttributeValue("href", out website)) + website = website.Trim('"'); + + if (node.TryGetByTagNameAndClass("a", "phone", out var phoneNode) + && phoneNode.TryGetAttributeValue("href", out var phoneStr) + && phoneStr.StartsWith("\"tel:") + && phoneStr.Length > 5) + { + phone = phoneStr.Substring(5, phoneStr.Length - 6); + } + } + + var childrenArray = children as IHtmlNode[] ?? children.ToArray(); + foreach (var child in childrenArray.Where(x => x.TryGetByClass("rev-box", out _, true))) + { + if (child.TryGetAttributeValue("title", out var ratingString) + && TryParseRatingString(ratingString, out decimal rating, out decimal maxRating) + && child.TryGetByTagNameAndClass("img", "rev-logo", out var imgNode) + && imgNode.TryGetAttributeValue("src", out var imgSrc) + && TryParseRatingSrc(imgSrc, out var ratingProvider)) + { + ratingsList.Add(new Rating(rating, maxRating, ratingProvider, imgSrc)); + } + } + + if (ratingsList.Count == 0) + { + foreach (var child in childrenArray.Where(x => !x.HasAttribute("class"))) + { + if (child.TryGetChildren(out var grandChildren)) + foreach (var grandChild in grandChildren) + if (grandChild.TryGetText(out var textContent) + && TryParseOwnRatingString(textContent, out var rating)) + ratingsList.Add(new Rating(rating, Consts.MaxRating, Consts.Name, Consts.IconPath)); + } + } + } + + ratings = ratingsList.ToArray(); + } + + + bool TryParseRatingString(string ratingString, out decimal rating, out decimal maxRating) + { + rating = 0; + maxRating = 0; + var parts = ratingString.Trim('"').Split(" / "); + if (parts.Length != 2) + return false; + + return decimal.TryParse(parts[0], out rating) && decimal.TryParse(parts[1], out maxRating); + } + + bool TryParseRatingSrc(string imgSrc, out string provider) + { + provider = ""; + imgSrc = imgSrc.Trim('"'); + var prefix = "/images/logo-"; + if (!imgSrc.StartsWith(prefix)) + return false; + + var providerAndExtension = imgSrc.Substring(prefix.Length); + provider = providerAndExtension.Split('.').First(); + return true; + } + + bool TryParseOwnRatingString(string ratingString, out decimal rating) + { + rating = 0; + var prefix = "Average review score : "; + if (!ratingString.StartsWith(prefix)) + return false; + + var ratingPart = ratingString.Substring(prefix.Length); + return decimal.TryParse(ratingPart, out rating); + } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/DIExtensions.cs b/backend/libs/Solicitors.Core/DIExtensions.cs new file mode 100644 index 0000000..b7feb4f --- /dev/null +++ b/backend/libs/Solicitors.Core/DIExtensions.cs @@ -0,0 +1,17 @@ +using System.Diagnostics.CodeAnalysis; +using Microsoft.Extensions.DependencyInjection; + +namespace Solicitors.Core; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +public static class DIExtensions +{ + public static IServiceCollection AddCore(this IServiceCollection services) + { + return services + .AddScoped() + .AddScoped(sp => sp.GetRequiredService()) + .AddScoped() + .AddScoped(); + } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Data/IRatingsProviderRepository.cs b/backend/libs/Solicitors.Core/Data/IRatingsProviderRepository.cs new file mode 100644 index 0000000..1ce39af --- /dev/null +++ b/backend/libs/Solicitors.Core/Data/IRatingsProviderRepository.cs @@ -0,0 +1,6 @@ +namespace Solicitors.Core.Data; + +public interface IRatingsProviderRepository +{ + IAsyncEnumerable GetAllRatingsProvidersAsync(); +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Data/IReadOnlySolicitorRepository.cs b/backend/libs/Solicitors.Core/Data/IReadOnlySolicitorRepository.cs new file mode 100644 index 0000000..7314b88 --- /dev/null +++ b/backend/libs/Solicitors.Core/Data/IReadOnlySolicitorRepository.cs @@ -0,0 +1,14 @@ +using Solicitors.Core.Models; + +namespace Solicitors.Core.Data; + +public interface IReadOnlySolicitorRepository +{ + IAsyncEnumerable GetAllSolicitorsAsync(); + Task GetSolicitorByIdAsync(Guid id, CancellationToken cancellationToken = default); +} + +public interface IReadOnlyCitiesRepository +{ + IAsyncEnumerable GetCitiesAsync(CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Data/ISolicitorRepository.cs b/backend/libs/Solicitors.Core/Data/ISolicitorRepository.cs new file mode 100644 index 0000000..72dd972 --- /dev/null +++ b/backend/libs/Solicitors.Core/Data/ISolicitorRepository.cs @@ -0,0 +1,8 @@ +using Solicitors.Core.Models.Imports; + +namespace Solicitors.Core.Data; + +public interface ISolicitorRepository : IReadOnlySolicitorRepository +{ + Task AddOrUpdateSolicitorAsync(SolicitorData solicitor, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/IRatingsProviderService.cs b/backend/libs/Solicitors.Core/IRatingsProviderService.cs new file mode 100644 index 0000000..f8fb306 --- /dev/null +++ b/backend/libs/Solicitors.Core/IRatingsProviderService.cs @@ -0,0 +1,6 @@ +namespace Solicitors.Core; + +public interface IRatingsProviderService +{ + Task GetRatingsProvidersAsync(CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/IReadOnlyCitiesService.cs b/backend/libs/Solicitors.Core/IReadOnlyCitiesService.cs new file mode 100644 index 0000000..0322247 --- /dev/null +++ b/backend/libs/Solicitors.Core/IReadOnlyCitiesService.cs @@ -0,0 +1,6 @@ +namespace Solicitors.Core; + +public interface IReadOnlyCitiesService +{ + Task GetAllCitiesAsync(CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/IReadOnlySolicitorService.cs b/backend/libs/Solicitors.Core/IReadOnlySolicitorService.cs new file mode 100644 index 0000000..030270a --- /dev/null +++ b/backend/libs/Solicitors.Core/IReadOnlySolicitorService.cs @@ -0,0 +1,16 @@ +using Solicitors.Core.Misc; +using Solicitors.Core.Models; + +namespace Solicitors.Core; + +public interface IReadOnlySolicitorService +{ + Task> GetSolicitorSummariesAsync( + Pagination pagination, + string ratingsProvider, + IFilter? filter = null, + IComparer? ordering = null, + CancellationToken cancellationToken = default); + + Task GetSolicitorInfoByIdAsync(Guid id, CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/ISolicitorService.cs b/backend/libs/Solicitors.Core/ISolicitorService.cs new file mode 100644 index 0000000..1bc9d56 --- /dev/null +++ b/backend/libs/Solicitors.Core/ISolicitorService.cs @@ -0,0 +1,6 @@ +namespace Solicitors.Core; + +public interface ISolicitorService : IReadOnlySolicitorService +{ + +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Misc/DefaultSolicitorDataOrdering.cs b/backend/libs/Solicitors.Core/Misc/DefaultSolicitorDataOrdering.cs new file mode 100644 index 0000000..7621939 --- /dev/null +++ b/backend/libs/Solicitors.Core/Misc/DefaultSolicitorDataOrdering.cs @@ -0,0 +1,23 @@ +using Solicitors.Core.Models; + +namespace Solicitors.Core.Misc; + +internal class DefaultSolicitorDataOrdering : IComparer +{ + public static IComparer Instance { get; } = new DefaultSolicitorDataOrdering(); + + private DefaultSolicitorDataOrdering() + { + } + + public int Compare(Solicitor? x, Solicitor? y) + { + if (x is null) + return y is null ? 0 : int.MaxValue; + + else if (y is null) + return int.MinValue; + + return Comparer.Default.Compare(x.SolicitorId, y.SolicitorId); + } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Misc/EnumerableExtensions.cs b/backend/libs/Solicitors.Core/Misc/EnumerableExtensions.cs new file mode 100644 index 0000000..90be174 --- /dev/null +++ b/backend/libs/Solicitors.Core/Misc/EnumerableExtensions.cs @@ -0,0 +1,21 @@ +namespace Solicitors.Core.Misc; + +public static class EnumerableExtensions +{ + public static IEnumerable Batch(this IEnumerable source, int batchSize) + { + var batch = new List(batchSize); + foreach (var item in source) + { + batch.Add(item); + if (batch.Count == batch.Capacity) + { + yield return batch.ToArray(); + batch.Clear(); + } + } + + if (batch.Count > 0) + yield return batch.ToArray(); + } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Misc/IFilter.cs b/backend/libs/Solicitors.Core/Misc/IFilter.cs new file mode 100644 index 0000000..8e82d43 --- /dev/null +++ b/backend/libs/Solicitors.Core/Misc/IFilter.cs @@ -0,0 +1,29 @@ +namespace Solicitors.Core.Misc; + +public interface IFilter +{ + bool Filter(T item); +} + +public class WrapperFilter : IFilter +{ + private readonly Func _filter; + private readonly IFilter? _inner; + + public WrapperFilter( + IFilter? inner, + Func filter) + { + _inner = inner; + _filter = filter; + } + + + public bool Filter(T item) + { + if (_inner is not null) + return _inner.Filter(item) && _filter(item); + + return _filter(item); + } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Misc/Pagination.cs b/backend/libs/Solicitors.Core/Misc/Pagination.cs new file mode 100644 index 0000000..ed4168c --- /dev/null +++ b/backend/libs/Solicitors.Core/Misc/Pagination.cs @@ -0,0 +1,7 @@ +namespace Solicitors.Core.Misc; + +public readonly struct Pagination(uint currentPage, uint pageSize) +{ + public uint CurrentPage { get; } = currentPage; + public uint PageSize { get; } = pageSize; +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Models/City.cs b/backend/libs/Solicitors.Core/Models/City.cs new file mode 100644 index 0000000..f183649 --- /dev/null +++ b/backend/libs/Solicitors.Core/Models/City.cs @@ -0,0 +1,9 @@ +namespace Solicitors.Core.Models; + +public record City +{ + public Guid CityId { get; set; } + public required string Name { get; set; } + + public List Solicitors { get; } = new(); +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Models/Imports/Location.cs b/backend/libs/Solicitors.Core/Models/Imports/Location.cs new file mode 100644 index 0000000..14c6fb6 --- /dev/null +++ b/backend/libs/Solicitors.Core/Models/Imports/Location.cs @@ -0,0 +1,8 @@ +namespace Solicitors.Core.Models.Imports; + +public record Location(string address, string phone, Rating[] locationRatings) +{ + public string Address { get; } = address; + public string Phone { get; } = phone; + public Rating[] LocationRatings { get; } = locationRatings; +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Models/Imports/Rating.cs b/backend/libs/Solicitors.Core/Models/Imports/Rating.cs new file mode 100644 index 0000000..7893907 --- /dev/null +++ b/backend/libs/Solicitors.Core/Models/Imports/Rating.cs @@ -0,0 +1,9 @@ +namespace Solicitors.Core.Models.Imports; + +public record Rating(decimal value, decimal maxValue, string provider, string imgSrc) +{ + public decimal Value { get; } = value; + public decimal MaxValue { get; } = maxValue; + public string RatingProvider { get; } = provider; + public string RatingProviderImgSrc { get; } = imgSrc; +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Models/Imports/SolicitorData.cs b/backend/libs/Solicitors.Core/Models/Imports/SolicitorData.cs new file mode 100644 index 0000000..e3489e7 --- /dev/null +++ b/backend/libs/Solicitors.Core/Models/Imports/SolicitorData.cs @@ -0,0 +1,16 @@ +namespace Solicitors.Core.Models.Imports; + +public class SolicitorData +{ + public required string Name { get; init; } + public required string UrlPath { get; init; } + + public string? ShortDescription { get; init; } + public string? Phone { get; init; } + public string? Email { get; init; } + public string? Website { get; init; } + + public string[] Cities { get; init; } = []; + public Rating[] Ratings { get; init; } = []; + public Location[] Offices { get; init; } = []; +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Models/LocationInfo.cs b/backend/libs/Solicitors.Core/Models/LocationInfo.cs new file mode 100644 index 0000000..63ef4d6 --- /dev/null +++ b/backend/libs/Solicitors.Core/Models/LocationInfo.cs @@ -0,0 +1,18 @@ +namespace Solicitors.Core.Models; + +public record LocationInfo +{ + public LocationInfo(SolicitorLocation location) + { + Address = location.Address; + Phone = location.Phone; + Ratings = location.LocationRatings + .Select(rating => new RatingInfo(rating)) + .ToArray(); + } + + public string Address { get; } + public string Phone { get; } + + public RatingInfo[] Ratings { get; } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Models/RatingInfo.cs b/backend/libs/Solicitors.Core/Models/RatingInfo.cs new file mode 100644 index 0000000..9564194 --- /dev/null +++ b/backend/libs/Solicitors.Core/Models/RatingInfo.cs @@ -0,0 +1,15 @@ +namespace Solicitors.Core.Models; + +public record RatingInfo +{ + public RatingInfo(IRating rating) + { + Value = rating.Value; + Maximum = rating.Maximum; + Provider = rating.Provider; + } + + public decimal Value { get; } + public decimal Maximum { get; } + public string Provider { get; } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Models/Solicitor.cs b/backend/libs/Solicitors.Core/Models/Solicitor.cs new file mode 100644 index 0000000..0172467 --- /dev/null +++ b/backend/libs/Solicitors.Core/Models/Solicitor.cs @@ -0,0 +1,18 @@ +namespace Solicitors.Core.Models; + +public record Solicitor +{ + public Guid SolicitorId { get; set; } + + public required string Name { get; set; } + public required string RelativeUrl { get; set; } + + public string? Phone { get; set; } + public string? Email { get; set; } + public string? Website { get; set; } + public string? ShortDescription { get; set; } + + public List Cities { get; } = new(); + public List Ratings { get; } = new(); + public List Locations { get; } = new(); +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Models/SolicitorInfo.cs b/backend/libs/Solicitors.Core/Models/SolicitorInfo.cs new file mode 100644 index 0000000..ac7c5a2 --- /dev/null +++ b/backend/libs/Solicitors.Core/Models/SolicitorInfo.cs @@ -0,0 +1,38 @@ +namespace Solicitors.Core.Models; + +public record SolicitorInfo +{ + internal SolicitorInfo(Solicitor solicitor) + { + Id = solicitor.SolicitorId; + Name = solicitor.Name; + ShortDescription = solicitor.ShortDescription; + Phone = solicitor.Phone; + Email = solicitor.Email; + Website = solicitor.Website; + + Cities = solicitor.Cities + .Select(city => city.Name) + .ToArray(); + + Ratings = solicitor.Ratings + .Select(rating => new RatingInfo(rating)) + .ToArray(); + + Locations = solicitor.Locations + .Select(location => new LocationInfo(location)) + .ToArray(); + } + + public string Name { get; set; } + public string ShortDescription { get; set; } + public Guid Id { get; set; } + + public string? Phone { get; set; } + public string? Email { get; set; } + public string? Website { get; set; } + + public string[] Cities { get; set; } + public RatingInfo[] Ratings { get; set; } + public LocationInfo[] Locations { get; set; } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Models/SolicitorLocation.cs b/backend/libs/Solicitors.Core/Models/SolicitorLocation.cs new file mode 100644 index 0000000..84111b3 --- /dev/null +++ b/backend/libs/Solicitors.Core/Models/SolicitorLocation.cs @@ -0,0 +1,21 @@ +namespace Solicitors.Core.Models; + +public record SolicitorLocation +{ + public Guid SolicitorLocationId { get; set; } + + public required string Address { get; set; } + public required string Phone { get; set; } + + public List LocationRatings { get; } = new(); + + public Guid SolicitorId { get; set; } + public required Solicitor Solicitor { get; set; } +} + +public interface IRating +{ + decimal Value { get; } + decimal Maximum { get; } + string Provider { get; } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Models/SolicitorLocationRating.cs b/backend/libs/Solicitors.Core/Models/SolicitorLocationRating.cs new file mode 100644 index 0000000..f578ac8 --- /dev/null +++ b/backend/libs/Solicitors.Core/Models/SolicitorLocationRating.cs @@ -0,0 +1,13 @@ +namespace Solicitors.Core.Models; + +public record SolicitorLocationRating : IRating +{ + public Guid SolicitorLocationRatingId { get; set; } + + public required decimal Value { get; set; } + public required decimal Maximum { get; set; } + public required string Provider { get; set; } + + public Guid SolicitorLocationId { get; set; } + public required SolicitorLocation SolicitorLocation { get; set; } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Models/SolicitorRating.cs b/backend/libs/Solicitors.Core/Models/SolicitorRating.cs new file mode 100644 index 0000000..e8edae2 --- /dev/null +++ b/backend/libs/Solicitors.Core/Models/SolicitorRating.cs @@ -0,0 +1,13 @@ +namespace Solicitors.Core.Models; + +public record SolicitorRating : IRating +{ + public Guid SolicitorRatingId { get; set; } + + public required decimal Value { get; set; } + public required decimal Maximum { get; set; } + public required string Provider { get; set; } + + public Guid SolicitorId { get; set; } + public required Solicitor Solicitor { get; set; } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Models/SolicitorSummary.cs b/backend/libs/Solicitors.Core/Models/SolicitorSummary.cs new file mode 100644 index 0000000..da5f195 --- /dev/null +++ b/backend/libs/Solicitors.Core/Models/SolicitorSummary.cs @@ -0,0 +1,19 @@ +namespace Solicitors.Core.Models; + +public record SolicitorSummary +{ + internal SolicitorSummary(Solicitor solicitor, string ratingsProvider) + { + Id = solicitor.SolicitorId; + Name = solicitor.Name; + ShortDescription = solicitor.ShortDescription; + var rating = solicitor.Ratings.FirstOrDefault(x => x.Provider == ratingsProvider); + if (rating is not null) + Rating = new RatingInfo(rating); + } + + public Guid Id { get; } + public string Name { get; } + public string? ShortDescription { get; } + public RatingInfo? Rating { get; } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/PaginationResponse.cs b/backend/libs/Solicitors.Core/PaginationResponse.cs new file mode 100644 index 0000000..bd0694f --- /dev/null +++ b/backend/libs/Solicitors.Core/PaginationResponse.cs @@ -0,0 +1,7 @@ +namespace Solicitors.Core; + +public record PaginationResponse(int Total, T[] Data) +{ + public T[] Data { get; set; } = Data; + public int Total { get; set; } = Total; +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/RatingsProviderService.cs b/backend/libs/Solicitors.Core/RatingsProviderService.cs new file mode 100644 index 0000000..e4f2ed8 --- /dev/null +++ b/backend/libs/Solicitors.Core/RatingsProviderService.cs @@ -0,0 +1,18 @@ +using Solicitors.Core.Data; + +namespace Solicitors.Core; + +internal class RatingsProviderService : IRatingsProviderService +{ + private readonly IRatingsProviderRepository _repo; + + public RatingsProviderService(IRatingsProviderRepository repo) + { + _repo = repo; + } + + public async Task GetRatingsProvidersAsync(CancellationToken cancellationToken) + { + return await _repo.GetAllRatingsProvidersAsync().ToArrayAsync(cancellationToken); + } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/ReadOnlyCitiesService.cs b/backend/libs/Solicitors.Core/ReadOnlyCitiesService.cs new file mode 100644 index 0000000..28b8371 --- /dev/null +++ b/backend/libs/Solicitors.Core/ReadOnlyCitiesService.cs @@ -0,0 +1,19 @@ +using Solicitors.Core.Data; + +namespace Solicitors.Core; + +internal class ReadOnlyCitiesService : IReadOnlyCitiesService +{ + private readonly IReadOnlyCitiesRepository _repo; + + public ReadOnlyCitiesService(IReadOnlyCitiesRepository repo) + { + _repo = repo; + } + + public async Task GetAllCitiesAsync(CancellationToken cancellationToken) + { + var cities = _repo.GetCitiesAsync(cancellationToken); + return await cities.ToArrayAsync(cancellationToken); + } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/SolicitorService.cs b/backend/libs/Solicitors.Core/SolicitorService.cs new file mode 100644 index 0000000..ad329a0 --- /dev/null +++ b/backend/libs/Solicitors.Core/SolicitorService.cs @@ -0,0 +1,50 @@ +using Solicitors.Core.Data; +using Solicitors.Core.Misc; +using Solicitors.Core.Models; + +namespace Solicitors.Core; + +internal class SolicitorService : ISolicitorService +{ + private readonly IReadOnlySolicitorRepository _repo; + + public SolicitorService(IReadOnlySolicitorRepository repo) + { + _repo = repo; + } + + public async Task> GetSolicitorSummariesAsync( + Pagination pagination, + string ratingsProvider, + IFilter? filter = null, + IComparer? ordering = null, + CancellationToken cancellationToken = default) + { + var allSolicitors = _repo.GetAllSolicitorsAsync(); + if (filter is not null) + allSolicitors = allSolicitors.Where(filter.Filter); + + var matchingSolicitors = await allSolicitors.ToArrayAsync(cancellationToken); + + if (ordering is null) + ordering = DefaultSolicitorDataOrdering.Instance; + + var results = matchingSolicitors + .OrderBy(x => x, ordering) + .Skip((int)((pagination.CurrentPage - 1) * pagination.PageSize)) + .Take((int)pagination.PageSize) + .Select(x => new SolicitorSummary(x, ratingsProvider)) + .ToArray(); + + return new PaginationResponse(matchingSolicitors.Length, results); + } + + public async Task GetSolicitorInfoByIdAsync(Guid id, CancellationToken cancellationToken = default) + { + var data = await _repo.GetSolicitorByIdAsync(id, cancellationToken); + if (data is null) + return null; + + return new SolicitorInfo(data); + } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Core/Solicitors.Core.csproj b/backend/libs/Solicitors.Core/Solicitors.Core.csproj new file mode 100644 index 0000000..faad367 --- /dev/null +++ b/backend/libs/Solicitors.Core/Solicitors.Core.csproj @@ -0,0 +1,13 @@ + + + + net10.0 + enable + enable + + + + + + + diff --git a/backend/libs/Solicitors.Data/DIExtensions.cs b/backend/libs/Solicitors.Data/DIExtensions.cs new file mode 100644 index 0000000..a8cda75 --- /dev/null +++ b/backend/libs/Solicitors.Data/DIExtensions.cs @@ -0,0 +1,36 @@ +using System.Diagnostics.CodeAnalysis; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Solicitors.Core; +using Solicitors.Core.Data; +using Solicitors.Data.RepositorySetup; +using Solicitors.Data.RepositorySetup.InMemory; +using Solicitors.Data.RepositorySetup.Sqlite; + +namespace Solicitors.Data; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +public static class DIExtensions +{ + public static IServiceCollection AddData(this IServiceCollection services, IRepoSetupOptions options) + { + return services + .AddScoped() + .AddScoped(sp => sp.GetRequiredService()) + .AddScoped(sp => sp.GetRequiredService()) + .AddScoped(sp => sp.GetRequiredService()) + .AddScoped(sp => sp.GetRequiredService()) + .AddSingleton(GetSetupService(options)); + } + + private static IRepoSetupService GetSetupService(IRepoSetupOptions options) + { + if (options is InMemoryDbSetupOptions inMemOptions) + return new InMemorySetupService(inMemOptions); + + if (options is SqliteDbSetupOptions sqliteOptions) + return new SqliteSetupService(sqliteOptions); + + throw new ArgumentException("Options type not supported", nameof(options)); + } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Data/Migrations/20260622195820_InitialCreate.Designer.cs b/backend/libs/Solicitors.Data/Migrations/20260622195820_InitialCreate.Designer.cs new file mode 100644 index 0000000..0b8622e --- /dev/null +++ b/backend/libs/Solicitors.Data/Migrations/20260622195820_InitialCreate.Designer.cs @@ -0,0 +1,222 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Solicitors.Data; + +#nullable disable + +namespace Solicitors.Data.Migrations +{ + [DbContext(typeof(SolicitorsRepository))] + [Migration("20260622195820_InitialCreate")] + partial class InitialCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "10.0.9"); + + modelBuilder.Entity("CitySolicitor", b => + { + b.Property("CitiesCityId") + .HasColumnType("TEXT"); + + b.Property("SolicitorsSolicitorId") + .HasColumnType("TEXT"); + + b.HasKey("CitiesCityId", "SolicitorsSolicitorId"); + + b.HasIndex("SolicitorsSolicitorId"); + + b.ToTable("CitySolicitor"); + }); + + modelBuilder.Entity("Solicitors.Core.Models.City", b => + { + b.Property("CityId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("CityId"); + + b.ToTable("Cities"); + }); + + modelBuilder.Entity("Solicitors.Core.Models.Solicitor", b => + { + b.Property("SolicitorId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Phone") + .HasColumnType("TEXT"); + + b.Property("RelativeUrl") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ShortDescription") + .HasColumnType("TEXT"); + + b.Property("Website") + .HasColumnType("TEXT"); + + b.HasKey("SolicitorId"); + + b.ToTable("Solicitors"); + }); + + modelBuilder.Entity("Solicitors.Core.Models.SolicitorLocation", b => + { + b.Property("SolicitorLocationId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Address") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Phone") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("SolicitorId") + .HasColumnType("TEXT"); + + b.HasKey("SolicitorLocationId"); + + b.HasIndex("SolicitorId"); + + b.ToTable("SolicitorLocations"); + }); + + modelBuilder.Entity("Solicitors.Core.Models.SolicitorLocationRating", b => + { + b.Property("SolicitorLocationRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Maximum") + .HasColumnType("TEXT"); + + b.Property("Provider") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("SolicitorLocationId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("SolicitorLocationRatingId"); + + b.HasIndex("SolicitorLocationId"); + + b.ToTable("SolicitorLocationRatings"); + }); + + modelBuilder.Entity("Solicitors.Core.Models.SolicitorRating", b => + { + b.Property("SolicitorRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Maximum") + .HasColumnType("TEXT"); + + b.Property("Provider") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("SolicitorId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("SolicitorRatingId"); + + b.HasIndex("SolicitorId"); + + b.ToTable("SolicitorRatings"); + }); + + modelBuilder.Entity("CitySolicitor", b => + { + b.HasOne("Solicitors.Core.Models.City", null) + .WithMany() + .HasForeignKey("CitiesCityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Solicitors.Core.Models.Solicitor", null) + .WithMany() + .HasForeignKey("SolicitorsSolicitorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Solicitors.Core.Models.SolicitorLocation", b => + { + b.HasOne("Solicitors.Core.Models.Solicitor", "Solicitor") + .WithMany("Locations") + .HasForeignKey("SolicitorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Solicitor"); + }); + + modelBuilder.Entity("Solicitors.Core.Models.SolicitorLocationRating", b => + { + b.HasOne("Solicitors.Core.Models.SolicitorLocation", "SolicitorLocation") + .WithMany("LocationRatings") + .HasForeignKey("SolicitorLocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("SolicitorLocation"); + }); + + modelBuilder.Entity("Solicitors.Core.Models.SolicitorRating", b => + { + b.HasOne("Solicitors.Core.Models.Solicitor", "Solicitor") + .WithMany("Ratings") + .HasForeignKey("SolicitorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Solicitor"); + }); + + modelBuilder.Entity("Solicitors.Core.Models.Solicitor", b => + { + b.Navigation("Locations"); + + b.Navigation("Ratings"); + }); + + modelBuilder.Entity("Solicitors.Core.Models.SolicitorLocation", b => + { + b.Navigation("LocationRatings"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/libs/Solicitors.Data/Migrations/20260622195820_InitialCreate.cs b/backend/libs/Solicitors.Data/Migrations/20260622195820_InitialCreate.cs new file mode 100644 index 0000000..708be18 --- /dev/null +++ b/backend/libs/Solicitors.Data/Migrations/20260622195820_InitialCreate.cs @@ -0,0 +1,172 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Solicitors.Data.Migrations +{ + /// + public partial class InitialCreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Cities", + columns: table => new + { + CityId = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Cities", x => x.CityId); + }); + + migrationBuilder.CreateTable( + name: "Solicitors", + columns: table => new + { + SolicitorId = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", nullable: false), + RelativeUrl = table.Column(type: "TEXT", nullable: false), + Phone = table.Column(type: "TEXT", nullable: true), + Email = table.Column(type: "TEXT", nullable: true), + Website = table.Column(type: "TEXT", nullable: true), + ShortDescription = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Solicitors", x => x.SolicitorId); + }); + + migrationBuilder.CreateTable( + name: "CitySolicitor", + columns: table => new + { + CitiesCityId = table.Column(type: "TEXT", nullable: false), + SolicitorsSolicitorId = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CitySolicitor", x => new { x.CitiesCityId, x.SolicitorsSolicitorId }); + table.ForeignKey( + name: "FK_CitySolicitor_Cities_CitiesCityId", + column: x => x.CitiesCityId, + principalTable: "Cities", + principalColumn: "CityId", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_CitySolicitor_Solicitors_SolicitorsSolicitorId", + column: x => x.SolicitorsSolicitorId, + principalTable: "Solicitors", + principalColumn: "SolicitorId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "SolicitorLocations", + columns: table => new + { + SolicitorLocationId = table.Column(type: "TEXT", nullable: false), + Address = table.Column(type: "TEXT", nullable: false), + Phone = table.Column(type: "TEXT", nullable: false), + SolicitorId = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SolicitorLocations", x => x.SolicitorLocationId); + table.ForeignKey( + name: "FK_SolicitorLocations_Solicitors_SolicitorId", + column: x => x.SolicitorId, + principalTable: "Solicitors", + principalColumn: "SolicitorId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "SolicitorRatings", + columns: table => new + { + SolicitorRatingId = table.Column(type: "TEXT", nullable: false), + Value = table.Column(type: "TEXT", nullable: false), + Maximum = table.Column(type: "TEXT", nullable: false), + Provider = table.Column(type: "TEXT", nullable: false), + SolicitorId = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SolicitorRatings", x => x.SolicitorRatingId); + table.ForeignKey( + name: "FK_SolicitorRatings_Solicitors_SolicitorId", + column: x => x.SolicitorId, + principalTable: "Solicitors", + principalColumn: "SolicitorId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "SolicitorLocationRatings", + columns: table => new + { + SolicitorLocationRatingId = table.Column(type: "TEXT", nullable: false), + Value = table.Column(type: "TEXT", nullable: false), + Maximum = table.Column(type: "TEXT", nullable: false), + Provider = table.Column(type: "TEXT", nullable: false), + SolicitorLocationId = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SolicitorLocationRatings", x => x.SolicitorLocationRatingId); + table.ForeignKey( + name: "FK_SolicitorLocationRatings_SolicitorLocations_SolicitorLocationId", + column: x => x.SolicitorLocationId, + principalTable: "SolicitorLocations", + principalColumn: "SolicitorLocationId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_CitySolicitor_SolicitorsSolicitorId", + table: "CitySolicitor", + column: "SolicitorsSolicitorId"); + + migrationBuilder.CreateIndex( + name: "IX_SolicitorLocationRatings_SolicitorLocationId", + table: "SolicitorLocationRatings", + column: "SolicitorLocationId"); + + migrationBuilder.CreateIndex( + name: "IX_SolicitorLocations_SolicitorId", + table: "SolicitorLocations", + column: "SolicitorId"); + + migrationBuilder.CreateIndex( + name: "IX_SolicitorRatings_SolicitorId", + table: "SolicitorRatings", + column: "SolicitorId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "CitySolicitor"); + + migrationBuilder.DropTable( + name: "SolicitorLocationRatings"); + + migrationBuilder.DropTable( + name: "SolicitorRatings"); + + migrationBuilder.DropTable( + name: "Cities"); + + migrationBuilder.DropTable( + name: "SolicitorLocations"); + + migrationBuilder.DropTable( + name: "Solicitors"); + } + } +} diff --git a/backend/libs/Solicitors.Data/Migrations/SolicitorsRepositoryModelSnapshot.cs b/backend/libs/Solicitors.Data/Migrations/SolicitorsRepositoryModelSnapshot.cs new file mode 100644 index 0000000..3552058 --- /dev/null +++ b/backend/libs/Solicitors.Data/Migrations/SolicitorsRepositoryModelSnapshot.cs @@ -0,0 +1,219 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Solicitors.Data; + +#nullable disable + +namespace Solicitors.Data.Migrations +{ + [DbContext(typeof(SolicitorsRepository))] + partial class SolicitorsRepositoryModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "10.0.9"); + + modelBuilder.Entity("CitySolicitor", b => + { + b.Property("CitiesCityId") + .HasColumnType("TEXT"); + + b.Property("SolicitorsSolicitorId") + .HasColumnType("TEXT"); + + b.HasKey("CitiesCityId", "SolicitorsSolicitorId"); + + b.HasIndex("SolicitorsSolicitorId"); + + b.ToTable("CitySolicitor"); + }); + + modelBuilder.Entity("Solicitors.Core.Models.City", b => + { + b.Property("CityId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("CityId"); + + b.ToTable("Cities"); + }); + + modelBuilder.Entity("Solicitors.Core.Models.Solicitor", b => + { + b.Property("SolicitorId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Phone") + .HasColumnType("TEXT"); + + b.Property("RelativeUrl") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ShortDescription") + .HasColumnType("TEXT"); + + b.Property("Website") + .HasColumnType("TEXT"); + + b.HasKey("SolicitorId"); + + b.ToTable("Solicitors"); + }); + + modelBuilder.Entity("Solicitors.Core.Models.SolicitorLocation", b => + { + b.Property("SolicitorLocationId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Address") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Phone") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("SolicitorId") + .HasColumnType("TEXT"); + + b.HasKey("SolicitorLocationId"); + + b.HasIndex("SolicitorId"); + + b.ToTable("SolicitorLocations"); + }); + + modelBuilder.Entity("Solicitors.Core.Models.SolicitorLocationRating", b => + { + b.Property("SolicitorLocationRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Maximum") + .HasColumnType("TEXT"); + + b.Property("Provider") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("SolicitorLocationId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("SolicitorLocationRatingId"); + + b.HasIndex("SolicitorLocationId"); + + b.ToTable("SolicitorLocationRatings"); + }); + + modelBuilder.Entity("Solicitors.Core.Models.SolicitorRating", b => + { + b.Property("SolicitorRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Maximum") + .HasColumnType("TEXT"); + + b.Property("Provider") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("SolicitorId") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("SolicitorRatingId"); + + b.HasIndex("SolicitorId"); + + b.ToTable("SolicitorRatings"); + }); + + modelBuilder.Entity("CitySolicitor", b => + { + b.HasOne("Solicitors.Core.Models.City", null) + .WithMany() + .HasForeignKey("CitiesCityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Solicitors.Core.Models.Solicitor", null) + .WithMany() + .HasForeignKey("SolicitorsSolicitorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Solicitors.Core.Models.SolicitorLocation", b => + { + b.HasOne("Solicitors.Core.Models.Solicitor", "Solicitor") + .WithMany("Locations") + .HasForeignKey("SolicitorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Solicitor"); + }); + + modelBuilder.Entity("Solicitors.Core.Models.SolicitorLocationRating", b => + { + b.HasOne("Solicitors.Core.Models.SolicitorLocation", "SolicitorLocation") + .WithMany("LocationRatings") + .HasForeignKey("SolicitorLocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("SolicitorLocation"); + }); + + modelBuilder.Entity("Solicitors.Core.Models.SolicitorRating", b => + { + b.HasOne("Solicitors.Core.Models.Solicitor", "Solicitor") + .WithMany("Ratings") + .HasForeignKey("SolicitorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Solicitor"); + }); + + modelBuilder.Entity("Solicitors.Core.Models.Solicitor", b => + { + b.Navigation("Locations"); + + b.Navigation("Ratings"); + }); + + modelBuilder.Entity("Solicitors.Core.Models.SolicitorLocation", b => + { + b.Navigation("LocationRatings"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/libs/Solicitors.Data/RepositorySetup/IRepoSetupOptions.cs b/backend/libs/Solicitors.Data/RepositorySetup/IRepoSetupOptions.cs new file mode 100644 index 0000000..6a0c460 --- /dev/null +++ b/backend/libs/Solicitors.Data/RepositorySetup/IRepoSetupOptions.cs @@ -0,0 +1,6 @@ +namespace Solicitors.Data.RepositorySetup; + +public interface IRepoSetupOptions +{ + +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Data/RepositorySetup/IRepoSetupService.cs b/backend/libs/Solicitors.Data/RepositorySetup/IRepoSetupService.cs new file mode 100644 index 0000000..7e13c54 --- /dev/null +++ b/backend/libs/Solicitors.Data/RepositorySetup/IRepoSetupService.cs @@ -0,0 +1,8 @@ +using Microsoft.EntityFrameworkCore; + +namespace Solicitors.Data.RepositorySetup; + +internal interface IRepoSetupService +{ + void OnConfiguring(DbContextOptionsBuilder optionsBuilder); +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Data/RepositorySetup/InMemory/InMemoryDbSetupOptions.cs b/backend/libs/Solicitors.Data/RepositorySetup/InMemory/InMemoryDbSetupOptions.cs new file mode 100644 index 0000000..3387933 --- /dev/null +++ b/backend/libs/Solicitors.Data/RepositorySetup/InMemory/InMemoryDbSetupOptions.cs @@ -0,0 +1,6 @@ +namespace Solicitors.Data.RepositorySetup.InMemory; + +public class InMemoryDbSetupOptions(string dbName) : IRepoSetupOptions +{ + public string DbName { get; } = dbName; +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Data/RepositorySetup/InMemory/InMemorySetupService.cs b/backend/libs/Solicitors.Data/RepositorySetup/InMemory/InMemorySetupService.cs new file mode 100644 index 0000000..3295f2b --- /dev/null +++ b/backend/libs/Solicitors.Data/RepositorySetup/InMemory/InMemorySetupService.cs @@ -0,0 +1,11 @@ +using Microsoft.EntityFrameworkCore; + +namespace Solicitors.Data.RepositorySetup.InMemory; + +internal class InMemorySetupService(InMemoryDbSetupOptions config) : IRepoSetupService +{ + public void OnConfiguring(DbContextOptionsBuilder options) + { + options.UseInMemoryDatabase(config.DbName); + } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Data/RepositorySetup/Sqlite/SqliteDbSetupOptions.cs b/backend/libs/Solicitors.Data/RepositorySetup/Sqlite/SqliteDbSetupOptions.cs new file mode 100644 index 0000000..7bc1f54 --- /dev/null +++ b/backend/libs/Solicitors.Data/RepositorySetup/Sqlite/SqliteDbSetupOptions.cs @@ -0,0 +1,6 @@ +namespace Solicitors.Data.RepositorySetup.Sqlite; + +public class SqliteDbSetupOptions(string dbName) : IRepoSetupOptions +{ + public string DbName { get; } = dbName; +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Data/RepositorySetup/Sqlite/SqliteSetupService.cs b/backend/libs/Solicitors.Data/RepositorySetup/Sqlite/SqliteSetupService.cs new file mode 100644 index 0000000..2568541 --- /dev/null +++ b/backend/libs/Solicitors.Data/RepositorySetup/Sqlite/SqliteSetupService.cs @@ -0,0 +1,16 @@ +using Microsoft.EntityFrameworkCore; + +namespace Solicitors.Data.RepositorySetup.Sqlite; + +internal class SqliteSetupService(SqliteDbSetupOptions config) : IRepoSetupService +{ + public void OnConfiguring(DbContextOptionsBuilder options) + { + var folder = Environment.SpecialFolder.MyDocuments; + var path = Environment.GetFolderPath(folder); + path = Path.Combine(path, "/data"); + var dbPath = System.IO.Path.Join(path, $"{config.DbName}.db"); + var dbString = $"Data Source={dbPath}"; + options.UseSqlite(dbString); + } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.Data/Solicitors.Data.csproj b/backend/libs/Solicitors.Data/Solicitors.Data.csproj new file mode 100644 index 0000000..5685344 --- /dev/null +++ b/backend/libs/Solicitors.Data/Solicitors.Data.csproj @@ -0,0 +1,20 @@ + + + + net10.0 + enable + enable + + + + + + + + + + + + + + diff --git a/backend/libs/Solicitors.Data/SolicitorsRepository.cs b/backend/libs/Solicitors.Data/SolicitorsRepository.cs new file mode 100644 index 0000000..de69605 --- /dev/null +++ b/backend/libs/Solicitors.Data/SolicitorsRepository.cs @@ -0,0 +1,157 @@ +using Microsoft.EntityFrameworkCore; +using Solicitors.Core; +using Solicitors.Core.Data; +using Solicitors.Core.Models; +using Solicitors.Core.Models.Imports; +using Solicitors.Data.RepositorySetup; + +namespace Solicitors.Data; + +internal class SolicitorsRepository : DbContext, ISolicitorRepository, IReadOnlyCitiesRepository, IRatingsProviderRepository +{ + private readonly IRepoSetupService _setup; + + public SolicitorsRepository(IRepoSetupService setup) + { + _setup = setup; + } + + public DbSet Solicitors { get; set; } + public DbSet SolicitorRatings { get; set; } + public DbSet SolicitorLocations { get; set; } + public DbSet SolicitorLocationRatings { get; set; } + public DbSet Cities { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => _setup.OnConfiguring(optionsBuilder); + + public IAsyncEnumerable GetAllSolicitorsAsync() + => Solicitors + .Include(solicitor => solicitor.Cities) + .Include(solicitor => solicitor.Locations) + .ThenInclude(location => location.LocationRatings) + .Include(solicitor => solicitor.Ratings) + .AsAsyncEnumerable(); + + public Task GetSolicitorByIdAsync(Guid id, CancellationToken cancellationToken = default) + => Solicitors + .Include(solicitor => solicitor.Cities) + .Include(solicitor => solicitor.Locations) + .ThenInclude(location => location.LocationRatings) + .Include(solicitor => solicitor.Ratings) + .FirstOrDefaultAsync(x => x.SolicitorId == id, cancellationToken); + + public async Task AddOrUpdateSolicitorAsync(SolicitorData solicitor, CancellationToken cancellationToken) + { + var matchingSolicitor = await Solicitors + .FirstOrDefaultAsync( + item => item.Name == solicitor.Name, + cancellationToken: cancellationToken); + + if (matchingSolicitor is null) + await AddNewSolicitor(solicitor, cancellationToken); + else + await UpdateExistingSolicitor(solicitor, matchingSolicitor, cancellationToken); + } + + private async Task AddNewSolicitor( + SolicitorData solicitor, + CancellationToken cancellationToken) + { + var newSol = new Solicitor() + { + Name = solicitor.Name, + RelativeUrl = solicitor.UrlPath, + Phone = solicitor.Phone, + Email = solicitor.Email, + Website = solicitor.Website, + ShortDescription = solicitor.ShortDescription + }; + Solicitors.Add(newSol); + + var cityTasks = solicitor.Cities + .Distinct() + .Select(async (city) => + { + var matchingCity = await Cities.FirstOrDefaultAsync( + item => item.Name == city, + cancellationToken: cancellationToken); + + if (matchingCity is null) + { + matchingCity = new City() { Name = city }; + Cities.Add(matchingCity); + newSol.Cities.Add(matchingCity); + } + + matchingCity.Solicitors.Add(newSol); + }); + await Task.WhenAll(cityTasks); + + foreach (var rating in solicitor.Ratings) + { + var newRating = new SolicitorRating() + { + Value = rating.Value, + Maximum = rating.MaxValue, + Provider = rating.RatingProvider, + Solicitor = newSol + }; + SolicitorRatings.Add(newRating); + newSol.Ratings.Add(newRating); + } + + foreach (var location in solicitor.Offices) + { + var newLocation = new SolicitorLocation() + { + Address = location.Address, + Phone = location.Phone, + Solicitor = newSol + }; + SolicitorLocations.Add(newLocation); + newSol.Locations.Add(newLocation); + + foreach (var rating in location.LocationRatings) + { + var newLocRating = new SolicitorLocationRating() + { + Value = rating.value, + Maximum = rating.MaxValue, + Provider = rating.RatingProvider, + SolicitorLocation = newLocation + }; + SolicitorLocationRatings.Add(newLocRating); + newLocation.LocationRatings.Add(newLocRating); + } + } + + await SaveChangesAsync(cancellationToken); + } + + private Task UpdateExistingSolicitor( + SolicitorData solicitor, + Solicitor matchingSolicitor, + CancellationToken cancellationToken) + { + // TODO + return Task.CompletedTask; + } + + public IAsyncEnumerable GetCitiesAsync(CancellationToken cancellationToken) + { + return Cities + .Select(city => city.Name) + .AsAsyncEnumerable(); + } + + public IAsyncEnumerable GetAllRatingsProvidersAsync() + { + return SolicitorRatings + .Select(rating => rating.Provider) + .Distinct() + .OrderBy(x => x == "Solicitors.com" ? 0 : 1) + .ThenBy(x => x) + .AsAsyncEnumerable(); + } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.HtmlParsing/DIExtensions.cs b/backend/libs/Solicitors.HtmlParsing/DIExtensions.cs new file mode 100644 index 0000000..286b841 --- /dev/null +++ b/backend/libs/Solicitors.HtmlParsing/DIExtensions.cs @@ -0,0 +1,11 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace Solicitors.HtmlParsing; + +public static class DIExtensions +{ + public static IServiceCollection AddHtmlParsing(this IServiceCollection services) + { + return services.AddSingleton(); + } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.HtmlParsing/HtmlParser.cs b/backend/libs/Solicitors.HtmlParsing/HtmlParser.cs new file mode 100644 index 0000000..2cbd4cf --- /dev/null +++ b/backend/libs/Solicitors.HtmlParsing/HtmlParser.cs @@ -0,0 +1,130 @@ +namespace Solicitors.HtmlParsing; + +using Models; + +internal class HtmlParser : IHtmlParser +{ + private readonly string[] _voidElements = + [ + "area", + "base", + "br", + "col", + "embed", + "hr", + "img", + "input", + "link", + "meta", + "source", + "track", + "wbr" + ]; + + public IEnumerable ParseHtml(string html) + { + // wanted to do this in one pass but was quite time-consuming + // so taking a little lesson from compiler development + // and lex the text into tokens before parsing :) + // deferred execution might help it still be "one pass"? + var stringEnumerator = html.GetEnumerator(); + var tokens = LexHtml(stringEnumerator); + var tokenEnumerator = tokens.GetEnumerator(); + return ParseHtml(tokenEnumerator); + } + + private IEnumerable LexHtml(IEnumerator content) + { + var work = ""; + while (content.MoveNext()) + { + if (content.Current == '<' && !string.IsNullOrWhiteSpace(work)) + { + yield return work.Trim(); + work = ""; + } + + work += content.Current; + + if (content.Current == '>' && !string.IsNullOrWhiteSpace(work)) + { + yield return work.Trim(); + work = ""; + } + } + } + + private IEnumerable ParseHtml(IEnumerator tokens) + { + while (tokens.MoveNext()) + { + var token = tokens.Current; + if (!token.StartsWith('<')) + { + yield return new StringNode(token); + continue; + } + + var noBraces = token.Substring(1, token.Length - 2); + var split = noBraces.Split(' '); + IHtmlAttribute[] attributes = []; + if (split.Length > 1) + { + attributes = ParseAttributes(noBraces).ToArray(); + } + + if (IsVoidOrSelfClosingElement(token)) + yield return new HtmlNode(split.First(), attributes); + else if (token.StartsWith("")) + return true; + + var tagName = token.Split(' ').First().Substring(1); + if (tagName.EndsWith('>')) + tagName = tagName.Substring(0, tagName.Length - 1); + return _voidElements.Contains(tagName); + } + + private IEnumerable ParseAttributes(string tokenNoBraces) + { + var attributesString = string.Join(' ', tokenNoBraces.Split(' ').Skip(1)); + var attString = ""; + bool inQuote = false; + foreach (char c in attributesString) + { + if (!inQuote && c == ' ') + { + yield return ParseAttribute(attString); + attString = ""; + } + else + { + attString += c; + if (c == '\"') + inQuote = !inQuote; + } + } + + yield return ParseAttribute(attString); + } + + private IHtmlAttribute ParseAttribute(string attString) + { + var split = attString.Split('='); + if (split.Length > 1) + return new HtmlValueAttribute(split[0], string.Join('=', split.Skip(1))); + else + return new HtmlAttribute(attString); + } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.HtmlParsing/IHtmlParser.cs b/backend/libs/Solicitors.HtmlParsing/IHtmlParser.cs new file mode 100644 index 0000000..199a93c --- /dev/null +++ b/backend/libs/Solicitors.HtmlParsing/IHtmlParser.cs @@ -0,0 +1,8 @@ +namespace Solicitors.HtmlParsing; + +using Models; + +public interface IHtmlParser +{ + IEnumerable ParseHtml(string html); +} \ No newline at end of file diff --git a/backend/libs/Solicitors.HtmlParsing/Models/HtmlAttribute.cs b/backend/libs/Solicitors.HtmlParsing/Models/HtmlAttribute.cs new file mode 100644 index 0000000..70a8fea --- /dev/null +++ b/backend/libs/Solicitors.HtmlParsing/Models/HtmlAttribute.cs @@ -0,0 +1,6 @@ +namespace Solicitors.HtmlParsing.Models; + +internal class HtmlAttribute(string name) : IHtmlAttribute +{ + public string Name { get; } = name; +} \ No newline at end of file diff --git a/backend/libs/Solicitors.HtmlParsing/Models/HtmlNode.cs b/backend/libs/Solicitors.HtmlParsing/Models/HtmlNode.cs new file mode 100644 index 0000000..050e011 --- /dev/null +++ b/backend/libs/Solicitors.HtmlParsing/Models/HtmlNode.cs @@ -0,0 +1,95 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Solicitors.HtmlParsing.Models; + +internal class HtmlNode(string tagName, IHtmlAttribute[] attributes) + : IHtmlNode +{ + private readonly IHtmlAttribute[] _attributes = attributes; + private readonly string _tagName = tagName; + + public virtual bool TryGetByTagName( + string tagName, + [NotNullWhen(true)] out IHtmlNode? node, + bool noChildren = false) + { + node = null; + if (tagName == _tagName) + node = this; + + return node is not null; + } + + private string[] Classes + { + get + { + var classAttribute = _attributes + .Where(a => a is HtmlValueAttribute) + .Select(a => (a as HtmlValueAttribute)!) + .FirstOrDefault(a => a.Name.Equals("class", StringComparison.CurrentCultureIgnoreCase)); + + return classAttribute is not null + ? classAttribute.Value.Substring(1, classAttribute.Value.Length - 2).Split(' ') + : []; + } + } + + public virtual bool TryGetByClass( + string className, + [NotNullWhen(true)] out IHtmlNode? node, + bool noChildren = false) + { + node = null; + + if (Classes.Contains(className, StringComparer.InvariantCultureIgnoreCase)) + node = this; + + return node is not null; + } + + public virtual bool TryGetByTagNameAndClass( + string tagName, + string className, + [NotNullWhen(true)] out IHtmlNode? node, + bool noChildren = false) + { + node = null; + if (tagName == _tagName && Classes.Contains(className, StringComparer.InvariantCultureIgnoreCase)) + node = this; + + return node is not null; + } + + public virtual bool TryGetText([NotNullWhen(true)] out string? text) + { + text = null; + return false; + } + + public virtual bool TryGetChildren([NotNullWhen(true)] out IEnumerable? children) + { + children = null; + return false; + } + + public bool HasAttribute(string attributeName) + { + return _attributes + .Any(a => a.Name.Equals(attributeName, StringComparison.InvariantCultureIgnoreCase)); + } + + public bool TryGetAttributeValue(string attributeName, [NotNullWhen(true)] out string? attributeValue) + { + attributeValue = null; + + var matchingAttribute = _attributes.FirstOrDefault( + a => a.Name.Equals(attributeName, StringComparison.InvariantCultureIgnoreCase) + ); + + if (matchingAttribute is HtmlValueAttribute valueAttribute) + attributeValue = valueAttribute.Value; + + return attributeValue is not null; + } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.HtmlParsing/Models/HtmlValueAttribute.cs b/backend/libs/Solicitors.HtmlParsing/Models/HtmlValueAttribute.cs new file mode 100644 index 0000000..c8ea5e4 --- /dev/null +++ b/backend/libs/Solicitors.HtmlParsing/Models/HtmlValueAttribute.cs @@ -0,0 +1,6 @@ +namespace Solicitors.HtmlParsing.Models; + +internal class HtmlValueAttribute(string name, string value) : HtmlAttribute(name) +{ + public string Value { get; } = value; +} \ No newline at end of file diff --git a/backend/libs/Solicitors.HtmlParsing/Models/IHtmlAttribute.cs b/backend/libs/Solicitors.HtmlParsing/Models/IHtmlAttribute.cs new file mode 100644 index 0000000..4240a2e --- /dev/null +++ b/backend/libs/Solicitors.HtmlParsing/Models/IHtmlAttribute.cs @@ -0,0 +1,6 @@ +namespace Solicitors.HtmlParsing.Models; + +internal interface IHtmlAttribute +{ + string Name { get; } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.HtmlParsing/Models/IHtmlNode.cs b/backend/libs/Solicitors.HtmlParsing/Models/IHtmlNode.cs new file mode 100644 index 0000000..e473d8f --- /dev/null +++ b/backend/libs/Solicitors.HtmlParsing/Models/IHtmlNode.cs @@ -0,0 +1,64 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Solicitors.HtmlParsing.Models; + +public interface IHtmlNode +{ + /// + /// Searches this node and its direct children for a matching tag name. + /// + /// The tag name to match. + /// If found, the node that matches the tag name. + /// If true, only check this node, not its children. + /// True if this node, or any of its direct children, have a matching tag name; false otherwise. + bool TryGetByTagName( + string tagName, + [NotNullWhen(true)] out IHtmlNode? node, + bool noChildren = false); + + /// + /// Searches this node and its direct children for a matching class. + /// + /// The class name to match. + /// If found, the node that matches the class name. + /// If true, only check this node, not its children. + /// True if this node, or any of its direct children, have a matching class name; false otherwise. + bool TryGetByClass( + string className, + [NotNullWhen(true)] out IHtmlNode? node, + bool noChildren = false); + + /// + /// Searches this node and its direct children for a matching tag name and matching class on the same node. + /// + /// The tag name to match. + /// The class name to match. + /// If found, the node that matches the tag name and class name. + /// If true, only check this node, not its children. + /// True if this node, or any of its direct children, have a matching tag name and class name; false otherwise. + bool TryGetByTagNameAndClass( + string tagName, + string className, + [NotNullWhen(true)] out IHtmlNode? node, + bool noChildren = false); + + /// + /// Checks this node (and *not* its children) to see if it is text content. + /// + /// If found, the text content. + /// True if the node is a text node, false otherwise. + bool TryGetText([NotNullWhen(true)] out string? text); + + /// + /// Checks this node to see if it has child elements. + /// + /// If found, the child elements. + /// True if the node has child elements, false otherwise. + bool TryGetChildren([NotNullWhen(true)] out IEnumerable? children); + + bool HasAttribute(string attributeName); + + bool TryGetAttributeValue( + string attributeName, + [NotNullWhen(true)] out string? attributeValue); +} \ No newline at end of file diff --git a/backend/libs/Solicitors.HtmlParsing/Models/ParentHtmlNode.cs b/backend/libs/Solicitors.HtmlParsing/Models/ParentHtmlNode.cs new file mode 100644 index 0000000..61a0eb7 --- /dev/null +++ b/backend/libs/Solicitors.HtmlParsing/Models/ParentHtmlNode.cs @@ -0,0 +1,94 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Solicitors.HtmlParsing.Models; + +internal class ParentHtmlNode(string tagName, IHtmlAttribute[] attributes, IHtmlNode[] children) + : HtmlNode(tagName, attributes) +{ + private readonly IHtmlNode[] _children = children; + + public override bool TryGetByTagName( + string tagName, + [NotNullWhen(true)] out IHtmlNode? node, + bool noChildren = false) + { + node = null; + if (!base.TryGetByTagName(tagName, out node, noChildren) && !noChildren) + { + var nodesToCheck = new Queue(_children); + while (nodesToCheck.TryDequeue(out var child)) + { + if (child.TryGetByTagName(tagName, out var childNode, true)) + { + node = childNode; + break; + } + + if (child.TryGetChildren(out var grandChildren)) + foreach (var grandChild in grandChildren) + nodesToCheck.Enqueue(grandChild); + } + } + + return node is not null; + } + + public override bool TryGetByClass( + string className, + [NotNullWhen(true)] out IHtmlNode? node, + bool noChildren = false) + { + node = null; + if (!base.TryGetByClass(className, out node, noChildren) && !noChildren) + { + var nodesToCheck = new Queue(_children); + while (nodesToCheck.TryDequeue(out var child)) + { + if (child.TryGetByClass(className, out var childNode, true)) + { + node = childNode; + break; + } + + if (child.TryGetChildren(out var grandChildren)) + foreach (var grandChild in grandChildren) + nodesToCheck.Enqueue(grandChild); + } + } + + return node is not null; + } + + public override bool TryGetByTagNameAndClass( + string tagName, + string className, + [NotNullWhen(true)] out IHtmlNode? node, + bool noChildren = false) + { + node = null; + if (!base.TryGetByTagNameAndClass(tagName, className, out node, noChildren) && !noChildren) + { + var nodesToCheck = new Queue(_children); + while (nodesToCheck.TryDequeue(out var child)) + { + if (child.TryGetByTagNameAndClass(tagName, className, out var childNode, true)) + { + node = childNode; + break; + } + + if (child.TryGetChildren(out var grandChildren)) + foreach (var grandChild in grandChildren) + nodesToCheck.Enqueue(grandChild); + } + } + + return node is not null; + } + + public override bool TryGetChildren([NotNullWhen(true)] out IEnumerable? children) + { + children = _children; + return _children.Length != 0; + } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.HtmlParsing/Models/StringNode.cs b/backend/libs/Solicitors.HtmlParsing/Models/StringNode.cs new file mode 100644 index 0000000..4669fb7 --- /dev/null +++ b/backend/libs/Solicitors.HtmlParsing/Models/StringNode.cs @@ -0,0 +1,59 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Solicitors.HtmlParsing.Models; + +internal class StringNode(string content) + : IHtmlNode +{ + private readonly string _content = content; + + public bool TryGetByTagName( + string tagName, + [NotNullWhen(true)] out IHtmlNode? node, + bool noChildren = false) + { + node = null; + return false; + } + + public bool TryGetByClass( + string className, + [NotNullWhen(true)] out IHtmlNode? node, + bool noChildren = false) + { + node = null; + return false; + } + + public bool TryGetByTagNameAndClass( + string tagName, + string className, + [NotNullWhen(true)] out IHtmlNode? node, + bool noChildren = false) + { + node = null; + return false; + } + + public bool TryGetText([NotNullWhen(true)] out string? text) + { + text = _content; + return !string.IsNullOrEmpty(text); + } + + public bool TryGetChildren([NotNullWhen(true)] out IEnumerable? children) + { + children = null; + return false; + } + + public bool HasAttribute(string attributeName) => false; + + public bool TryGetAttributeValue( + string attributeName, + [NotNullWhen(true)] out string? attributeValue) + { + attributeValue = null; + return false; + } +} \ No newline at end of file diff --git a/backend/libs/Solicitors.HtmlParsing/Solicitors.HtmlParsing.csproj b/backend/libs/Solicitors.HtmlParsing/Solicitors.HtmlParsing.csproj new file mode 100644 index 0000000..90bc4ed --- /dev/null +++ b/backend/libs/Solicitors.HtmlParsing/Solicitors.HtmlParsing.csproj @@ -0,0 +1,13 @@ + + + + net10.0 + enable + enable + + + + + + + diff --git a/backend/tests/Solicitors.HtmlParsing.Tests/Solicitors.HtmlParsing.Tests.csproj b/backend/tests/Solicitors.HtmlParsing.Tests/Solicitors.HtmlParsing.Tests.csproj new file mode 100644 index 0000000..df7c6e2 --- /dev/null +++ b/backend/tests/Solicitors.HtmlParsing.Tests/Solicitors.HtmlParsing.Tests.csproj @@ -0,0 +1,25 @@ + + + + net10.0 + enable + enable + false + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/frontend/.yarn/install-state.gz b/frontend/.yarn/install-state.gz new file mode 100644 index 0000000..1a7cf7b Binary files /dev/null and b/frontend/.yarn/install-state.gz differ diff --git a/frontend/.yarnrc.yml b/frontend/.yarnrc.yml new file mode 100644 index 0000000..063ed60 --- /dev/null +++ b/frontend/.yarnrc.yml @@ -0,0 +1,8 @@ +approvedGitRepositories: + - "**" + +enableScripts: true + +nodeLinker: node-modules + +npmMinimalAgeGate: 0 diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..5f3ba6a --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,15 @@ +FROM node:26.3.1-alpine3.24 as build + +ARG VITE_API_URL +ENV VITE_API_URL=$VITE_API_URL + +RUN mkdir -p /code +WORKDIR /code +ADD . /code +RUN npm install -g -s --no-progress corepack +RUN COREPACK_ENABLE_DOWNLOAD_PROMPT=0 /bin/sh -c "yarn -v" +RUN yarn install +RUN yarn run build + +FROM httpd:2.4.68-alpine3.24 +COPY --from=build /code/dist /usr/local/apache2/htdocs/ \ No newline at end of file diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..51bbeef --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,15 @@ +# `create-preact` + +

+ +

+ +

Get started using Preact and Vite!

+ +## Getting Started + +- `yarn dev` - Starts a dev server at http://localhost:5173/ + +- `yarn build` - Builds for production, emitting to `dist/` + +- `yarn preview` - Starts a server at http://localhost:4173/ to test production build locally diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..170c101 --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,17 @@ + + + + + + + + + + Vite + Preact + + + +
+ + + diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..75419b2 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,31 @@ +{ + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "@babel/core": "^8.0.1", + "@base-ui/react": "^1.6.0", + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@fontsource/roboto": "^5.2.10", + "@mui/icons-material": "^9.1.1", + "@mui/material": "^9.1.2", + "axios": "^1.18.1", + "preact": "^10.26.9" + }, + "devDependencies": { + "@preact/preset-vite": "^2.10.2", + "eslint": "^10.5.0", + "eslint-config-preact": "^2.0.0", + "typescript": "^6.0.3", + "vite": "^7.0.4" + }, + "eslintConfig": { + "extends": "preact" + }, + "packageManager": "yarn@4.17.0" +} diff --git a/frontend/public/vite.svg b/frontend/public/vite.svg new file mode 100644 index 0000000..ffcb6bc --- /dev/null +++ b/frontend/public/vite.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/preact.svg b/frontend/src/assets/preact.svg new file mode 100644 index 0000000..f34e939 --- /dev/null +++ b/frontend/src/assets/preact.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/components/detail.tsx b/frontend/src/components/detail.tsx new file mode 100644 index 0000000..4cdcbbf --- /dev/null +++ b/frontend/src/components/detail.tsx @@ -0,0 +1,137 @@ +import Box from "@mui/material/Box"; +import Modal from "@mui/material/Modal"; +import { forwardRef, useEffect, useState } from "react"; +import { SolicitorInfo } from "../models/solicitorSummary"; +import getSolicitor from "../functions/getSolicitor"; +import Card from "@mui/material/Card"; +import { Grid, Rating, Typography } from "@mui/material"; + +interface ClosedProps { + open : false; +} + +interface OpenProps { + open : true; + id : string; +} + +export type DetailInfo = OpenProps | ClosedProps; +type DetailProps = DetailInfo & { onClose : (error? : string) => void }; + + +export default function Detail(props : DetailProps) { + const [data, setData] = useState('loading'); + + const handleResult = (result : SolicitorInfo | undefined) => { + console.log(data, props, result); + if (data == 'loading' && props.open && props.id == result?.id) { + setData(result); + } else if (!result) { + handleClose('An error occurred loading the solicitor'); + } + } + + const handleClose = (error? : string) => { + props.onClose(error); + setData('loading'); + } + + useEffect(() => { + if (props.open && data == 'loading') { + getSolicitor(props.id) + .then(result => { console.log(result); handleResult(result); }); + } + }, [props.open]); + + useEffect(() => {}, [data]) + + return ( + handleClose()} + > + + + + ); +} + +const style = { + position: 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + width: 800, + maxWidth: '60%', + maxHeight: '80%', + bgcolor: 'background.default', + overflow: 'scroll', + p: 4, +}; + +const DetailDisplay = forwardRef((props : {data : SolicitorInfo | 'loading'}) => { + console.log(props.data); + useEffect(() => {console.log(props.data);}, [props.data]); + + if (props.data === 'loading') { + return Nope; + } else { + return ( + + {props.data.name} + {props.data.shortDescription} + {props.data.ratings && + (<> +
+ Ratings + + {props.data.ratings.map(rating => ( + + + {rating.provider} + + + + ))} + + ) + } + {props.data.locations && + (<> +
+ Offices + + {props.data.locations.map(office => ( + + + {office.address.split('\n').map(line => ({line}))} + {office.phone && <>
tel: {office.phone}} + {office.ratings && office.ratings.map(rating => + (<> + {rating.provider} + + ) + )} +
+
+ ))} +
+ ) + } + +
+ ); + } +}); \ No newline at end of file diff --git a/frontend/src/components/header.tsx b/frontend/src/components/header.tsx new file mode 100644 index 0000000..41cd118 --- /dev/null +++ b/frontend/src/components/header.tsx @@ -0,0 +1,42 @@ +import DarkMode from "@mui/icons-material/DarkMode"; +import LightMode from "@mui/icons-material/LightMode"; +import { AppBar, IconButton, Toolbar, Tooltip, Typography } from "@mui/material"; +import { Theme } from "@mui/material/styles"; + +export interface ThemeWrapper { + theme : Theme, + value : 'dark' | 'light'; +} + +interface HeaderProps { + theme : ThemeWrapper; + toggleTheme : () => void; +} + +export default function Header(props : HeaderProps) { + return ( + + + + Conveyancing Search + + + + { + props.theme.value === 'dark' + ? + : + } + + + + + ); +} \ No newline at end of file diff --git a/frontend/src/components/numberField.tsx b/frontend/src/components/numberField.tsx new file mode 100644 index 0000000..75794f9 --- /dev/null +++ b/frontend/src/components/numberField.tsx @@ -0,0 +1,114 @@ +import * as React from 'react'; +import { NumberField as BaseNumberField } from '@base-ui/react/number-field'; +import IconButton from '@mui/material/IconButton'; +import FormControl from '@mui/material/FormControl'; +import FormHelperText from '@mui/material/FormHelperText'; +import OutlinedInput from '@mui/material/OutlinedInput'; +import InputAdornment from '@mui/material/InputAdornment'; +import InputLabel from '@mui/material/InputLabel'; +import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'; +import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; + +/** + * This component is a placeholder for FormControl to correctly set the shrink label state on SSR. + */ +function SSRInitialFilled(_: BaseNumberField.Root.Props) { + return null; +} +SSRInitialFilled.muiName = 'Input'; + +export default function NumberField({ + id: idProp, + label, + error, + size = 'medium', + ...other +}: BaseNumberField.Root.Props & { + label?: React.ReactNode; + size?: 'small' | 'medium'; + error?: boolean; +}) { + let id = React.useId(); + if (idProp) { + id = idProp; + } + return ( + ( + + {props.children} + + )} + > + + {label} + ( + + } + > + + + + } + > + + + + } + sx={{ pr: 0 }} + /> + )} + /> + + Enter value between 10 and 40 + + + ); +} \ No newline at end of file diff --git a/frontend/src/components/result.tsx b/frontend/src/components/result.tsx new file mode 100644 index 0000000..3d1adf3 --- /dev/null +++ b/frontend/src/components/result.tsx @@ -0,0 +1,42 @@ +import ListItemText from "@mui/material/ListItemText"; +import SolicitorSummary from "../models/solicitorSummary"; +import ListItemButton from "@mui/material/ListItemButton"; +import Typography from "@mui/material/Typography"; +import Rating from "@mui/material/Rating"; +import Divider from "@mui/material/Divider"; + +type ResultProps = SolicitorSummary & { last : boolean, onClick: () => void }; + +export default function Result(props : ResultProps) { + return ( + <> + + + + {props.name} + + + + } + secondary={props.shortDescription} + /> + + {props.last || } + + ); +} \ No newline at end of file diff --git a/frontend/src/components/results.tsx b/frontend/src/components/results.tsx new file mode 100644 index 0000000..364e101 --- /dev/null +++ b/frontend/src/components/results.tsx @@ -0,0 +1,38 @@ +import { useEffect, useState } from "preact/hooks"; +import GetSolicitors from "../functions/getSolicitors"; +import Grid from "@mui/material/Grid"; +import Sidebar from "./sidebar"; +import FilterState from "../models/filterState"; +import { default as ResultsType, waitingResults } from "../models/results"; +import ResultsList from "./resultsList"; + +export default function Results() { + const [results, setResults] = useState(waitingResults); + const [filters, setFilters] = useState({cities: [], minRating: 3, resultsPerPage: 20, currentPage: 1, ratingsProvider: 'Solicitors.com', sortBy: 'rating-desc'}); + + useEffect(() => { + if (results.type == 'Waiting') { + GetSolicitors(filters) + .then(result => setResults({type: 'Success', data: result})); + } + }, [results]); + + useEffect(() => { + setResults({type: 'Waiting'}); + }, [filters]); + + return ( + + + + + + + + + ); +} + diff --git a/frontend/src/components/resultsList.tsx b/frontend/src/components/resultsList.tsx new file mode 100644 index 0000000..7b911bb --- /dev/null +++ b/frontend/src/components/resultsList.tsx @@ -0,0 +1,42 @@ +import List from "@mui/material/List"; +import Pagination from "@mui/material/Pagination"; +import FilterState from "../models/filterState"; +import Results from "../models/results"; +import Result from "./result"; +import Detail, { DetailInfo } from "./detail"; +import { useState } from "react"; + +interface ResultsListProps { + results : Results; + filters : FilterState; + setFilters : (state : FilterState) => void; +} + +export default function ResultsList(props : ResultsListProps) { + const [detail, setDetail] = useState({open: false}); + + switch (props.results.type) { + case 'Success': + let data = props.results.data.data; + return ( + <> + + {data.map((r, i) => ( setDetail({open : true, id : r.id})} last={i == data.length - 1} />))} + + setDetail({open: false})} /> + props.setFilters(Object.assign({}, {...props.filters}, {currentPage: page}))} + /> + + ); + case 'Waiting': + return
Waiting...
; + case 'Error': + return
Error...
; + case 'Warning': + return
Warning...
; + } +} \ No newline at end of file diff --git a/frontend/src/components/sidebar.tsx b/frontend/src/components/sidebar.tsx new file mode 100644 index 0000000..5d1264a --- /dev/null +++ b/frontend/src/components/sidebar.tsx @@ -0,0 +1,140 @@ +import { Autocomplete, Box, Divider, Grid, InputLabel, MenuItem, Paper, Rating, Select, SelectChangeEvent, TextField, Typography } from "@mui/material"; +import getCities from "../functions/getCities"; +import FilterState from "../models/filterState"; +import { useEffect, useState } from "react"; +import NumberField from "./numberField"; +import getRatingsProviders from "../functions/getRatingsProviders"; + +interface SidebarProps { + filters : FilterState; + onChange : (filters : FilterState) => void; +} + +function capitalizeFirstLetter(val : string) { + return String(val).charAt(0).toUpperCase() + String(val).slice(1); +} + +export default function Sidebar(props : SidebarProps) { + const [cities, setCities] = useState([]); + const [ratingsProviders, setRatingsProviders] = useState(['Solicitors.com']); + + useEffect(() => { + if (cities.length === 0) { + getCities().then((results) => setCities(results)); + } + }, [cities.length]); + + useEffect(() => { + if (cities.length === 0) { + getRatingsProviders().then((results) => setRatingsProviders(results)); + } + }, [cities.length]); + + return ( + + + Filter Conveyancers + + + Cities + props.onChange(Object.assign({}, {...props.filters}, {cities: value}))} + renderInput={(params) => ( + + )} + /> + + + + + + Min. Rating + props.onChange(Object.assign({}, {...props.filters}, {minRating: value}))} + /> + + + Rating Provider + + + + + + + Results per Page + props.onChange(Object.assign({}, {...props.filters}, {resultsPerPage: value, currentPage: 1}))} + min={10} + max={40} + /> + + + + Sort By + + + + ) +} + +const sortingOptions = [ + { + value: 'rating-desc', + name: 'Rating (descending)' + }, + { + value: 'rating-asc', + name: 'Rating (ascending)' + }, + { + value: 'alphabet-asc', + name: 'Alphabetical (ascending)' + }, + { + value: 'alphabet-desc', + name: 'Alphabetical (descending)' + } +] \ No newline at end of file diff --git a/frontend/src/functions/axios.ts b/frontend/src/functions/axios.ts new file mode 100644 index 0000000..a801971 --- /dev/null +++ b/frontend/src/functions/axios.ts @@ -0,0 +1,7 @@ +import axios from 'axios'; + +const api = axios.create({ + baseURL: import.meta.env.VITE_API_URL +}); + +export default api; \ No newline at end of file diff --git a/frontend/src/functions/getCities.ts b/frontend/src/functions/getCities.ts new file mode 100644 index 0000000..0d1a36e --- /dev/null +++ b/frontend/src/functions/getCities.ts @@ -0,0 +1,6 @@ +import api from "./axios"; + +export default async function GetCiries() { + const response = await api.get('/cities'); + return response.data as string[]; +} \ No newline at end of file diff --git a/frontend/src/functions/getRatingsProviders.ts b/frontend/src/functions/getRatingsProviders.ts new file mode 100644 index 0000000..9efc592 --- /dev/null +++ b/frontend/src/functions/getRatingsProviders.ts @@ -0,0 +1,6 @@ +import api from "./axios"; + +export default async function GetCiries() { + const response = await api.get('/ratingsProviders'); + return response.data as string[]; +} \ No newline at end of file diff --git a/frontend/src/functions/getSolicitor.ts b/frontend/src/functions/getSolicitor.ts new file mode 100644 index 0000000..382843a --- /dev/null +++ b/frontend/src/functions/getSolicitor.ts @@ -0,0 +1,7 @@ +import { SolicitorInfo } from "../models/solicitorSummary"; +import api from "./axios"; + +export default async function GetSolicitor(id : string) : Promise { + const response = await api.get(`/conveyancors/${id}`); + return response.data as SolicitorInfo; +} \ No newline at end of file diff --git a/frontend/src/functions/getSolicitors.ts b/frontend/src/functions/getSolicitors.ts new file mode 100644 index 0000000..c69a5a4 --- /dev/null +++ b/frontend/src/functions/getSolicitors.ts @@ -0,0 +1,22 @@ +import SolicitorSummary from "../models/solicitorSummary"; +import PaginationResponse from "../models/paginationResponse"; +import FilterState from "../models/filterState"; +import api from "./axios"; + +export default async function GetSolicitors(filters : FilterState) { + console.log(api.defaults.baseURL); + var minRating = filters.minRating; + if (minRating == null) { + minRating = 0; + } + + let queryString = `pageSize=${filters.resultsPerPage}&pageNumber=${filters.currentPage}&ratingsProvider=${filters.ratingsProvider}&minRating=${minRating}`; + if (filters.cities.length > 0) { + queryString += '&cities=' + filters.cities.join('&cities='); + } + if (filters.sortBy != null) { + queryString += `&orderingType=${filters.sortBy}`; + } + const response = await api.get(`/conveyancors?${queryString}`); + return response.data as PaginationResponse; +} \ No newline at end of file diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx new file mode 100644 index 0000000..89568a2 --- /dev/null +++ b/frontend/src/index.tsx @@ -0,0 +1,129 @@ +import { render } from 'preact'; +import Button from '@mui/material/Button'; +import AppBar from '@mui/material/AppBar'; +import Toolbar from '@mui/material/Toolbar'; +import IconButton from '@mui/material/IconButton'; +import Typography from '@mui/material/Typography'; +import Container from '@mui/material/Container'; +import { useState } from 'preact/compat'; +import { createTheme, Theme, ThemeProvider } from '@mui/material/styles'; +import DarkMode from '@mui/icons-material/DarkMode'; +import LightMode from '@mui/icons-material/LightMode'; +import { CssBaseline, Tooltip } from '@mui/material'; +import Header, { ThemeWrapper } from './components/header'; +import Results from './components/results'; + +function prefersDarkMode() { + const darkModeMql = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)'); + return darkModeMql && darkModeMql.matches; +} + +const darkTheme = createTheme({ + palette: { + mode: 'dark', + primary: { + light: '#B79AD5', + main: '#A27EC9', + dark: '#8D61BD' + }, + secondary: { + light: '#70DBFF', + main: '#47D1FF', + dark: '#1FC7FF' + }, + error: { + light: '#E73936', + main: '#DD1C1A', + dark: '#B71815' + }, + warning: { + light: '#FA804C', + main: '#F9611F', + dark: '#EF4C06' + }, + info : { + light: '#FFEB99', + main: '#FFE066', + dark: '#FFDA47' + }, + success: { + light: '#6ADC98', + main: '#48D480', + dark: '#2FC66B' + }, + background: { + default: '#1D2535', + paper: '#242E42' + } + } +}); + +const lightTheme = createTheme({ + palette: { + mode: 'light', + primary: { + light: '#B79AD5', + main: '#A27EC9', + dark: '#8D61BD' + }, + secondary: { + light: '#70DBFF', + main: '#47D1FF', + dark: '#1FC7FF' + }, + error: { + light: '#E73936', + main: '#DD1C1A', + dark: '#B71815' + }, + warning: { + light: '#FA804C', + main: '#F9611F', + dark: '#EF4C06' + }, + info : { + light: '#FFEB99', + main: '#FFE066', + dark: '#FFDA47' + }, + success: { + light: '#6ADC98', + main: '#48D480', + dark: '#2FC66B' + }, + background: { + default: '#EFFFFF', + paper: '#e8f1f1' + } + } +}); + +export function App() { + const [value, setValue] = useState(0); + const [theme, setTheme] = useState({ + theme : prefersDarkMode() ? darkTheme : lightTheme, + value : prefersDarkMode() ? 'dark' : 'light' + }); + + const handleChange = (event: any, newValue: number) => { + setValue(newValue); + }; + + const toggleTheme = () => { + setTheme(theme.value == 'dark' + ? { theme : lightTheme, value : 'light' } + : { theme : darkTheme, value : 'dark' }); + } + + return ( + + +
+ + + + + ); +} + +render(, document.getElementById('app')); diff --git a/frontend/src/models/filterState.ts b/frontend/src/models/filterState.ts new file mode 100644 index 0000000..6d1bd34 --- /dev/null +++ b/frontend/src/models/filterState.ts @@ -0,0 +1,8 @@ +export default interface FilterState { + cities : string[]; + minRating : number; + resultsPerPage : number; + currentPage : number; + ratingsProvider : string; + sortBy : string; +}; \ No newline at end of file diff --git a/frontend/src/models/paginationResponse.ts b/frontend/src/models/paginationResponse.ts new file mode 100644 index 0000000..c7dc57e --- /dev/null +++ b/frontend/src/models/paginationResponse.ts @@ -0,0 +1,4 @@ +export default interface PaginationResponse { + data : T[]; + total : number; +} \ No newline at end of file diff --git a/frontend/src/models/results.ts b/frontend/src/models/results.ts new file mode 100644 index 0000000..20381b7 --- /dev/null +++ b/frontend/src/models/results.ts @@ -0,0 +1,25 @@ +import PaginationResponse from "./paginationResponse"; +import SolicitorSummary from "./solicitorSummary"; + +type Results = SuccessResults | ErrorResults | WaitingResults; + +interface SuccessResults { + type : 'Success', + data : PaginationResponse +}; + +interface ErrorResults { + type : 'Error' | 'Warning', + message : string +}; + +interface WaitingResults { + type : 'Waiting' +}; + +const waitingResults : WaitingResults = { + type : 'Waiting' +}; + +export default Results; +export {waitingResults}; \ No newline at end of file diff --git a/frontend/src/models/solicitorSummary.ts b/frontend/src/models/solicitorSummary.ts new file mode 100644 index 0000000..7dc69b7 --- /dev/null +++ b/frontend/src/models/solicitorSummary.ts @@ -0,0 +1,30 @@ +export default interface SolicitorSummary { + name : string, + shortDescription : string | null, + id : string, + rating : Rating +}; + +export interface Rating { + value : number, + maximum : number, + provider : string +} + +export interface Location { + address : string, + phone : string, + ratings : Rating[] +} + +export interface SolicitorInfo { + name : string, + shortDescription : string | null, + id : string, + phone? : string, + email? : string, + website? : string, + + ratings : Rating[], + locations : Location[] +} \ No newline at end of file diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 0000000..12bb30b --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "allowJs": true, + "checkJs": true, + + /* Preact Config */ + "jsx": "react-jsx", + "jsxImportSource": "preact", + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + } + }, + "include": ["node_modules/vite/client.d.ts", "**/*"] +} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts new file mode 100644 index 0000000..0e309b2 --- /dev/null +++ b/frontend/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite'; +import preact from '@preact/preset-vite'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact()], +}); diff --git a/frontend/yarn.lock b/frontend/yarn.lock new file mode 100644 index 0000000..160358a --- /dev/null +++ b/frontend/yarn.lock @@ -0,0 +1,4693 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 10 + cacheKey: 10c0 + +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/code-frame@npm:7.29.7" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.29.7" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.1.1" + checksum: 10c0/169fc2080169a40c1760155eaaaf739bcb882df0bec76a83adbda5493645bc17270a3434b8848c494b1933e96fe1d147370001e3cda09a39f43ae30f08ef2069 + languageName: node + linkType: hard + +"@babel/code-frame@npm:^8.0.0": + version: 8.0.0 + resolution: "@babel/code-frame@npm:8.0.0" + dependencies: + "@babel/helper-validator-identifier": "npm:^8.0.0" + js-tokens: "npm:^10.0.0" + checksum: 10c0/2ea8614018bcd8c86358ab6aa930508115d2205e5e111f736d355b150453818bdf487850f6dec5ec92a10bf27ba4536f4b3b8ad9204514e43d8d68ff2e542443 + languageName: node + linkType: hard + +"@babel/compat-data@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/compat-data@npm:7.29.7" + checksum: 10c0/47913f05e08a45a1c9df38c02b4b49e391005085b489432647a1abe112e5d9c75e3be8ea5972b7f6da4ec5d1339922ceb9ea02b8a25d4ed1cb8636e5261f344e + languageName: node + linkType: hard + +"@babel/compat-data@npm:^8.0.0": + version: 8.0.0 + resolution: "@babel/compat-data@npm:8.0.0" + checksum: 10c0/8d934415a308cf6c893d815b1dbb79faf7678c1e489934e81025c61673bf98ef88770b42297492bbd4c014978688012aa635e855bf8553b96ec8287bddfbae89 + languageName: node + linkType: hard + +"@babel/core@npm:^7.13.16, @babel/core@npm:^7.22.1": + version: 7.29.7 + resolution: "@babel/core@npm:7.29.7" + dependencies: + "@babel/code-frame": "npm:^7.29.7" + "@babel/generator": "npm:^7.29.7" + "@babel/helper-compilation-targets": "npm:^7.29.7" + "@babel/helper-module-transforms": "npm:^7.29.7" + "@babel/helpers": "npm:^7.29.7" + "@babel/parser": "npm:^7.29.7" + "@babel/template": "npm:^7.29.7" + "@babel/traverse": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + "@jridgewell/remapping": "npm:^2.3.5" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10c0/112fb09c24de7a1de64d1de2c31fe65c4e6af4cb2fb6e6d99ea5373e6fc51e75b88581c0efae4c4c68f119a02a988c7106e95011a41530a2fb8ed793c7eaa07b + languageName: node + linkType: hard + +"@babel/core@npm:^8.0.1": + version: 8.0.1 + resolution: "@babel/core@npm:8.0.1" + dependencies: + "@babel/code-frame": "npm:^8.0.0" + "@babel/generator": "npm:^8.0.0" + "@babel/helper-compilation-targets": "npm:^8.0.0" + "@babel/helpers": "npm:^8.0.0" + "@babel/parser": "npm:^8.0.0" + "@babel/template": "npm:^8.0.0" + "@babel/traverse": "npm:^8.0.0" + "@babel/types": "npm:^8.0.0" + "@types/gensync": "npm:^1.0.5" + convert-source-map: "npm:^2.0.0" + empathic: "npm:^2.0.1" + gensync: "npm:^1.0.0-beta.2" + import-meta-resolve: "npm:^4.2.0" + json5: "npm:^2.2.3" + obug: "npm:^2.1.1" + semver: "npm:^7.7.3" + checksum: 10c0/e7fd9266d22906132fb052383a624358f54268dade31d50264416afeab6e5648cd23c7e845a89a501d270b80601d6e89abc67de0a9f1f55133f4abd8ac745be7 + languageName: node + linkType: hard + +"@babel/eslint-parser@npm:^7.27.5": + version: 7.29.7 + resolution: "@babel/eslint-parser@npm:7.29.7" + dependencies: + "@nicolo-ribaudo/eslint-scope-5-internals": "npm:5.1.1-v1" + eslint-visitor-keys: "npm:^2.1.0" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.11.0 + eslint: ^7.5.0 || ^8.0.0 || ^9.0.0 + checksum: 10c0/c24dcd941b0a149b197a9e9c3297a01d621775ac71cdf2e1134b1097c1691b46ce969355e1be3676d83b88f62c43ed33cf3a499da21ea11a5eb07339ce64ac20 + languageName: node + linkType: hard + +"@babel/generator@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/generator@npm:7.29.7" + dependencies: + "@babel/parser": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + "@jridgewell/gen-mapping": "npm:^0.3.12" + "@jridgewell/trace-mapping": "npm:^0.3.28" + jsesc: "npm:^3.0.2" + checksum: 10c0/9bf72b01b5bd0ea5b1288a0e37dbd360bff2f2b1ce73342c0d40fb3db2ec3dc004ada5ffa925c5e12939a416eed59e600d562b8ecd938ce0d27dfd0eb6c6c2b7 + languageName: node + linkType: hard + +"@babel/generator@npm:^8.0.0": + version: 8.0.0 + resolution: "@babel/generator@npm:8.0.0" + dependencies: + "@babel/parser": "npm:^8.0.0" + "@babel/types": "npm:^8.0.0" + "@jridgewell/gen-mapping": "npm:^0.3.12" + "@jridgewell/trace-mapping": "npm:^0.3.28" + "@types/jsesc": "npm:^2.5.0" + jsesc: "npm:^3.0.2" + checksum: 10c0/2b2d171beaedcacca62164f0f39bc8962df5f9700a54c5515174276ea20b3a53933e9804e0b35c2be1059108a764447d99d0c5beb63ecbbf8c66035ca6c003c4 + languageName: node + linkType: hard + +"@babel/helper-annotate-as-pure@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-annotate-as-pure@npm:7.29.7" + dependencies: + "@babel/types": "npm:^7.29.7" + checksum: 10c0/c56536b52d17632d89d49db2063ed6102f0e3bbadf6a0ccb74e6599d6a77173b644c7fe8c3ef17c7a162709d55b75ee5145ef6db917d16ba7f375fbffcf2e942 + languageName: node + linkType: hard + +"@babel/helper-compilation-targets@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-compilation-targets@npm:7.29.7" + dependencies: + "@babel/compat-data": "npm:^7.29.7" + "@babel/helper-validator-option": "npm:^7.29.7" + browserslist: "npm:^4.24.0" + lru-cache: "npm:^5.1.1" + semver: "npm:^6.3.1" + checksum: 10c0/4c15fd4c69a0a7047799a28a88460c19cede0a0ee8af994ea169114986f4af48b92c7393a4a3fee0456c11a656eece3448a6ed06354453d6c27cccf17195453b + languageName: node + linkType: hard + +"@babel/helper-compilation-targets@npm:^8.0.0": + version: 8.0.0 + resolution: "@babel/helper-compilation-targets@npm:8.0.0" + dependencies: + "@babel/compat-data": "npm:^8.0.0" + "@babel/helper-validator-option": "npm:^8.0.0" + browserslist: "npm:^4.24.0" + lru-cache: "npm:^11.0.0" + semver: "npm:^7.7.3" + checksum: 10c0/871876b4a9de1a2be68f2ec6c7576933dd9a8452bfb3c02ebcc16939791b8f2ab7467686e40060c6abfbb44bd76f898972e53034c3e7626a686a656f3a8d3bc9 + languageName: node + linkType: hard + +"@babel/helper-globals@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-globals@npm:7.29.7" + checksum: 10c0/f38417c40b1129a1b2b519ca961b9040c8827d1444fd74068702286b91b77089431dc76b6b9d5c1496e5da2a4f3ad329c6946e688ba3fa0d1d0b3d2b4f34f36a + languageName: node + linkType: hard + +"@babel/helper-globals@npm:^8.0.0": + version: 8.0.0 + resolution: "@babel/helper-globals@npm:8.0.0" + checksum: 10c0/c53a9fcf451df5c8d3aa72f282d1f058e2874e2ccbbdbb5572a805595d75a9355461822d01a6cac3128f5d9ab9a3a99538c6be4ebd728068afb20a65a4d1d986 + languageName: node + linkType: hard + +"@babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-module-imports@npm:7.29.7" + dependencies: + "@babel/traverse": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + checksum: 10c0/6adf60d97356027413342a092f818d9678c4f5caff716a33e3284b5ae14e47a9e88059d421dde4ee4894691260039a12602c0e7becadc175602194b40dfa345d + languageName: node + linkType: hard + +"@babel/helper-module-transforms@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-module-transforms@npm:7.29.7" + dependencies: + "@babel/helper-module-imports": "npm:^7.29.7" + "@babel/helper-validator-identifier": "npm:^7.29.7" + "@babel/traverse": "npm:^7.29.7" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/ee5a2172c24a42be696836f4b0d947489c9729d8adf5821885cf77d1ad5333e3c447368e9a71f67df1099570490553dccf9f888ef0a92a48aa63cb086bd8c7e1 + languageName: node + linkType: hard + +"@babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-plugin-utils@npm:7.29.7" + checksum: 10c0/380477a06133274a2759f9355929cb60a95e8b8fee624a1ae1fa349e1d1645b89daca456f72833f6d1062bffa12ee4271c5bf0cc5a61c0166cdc24c7591e2408 + languageName: node + linkType: hard + +"@babel/helper-string-parser@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-string-parser@npm:7.29.7" + checksum: 10c0/194bc0f1716e396d5ffde56ad6119745fb9557662c98611590e5e454906783a4ccb21ce93056b8eb69a4909044834e45d96e50ac695bbe9e3221648fe033c06c + languageName: node + linkType: hard + +"@babel/helper-string-parser@npm:^8.0.0": + version: 8.0.0 + resolution: "@babel/helper-string-parser@npm:8.0.0" + checksum: 10c0/b2272a9eaa63a1bc9ce2673d580e69620fd79786f3e3cf1891f406801f8211810f194f2739fef920f01a97ae06ae465b2dfd238ab8037a3182d0869939ca9a5d + languageName: node + linkType: hard + +"@babel/helper-validator-identifier@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-validator-identifier@npm:7.29.7" + checksum: 10c0/4795354e7ae0dcafa72de1cd04ec51252dc1498517170beaf019e03effc5b7bf13c6b21a3949a77e07b8125be7f106ed1131350d8ebd4566ae874094a726d62b + languageName: node + linkType: hard + +"@babel/helper-validator-identifier@npm:^8.0.0": + version: 8.0.2 + resolution: "@babel/helper-validator-identifier@npm:8.0.2" + checksum: 10c0/629eda2a0a99442a1628bbef5f9fd8e26c1aa21ddbf02760d1c482b737932b1bb21fb1f89aacf9c3cf0642b481b810e39f94b8ae9aa44fc4f5516ebec6798b7b + languageName: node + linkType: hard + +"@babel/helper-validator-option@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-validator-option@npm:7.29.7" + checksum: 10c0/d2a06c6d0ac40ba4a2f219fc2cab249c7a94bacdb2686273b7f9598571c908809b48468ff588915a346e6cc7296f60b581023d1d498b747fed06f779d335c2cc + languageName: node + linkType: hard + +"@babel/helper-validator-option@npm:^8.0.0": + version: 8.0.0 + resolution: "@babel/helper-validator-option@npm:8.0.0" + checksum: 10c0/eb466b464479f75c15ba06f6c53862f10d90740350c9203b3d81c6f33d4193bf0a7b7b89de901f256fb639a1346475b48616734af89906d6b4fcf9a856d9f1f1 + languageName: node + linkType: hard + +"@babel/helpers@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helpers@npm:7.29.7" + dependencies: + "@babel/template": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + checksum: 10c0/218e8d10953647c9f44775f5a022b227a182674853b5ea8631889deb7e1a3e4bc870388aaecf59bb8bd92a87f9a96220ed3f70a35bffec6bcf9169ecb67891ac + languageName: node + linkType: hard + +"@babel/helpers@npm:^8.0.0": + version: 8.0.0 + resolution: "@babel/helpers@npm:8.0.0" + dependencies: + "@babel/template": "npm:^8.0.0" + "@babel/types": "npm:^8.0.0" + checksum: 10c0/5d649bf2cfc37b76b8c9dd7d2992fa0503a6081c2439cd4de16b56abb778f3bb391441d687594f3e08af5ef3f59c8b93a77ae81f9e5f831989ebfd3443851189 + languageName: node + linkType: hard + +"@babel/parser@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/parser@npm:7.29.7" + dependencies: + "@babel/types": "npm:^7.29.7" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/65133038f80b54a714d6027cb77cee3f9a6b5c4c6842ce674301e13947cbcbfa8055e63acaf1b84c085d34226a14425b2c2b97b829e0e226d2e8f1299942a51d + languageName: node + linkType: hard + +"@babel/parser@npm:^8.0.0": + version: 8.0.0 + resolution: "@babel/parser@npm:8.0.0" + dependencies: + "@babel/types": "npm:^8.0.0" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/f10665bf3289f4bdc43bc58c482d6baa9fc4e306460d1bc57b059486dc9f23ed4463e746f62d721396466e2a2e0b32d856648b8c30dedbf6b69787b430f21e75 + languageName: node + linkType: hard + +"@babel/plugin-syntax-class-properties@npm:^7.12.13": + version: 7.12.13 + resolution: "@babel/plugin-syntax-class-properties@npm:7.12.13" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.12.13" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/95168fa186416195280b1264fb18afcdcdcea780b3515537b766cb90de6ce042d42dd6a204a39002f794ae5845b02afb0fd4861a3308a861204a55e68310a120 + languageName: node + linkType: hard + +"@babel/plugin-syntax-jsx@npm:^7.12.13, @babel/plugin-syntax-jsx@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/plugin-syntax-jsx@npm:7.29.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.29.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/1736000de183538ba8eef34520105508860e48b0c763254ba9158af5e814ed8bbceeedbb4281fbda33de787ae5b3870e92f60c6ae7131e7d322e451d57387896 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx-development@npm:^7.27.1": + version: 7.29.7 + resolution: "@babel/plugin-transform-react-jsx-development@npm:7.29.7" + dependencies: + "@babel/plugin-transform-react-jsx": "npm:^7.29.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/a2d44d068d35f8e6bc0437ba0da86526d4473491a43108caf77cba467a3ab522cbd09bcd8184b7a49f3d2b52e0883ad797ed2f91c090b857a80a6f383e88f449 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx@npm:^7.27.1, @babel/plugin-transform-react-jsx@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/plugin-transform-react-jsx@npm:7.29.7" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.29.7" + "@babel/helper-module-imports": "npm:^7.29.7" + "@babel/helper-plugin-utils": "npm:^7.29.7" + "@babel/plugin-syntax-jsx": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/ae6487c3deafcffda8a2c1b1eb77e0b7121630fa1a9646cecd73dbbdd8271532a0f7f0e8c01f69b6d39a36d8d79eb67e2d51031369c9055f18f7d8e70d9b5446 + languageName: node + linkType: hard + +"@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.29.2, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.7": + version: 7.29.7 + resolution: "@babel/runtime@npm:7.29.7" + checksum: 10c0/ca11572f7146b21e0bde6a9ed4bb6a89eafbee5f0944c7eb54d0d8a2dac962c33638a1d611e14faa71dfbb92b4b5f9236232208568a6b7d5c6f3f39ddb91771e + languageName: node + linkType: hard + +"@babel/template@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/template@npm:7.29.7" + dependencies: + "@babel/code-frame": "npm:^7.29.7" + "@babel/parser": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + checksum: 10c0/8bb7f900dcab0e9e1c5ffbc33ca10e0d26b7b2e2ca804becb73ee771b9c4ed6e2908a4ae4a14c08560febb45d2b6b9a173955e42ad404d05f8b04840a14d9c58 + languageName: node + linkType: hard + +"@babel/template@npm:^8.0.0": + version: 8.0.0 + resolution: "@babel/template@npm:8.0.0" + dependencies: + "@babel/code-frame": "npm:^8.0.0" + "@babel/parser": "npm:^8.0.0" + "@babel/types": "npm:^8.0.0" + checksum: 10c0/8a5e5687299517cc6b0efff3a6342cf4c4256aeeffa14753cc8d08106aaf0ba1916707c0e1f385b511a7b42c6c87806fecaecd4fe06316207475e0d4d1148e2c + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/traverse@npm:7.29.7" + dependencies: + "@babel/code-frame": "npm:^7.29.7" + "@babel/generator": "npm:^7.29.7" + "@babel/helper-globals": "npm:^7.29.7" + "@babel/parser": "npm:^7.29.7" + "@babel/template": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + debug: "npm:^4.3.1" + checksum: 10c0/e256a1fbdb956555b76f3c285b1e453f6bedec8b3afb61751d99d933efd11c7d79caf5ddf2493570058a9f7deaa1b48324380d7c1aa1443fd9508becbf56331a + languageName: node + linkType: hard + +"@babel/traverse@npm:^8.0.0": + version: 8.0.0 + resolution: "@babel/traverse@npm:8.0.0" + dependencies: + "@babel/code-frame": "npm:^8.0.0" + "@babel/generator": "npm:^8.0.0" + "@babel/helper-globals": "npm:^8.0.0" + "@babel/parser": "npm:^8.0.0" + "@babel/template": "npm:^8.0.0" + "@babel/types": "npm:^8.0.0" + obug: "npm:^2.1.1" + checksum: 10c0/de5e5c144c72a2949d75ea8baf5dd2926a6410512397ac28692719df45e31e70e26415e10cacfe2c1c1dd73e7276c6a8fc832754c8b14202627d64e1aa1a9393 + languageName: node + linkType: hard + +"@babel/types@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/types@npm:7.29.7" + dependencies: + "@babel/helper-string-parser": "npm:^7.29.7" + "@babel/helper-validator-identifier": "npm:^7.29.7" + checksum: 10c0/b6623994c69717fa27294f5fa46d59140338e2d86c6c1c13085c84ef7d53086ee357fbf4fe9abe3dd3da75734dc77c4c0df2f90fb29e667558bb3b3fb705e88f + languageName: node + linkType: hard + +"@babel/types@npm:^8.0.0": + version: 8.0.0 + resolution: "@babel/types@npm:8.0.0" + dependencies: + "@babel/helper-string-parser": "npm:^8.0.0" + "@babel/helper-validator-identifier": "npm:^8.0.0" + checksum: 10c0/f4130b88818cf9fd0fb653dd35459f58794018416bc0cee0eccefd364c2d146ae90611ae3ae19d91c2f0bbd1e0e440840832baf9a3d5eb5fed077a52f0bcc001 + languageName: node + linkType: hard + +"@base-ui/react@npm:^1.6.0": + version: 1.6.0 + resolution: "@base-ui/react@npm:1.6.0" + dependencies: + "@babel/runtime": "npm:^7.29.2" + "@base-ui/utils": "npm:0.3.1" + "@floating-ui/react-dom": "npm:^2.1.8" + "@floating-ui/utils": "npm:^0.2.11" + use-sync-external-store: "npm:^1.6.0" + peerDependencies: + "@date-fns/tz": ^1.2.0 + "@types/react": ^17 || ^18 || ^19 + date-fns: ^4.0.0 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + "@date-fns/tz": + optional: true + "@types/react": + optional: true + date-fns: + optional: true + checksum: 10c0/5e5994dc782710eac900d68cc0691aea70a47fabc6ef8d2ea943103d9aa96c4b44f9fd76ba65d29fa2667a5fbd7ea7a1cc02fe111c4bf639d4e3e65a1c281118 + languageName: node + linkType: hard + +"@base-ui/utils@npm:0.3.1": + version: 0.3.1 + resolution: "@base-ui/utils@npm:0.3.1" + dependencies: + "@babel/runtime": "npm:^7.29.2" + "@floating-ui/utils": "npm:^0.2.11" + reselect: "npm:^5.2.0" + use-sync-external-store: "npm:^1.6.0" + peerDependencies: + "@types/react": ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/4de858c3e2c8a4486a549d51c5e887bba6921e5a7f8db54439ba558feaf1656c3592a873928aee8a1711ee9210be3a65ca43b26713e97f649695ed2fa8c3af2c + languageName: node + linkType: hard + +"@emotion/babel-plugin@npm:^11.13.5": + version: 11.13.5 + resolution: "@emotion/babel-plugin@npm:11.13.5" + dependencies: + "@babel/helper-module-imports": "npm:^7.16.7" + "@babel/runtime": "npm:^7.18.3" + "@emotion/hash": "npm:^0.9.2" + "@emotion/memoize": "npm:^0.9.0" + "@emotion/serialize": "npm:^1.3.3" + babel-plugin-macros: "npm:^3.1.0" + convert-source-map: "npm:^1.5.0" + escape-string-regexp: "npm:^4.0.0" + find-root: "npm:^1.1.0" + source-map: "npm:^0.5.7" + stylis: "npm:4.2.0" + checksum: 10c0/8ccbfec7defd0e513cb8a1568fa179eac1e20c35fda18aed767f6c59ea7314363ebf2de3e9d2df66c8ad78928dc3dceeded84e6fa8059087cae5c280090aeeeb + languageName: node + linkType: hard + +"@emotion/cache@npm:^11.14.0": + version: 11.14.0 + resolution: "@emotion/cache@npm:11.14.0" + dependencies: + "@emotion/memoize": "npm:^0.9.0" + "@emotion/sheet": "npm:^1.4.0" + "@emotion/utils": "npm:^1.4.2" + "@emotion/weak-memoize": "npm:^0.4.0" + stylis: "npm:4.2.0" + checksum: 10c0/3fa3e7a431ab6f8a47c67132a00ac8358f428c1b6c8421d4b20de9df7c18e95eec04a5a6ff5a68908f98d3280044f247b4965ac63df8302d2c94dba718769724 + languageName: node + linkType: hard + +"@emotion/hash@npm:^0.9.2": + version: 0.9.2 + resolution: "@emotion/hash@npm:0.9.2" + checksum: 10c0/0dc254561a3cc0a06a10bbce7f6a997883fd240c8c1928b93713f803a2e9153a257a488537012efe89dbe1246f2abfe2add62cdb3471a13d67137fcb808e81c2 + languageName: node + linkType: hard + +"@emotion/is-prop-valid@npm:^1.3.0": + version: 1.4.0 + resolution: "@emotion/is-prop-valid@npm:1.4.0" + dependencies: + "@emotion/memoize": "npm:^0.9.0" + checksum: 10c0/5f857814ec7d8c7e727727346dfb001af6b1fb31d621a3ce9c3edf944a484d8b0d619546c30899ae3ade2f317c76390ba4394449728e9bf628312defc2c41ac3 + languageName: node + linkType: hard + +"@emotion/memoize@npm:^0.9.0": + version: 0.9.0 + resolution: "@emotion/memoize@npm:0.9.0" + checksum: 10c0/13f474a9201c7f88b543e6ea42f55c04fb2fdc05e6c5a3108aced2f7e7aa7eda7794c56bba02985a46d8aaa914fcdde238727a98341a96e2aec750d372dadd15 + languageName: node + linkType: hard + +"@emotion/react@npm:^11.14.0": + version: 11.14.0 + resolution: "@emotion/react@npm:11.14.0" + dependencies: + "@babel/runtime": "npm:^7.18.3" + "@emotion/babel-plugin": "npm:^11.13.5" + "@emotion/cache": "npm:^11.14.0" + "@emotion/serialize": "npm:^1.3.3" + "@emotion/use-insertion-effect-with-fallbacks": "npm:^1.2.0" + "@emotion/utils": "npm:^1.4.2" + "@emotion/weak-memoize": "npm:^0.4.0" + hoist-non-react-statics: "npm:^3.3.1" + peerDependencies: + react: ">=16.8.0" + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/d0864f571a9f99ec643420ef31fde09e2006d3943a6aba079980e4d5f6e9f9fecbcc54b8f617fe003c00092ff9d5241179149ffff2810cb05cf72b4620cfc031 + languageName: node + linkType: hard + +"@emotion/serialize@npm:^1.3.3": + version: 1.3.3 + resolution: "@emotion/serialize@npm:1.3.3" + dependencies: + "@emotion/hash": "npm:^0.9.2" + "@emotion/memoize": "npm:^0.9.0" + "@emotion/unitless": "npm:^0.10.0" + "@emotion/utils": "npm:^1.4.2" + csstype: "npm:^3.0.2" + checksum: 10c0/b28cb7de59de382021de2b26c0c94ebbfb16967a1b969a56fdb6408465a8993df243bfbd66430badaa6800e1834724e84895f5a6a9d97d0d224de3d77852acb4 + languageName: node + linkType: hard + +"@emotion/sheet@npm:^1.4.0": + version: 1.4.0 + resolution: "@emotion/sheet@npm:1.4.0" + checksum: 10c0/3ca72d1650a07d2fbb7e382761b130b4a887dcd04e6574b2d51ce578791240150d7072a9bcb4161933abbcd1e38b243a6fb4464a7fe991d700c17aa66bb5acc7 + languageName: node + linkType: hard + +"@emotion/styled@npm:^11.14.1": + version: 11.14.1 + resolution: "@emotion/styled@npm:11.14.1" + dependencies: + "@babel/runtime": "npm:^7.18.3" + "@emotion/babel-plugin": "npm:^11.13.5" + "@emotion/is-prop-valid": "npm:^1.3.0" + "@emotion/serialize": "npm:^1.3.3" + "@emotion/use-insertion-effect-with-fallbacks": "npm:^1.2.0" + "@emotion/utils": "npm:^1.4.2" + peerDependencies: + "@emotion/react": ^11.0.0-rc.0 + react: ">=16.8.0" + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/2bbf8451df49c967e41fbcf8111a7f6dafe6757f0cc113f2f6e287206c45ac1d54dc8a95a483b7c0cee8614b8a8d08155bded6453d6721de1f8cc8d5b9216963 + languageName: node + linkType: hard + +"@emotion/unitless@npm:^0.10.0": + version: 0.10.0 + resolution: "@emotion/unitless@npm:0.10.0" + checksum: 10c0/150943192727b7650eb9a6851a98034ddb58a8b6958b37546080f794696141c3760966ac695ab9af97efe10178690987aee4791f9f0ad1ff76783cdca83c1d49 + languageName: node + linkType: hard + +"@emotion/use-insertion-effect-with-fallbacks@npm:^1.2.0": + version: 1.2.0 + resolution: "@emotion/use-insertion-effect-with-fallbacks@npm:1.2.0" + peerDependencies: + react: ">=16.8.0" + checksum: 10c0/074dbc92b96bdc09209871070076e3b0351b6b47efefa849a7d9c37ab142130767609ca1831da0055988974e3b895c1de7606e4c421fecaa27c3e56a2afd3b08 + languageName: node + linkType: hard + +"@emotion/utils@npm:^1.4.2": + version: 1.4.2 + resolution: "@emotion/utils@npm:1.4.2" + checksum: 10c0/7d0010bf60a2a8c1a033b6431469de4c80e47aeb8fd856a17c1d1f76bbc3a03161a34aeaa78803566e29681ca551e7bf9994b68e9c5f5c796159923e44f78d9a + languageName: node + linkType: hard + +"@emotion/weak-memoize@npm:^0.4.0": + version: 0.4.0 + resolution: "@emotion/weak-memoize@npm:0.4.0" + checksum: 10c0/64376af11f1266042d03b3305c30b7502e6084868e33327e944b539091a472f089db307af69240f7188f8bc6b319276fd7b141a36613f1160d73d12a60f6ca1a + languageName: node + linkType: hard + +"@esbuild/aix-ppc64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/aix-ppc64@npm:0.27.7" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/android-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/android-arm64@npm:0.27.7" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/android-arm@npm:0.27.7" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@esbuild/android-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/android-x64@npm:0.27.7" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/darwin-arm64@npm:0.27.7" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/darwin-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/darwin-x64@npm:0.27.7" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/freebsd-arm64@npm:0.27.7" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/freebsd-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/freebsd-x64@npm:0.27.7" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-arm64@npm:0.27.7" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/linux-arm@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-arm@npm:0.27.7" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-ia32@npm:0.27.7" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/linux-loong64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-loong64@npm:0.27.7" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-mips64el@npm:0.27.7" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"@esbuild/linux-ppc64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-ppc64@npm:0.27.7" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-riscv64@npm:0.27.7" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + +"@esbuild/linux-s390x@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-s390x@npm:0.27.7" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-x64@npm:0.27.7" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/netbsd-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/netbsd-arm64@npm:0.27.7" + conditions: os=netbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/netbsd-x64@npm:0.27.7" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/openbsd-arm64@npm:0.27.7" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/openbsd-x64@npm:0.27.7" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openharmony-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/openharmony-arm64@npm:0.27.7" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/sunos-x64@npm:0.27.7" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/win32-arm64@npm:0.27.7" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/win32-ia32@npm:0.27.7" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/win32-x64@npm:0.27.7" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@eslint-community/eslint-utils@npm:^4.8.0": + version: 4.9.1 + resolution: "@eslint-community/eslint-utils@npm:4.9.1" + dependencies: + eslint-visitor-keys: "npm:^3.4.3" + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + checksum: 10c0/dc4ab5e3e364ef27e33666b11f4b86e1a6c1d7cbf16f0c6ff87b1619b3562335e9201a3d6ce806221887ff780ec9d828962a290bb910759fd40a674686503f02 + languageName: node + linkType: hard + +"@eslint-community/regexpp@npm:^4.12.2": + version: 4.12.2 + resolution: "@eslint-community/regexpp@npm:4.12.2" + checksum: 10c0/fddcbc66851b308478d04e302a4d771d6917a0b3740dc351513c0da9ca2eab8a1adf99f5e0aa7ab8b13fa0df005c81adeee7e63a92f3effd7d367a163b721c2d + languageName: node + linkType: hard + +"@eslint/config-array@npm:^0.23.5": + version: 0.23.5 + resolution: "@eslint/config-array@npm:0.23.5" + dependencies: + "@eslint/object-schema": "npm:^3.0.5" + debug: "npm:^4.3.1" + minimatch: "npm:^10.2.4" + checksum: 10c0/b24833c4c76e78ee075d306cd3f095db46b2db0f90cc13a6ee6e4275f9889731c05bf5403ab5fefb79c756e07ac9184ed0e04570341382f9eccbccc80e6d1a0c + languageName: node + linkType: hard + +"@eslint/config-helpers@npm:^0.6.0": + version: 0.6.0 + resolution: "@eslint/config-helpers@npm:0.6.0" + dependencies: + "@eslint/core": "npm:^1.2.1" + checksum: 10c0/f9af20e8b60b0ba27edb74b8eb40c0c5d51a9bf9baf9e053bb57833a87cb0a1c49b4dfaad88fc24d49c907ad1324c8a0b668684fa9c321351dac4bc9155ec10a + languageName: node + linkType: hard + +"@eslint/core@npm:^1.2.1": + version: 1.2.1 + resolution: "@eslint/core@npm:1.2.1" + dependencies: + "@types/json-schema": "npm:^7.0.15" + checksum: 10c0/10979b40588ecfef771fcb5013a542a35fb30692cc95a65f3481b0b36fbd89f5679efeb30d57f4eed35203d859aabace2a620177d6c536f71b299a1af2f3398f + languageName: node + linkType: hard + +"@eslint/js@npm:^9.29.0": + version: 9.39.4 + resolution: "@eslint/js@npm:9.39.4" + checksum: 10c0/5aa7dea2cbc5decf7f5e3b0c6f86a084ccee0f792d288ca8e839f8bc1b64e03e227068968e49b26096e6f71fd857ab6e42691d1b993826b9a3883f1bdd7a0e46 + languageName: node + linkType: hard + +"@eslint/object-schema@npm:^3.0.5": + version: 3.0.5 + resolution: "@eslint/object-schema@npm:3.0.5" + checksum: 10c0/1db337431f520b99e9edda64ef5fafd7ec6a029843eeb608753025125b6649d861d843cffafafd3c4e37926d7d5f9ec0c6a8e3665c13c3da2144e8132892e92e + languageName: node + linkType: hard + +"@eslint/plugin-kit@npm:^0.7.2": + version: 0.7.2 + resolution: "@eslint/plugin-kit@npm:0.7.2" + dependencies: + "@eslint/core": "npm:^1.2.1" + levn: "npm:^0.4.1" + checksum: 10c0/aafba08077bcd6d7dde6c2e21db18086046a88f914f29971a84cac9ad2d48952ded1b293e665e523805297eff756522dafa16f0062195e2c7143dcd1d47d11ed + languageName: node + linkType: hard + +"@floating-ui/core@npm:^1.7.5": + version: 1.7.5 + resolution: "@floating-ui/core@npm:1.7.5" + dependencies: + "@floating-ui/utils": "npm:^0.2.11" + checksum: 10c0/f9c52205e198b231d63a387b09c659aab08c46a1899e0b0bbe147b8b4f048b546f15ba17cb5d2a471da9534f1883d979425e13e5c4ceee67be63e4b0abd4db5d + languageName: node + linkType: hard + +"@floating-ui/dom@npm:^1.7.6": + version: 1.7.6 + resolution: "@floating-ui/dom@npm:1.7.6" + dependencies: + "@floating-ui/core": "npm:^1.7.5" + "@floating-ui/utils": "npm:^0.2.11" + checksum: 10c0/5c098e0d7b58c9bc769f276cca1766994c2c9c70c92d091a61bba8b3e9be53c011e0a79a8457fc2fb2f3d91697a26eb52e0a4962ef936dc963b45f58613c212f + languageName: node + linkType: hard + +"@floating-ui/react-dom@npm:^2.1.8": + version: 2.1.8 + resolution: "@floating-ui/react-dom@npm:2.1.8" + dependencies: + "@floating-ui/dom": "npm:^1.7.6" + peerDependencies: + react: ">=16.8.0" + react-dom: ">=16.8.0" + checksum: 10c0/26260ca4bb23b57c73b824062505abf977a008ce6e0463bdacca74f7e49853c4cd1d2bbf1a77c6caa17fa37dfffda2c6c4cd07a8737ebd7474aaff7818401d75 + languageName: node + linkType: hard + +"@floating-ui/utils@npm:^0.2.11": + version: 0.2.11 + resolution: "@floating-ui/utils@npm:0.2.11" + checksum: 10c0/f4bcea1559bdbb721ecc8e8ead423ac58d6a5b6e70b602cf0810ba6ad4ed1c77211b207faa88b278a9042f0c743133de08a203ed6741c1b6443423332884d5b3 + languageName: node + linkType: hard + +"@fontsource/roboto@npm:^5.2.10": + version: 5.2.10 + resolution: "@fontsource/roboto@npm:5.2.10" + checksum: 10c0/abadfcaefbe2196bbd36d9258b336063f721894a3624a9639da00792583c565bfd0748ef978f91a38c3c0de8d247615c9be92a763184c085c630fa43f04b1cd9 + languageName: node + linkType: hard + +"@humanfs/core@npm:^0.19.2": + version: 0.19.2 + resolution: "@humanfs/core@npm:0.19.2" + dependencies: + "@humanfs/types": "npm:^0.15.0" + checksum: 10c0/d0a1d52d7b30c27d49475a53072d1510b81c5803e44b342fb8faf3887f1aa27593a1e6dc76a45268e7892d3f4e198146659281f6b6d55eacf3fd5a38bac30c5c + languageName: node + linkType: hard + +"@humanfs/node@npm:^0.16.6": + version: 0.16.8 + resolution: "@humanfs/node@npm:0.16.8" + dependencies: + "@humanfs/core": "npm:^0.19.2" + "@humanfs/types": "npm:^0.15.0" + "@humanwhocodes/retry": "npm:^0.4.0" + checksum: 10c0/56140579db811af4e160b195d45d0f29acf644d192c93fe24c9e594ebf06f19dfc157494a07c84540b8a071c0e4b37209c2362765d31734f4d0be869c2422e25 + languageName: node + linkType: hard + +"@humanfs/types@npm:^0.15.0": + version: 0.15.0 + resolution: "@humanfs/types@npm:0.15.0" + checksum: 10c0/fc26b9a024b0e55f7eaf64036df94345bf5d36d6a41ef80ef38e78f1f7430ce26cf435af736adae58913baae18eac3f38c18739054a3d379102015978eae862e + languageName: node + linkType: hard + +"@humanwhocodes/module-importer@npm:^1.0.1": + version: 1.0.1 + resolution: "@humanwhocodes/module-importer@npm:1.0.1" + checksum: 10c0/909b69c3b86d482c26b3359db16e46a32e0fb30bd306a3c176b8313b9e7313dba0f37f519de6aa8b0a1921349e505f259d19475e123182416a506d7f87e7f529 + languageName: node + linkType: hard + +"@humanwhocodes/retry@npm:^0.4.0, @humanwhocodes/retry@npm:^0.4.2": + version: 0.4.3 + resolution: "@humanwhocodes/retry@npm:0.4.3" + checksum: 10c0/3775bb30087d4440b3f7406d5a057777d90e4b9f435af488a4923ef249e93615fb78565a85f173a186a076c7706a81d0d57d563a2624e4de2c5c9c66c486ce42 + languageName: node + linkType: hard + +"@isaacs/fs-minipass@npm:^4.0.0": + version: 4.0.1 + resolution: "@isaacs/fs-minipass@npm:4.0.1" + dependencies: + minipass: "npm:^7.0.4" + checksum: 10c0/c25b6dc1598790d5b55c0947a9b7d111cfa92594db5296c3b907e2f533c033666f692a3939eadac17b1c7c40d362d0b0635dc874cbfe3e70db7c2b07cc97a5d2 + languageName: node + linkType: hard + +"@jridgewell/gen-mapping@npm:^0.3.12, @jridgewell/gen-mapping@npm:^0.3.5": + version: 0.3.13 + resolution: "@jridgewell/gen-mapping@npm:0.3.13" + dependencies: + "@jridgewell/sourcemap-codec": "npm:^1.5.0" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/9a7d65fb13bd9aec1fbab74cda08496839b7e2ceb31f5ab922b323e94d7c481ce0fc4fd7e12e2610915ed8af51178bdc61e168e92a8c8b8303b030b03489b13b + languageName: node + linkType: hard + +"@jridgewell/remapping@npm:^2.3.5": + version: 2.3.5 + resolution: "@jridgewell/remapping@npm:2.3.5" + dependencies: + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/3de494219ffeb2c5c38711d0d7bb128097edf91893090a2dbc8ee0b55d092bb7347b1fd0f478486c5eab010e855c73927b1666f2107516d472d24a73017d1194 + languageName: node + linkType: hard + +"@jridgewell/resolve-uri@npm:^3.1.0": + version: 3.1.2 + resolution: "@jridgewell/resolve-uri@npm:3.1.2" + checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0, @jridgewell/sourcemap-codec@npm:^1.5.5": + version: 1.5.5 + resolution: "@jridgewell/sourcemap-codec@npm:1.5.5" + checksum: 10c0/f9e538f302b63c0ebc06eecb1dd9918dd4289ed36147a0ddce35d6ea4d7ebbda243cda7b2213b6a5e1d8087a298d5cf630fb2bd39329cdecb82017023f6081a0 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.28": + version: 0.3.31 + resolution: "@jridgewell/trace-mapping@npm:0.3.31" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.1.0" + "@jridgewell/sourcemap-codec": "npm:^1.4.14" + checksum: 10c0/4b30ec8cd56c5fd9a661f088230af01e0c1a3888d11ffb6b47639700f71225be21d1f7e168048d6d4f9449207b978a235c07c8f15c07705685d16dc06280e9d9 + languageName: node + linkType: hard + +"@mdn/browser-compat-data@npm:^5.6.19": + version: 5.7.6 + resolution: "@mdn/browser-compat-data@npm:5.7.6" + checksum: 10c0/918df768e734115bee0a43fb2eceaf6438cb9b294c27e13d0ac8a19ab9f00f59e4f306fc38c498b62bdec2d726d4f3874826fa2afccd2a29d50d306f687bfdff + languageName: node + linkType: hard + +"@mdn/browser-compat-data@npm:^6.1.1": + version: 6.1.5 + resolution: "@mdn/browser-compat-data@npm:6.1.5" + checksum: 10c0/a2d8ef7cdb3268c72540909755d4d56ae5a8674ddd8216a3bd4a40e4d1497c01b0205a29a8fd6bf4599e091cbc8a90d9a3a52836a8439d66b0af00886f68e7b9 + languageName: node + linkType: hard + +"@mui/core-downloads-tracker@npm:^9.1.2": + version: 9.1.2 + resolution: "@mui/core-downloads-tracker@npm:9.1.2" + checksum: 10c0/787f9bf6bc178cf405252bbd7ab8fd24375cb203fe36beedc29165eea432bf120e1fdf61b22de0037b6e2db6702c9f348c8f45164a5c367a3f3dbacea6f1fe04 + languageName: node + linkType: hard + +"@mui/icons-material@npm:^9.1.1": + version: 9.1.1 + resolution: "@mui/icons-material@npm:9.1.1" + dependencies: + "@babel/runtime": "npm:^7.29.2" + peerDependencies: + "@mui/material": ^9.1.1 + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/bb7719221fed6258be9959538986aa9525370a0db25ca4acf3d58adb85a119ebc98ca519054789efffb3813aeea9c83d120b3e0358f7b67e88f73997ef33c986 + languageName: node + linkType: hard + +"@mui/material@npm:^9.1.2": + version: 9.1.2 + resolution: "@mui/material@npm:9.1.2" + dependencies: + "@babel/runtime": "npm:^7.29.2" + "@mui/core-downloads-tracker": "npm:^9.1.2" + "@mui/system": "npm:^9.1.2" + "@mui/types": "npm:^9.1.1" + "@mui/utils": "npm:^9.1.1" + "@popperjs/core": "npm:^2.11.8" + "@types/react-transition-group": "npm:^4.4.12" + clsx: "npm:^2.1.1" + csstype: "npm:^3.2.3" + prop-types: "npm:^15.8.1" + react-is: "npm:^19.2.6" + react-transition-group: "npm:^4.4.5" + peerDependencies: + "@emotion/react": ^11.5.0 + "@emotion/styled": ^11.3.0 + "@mui/material-pigment-css": ^9.1.1 + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/react": + optional: true + "@emotion/styled": + optional: true + "@mui/material-pigment-css": + optional: true + "@types/react": + optional: true + checksum: 10c0/b3279d4b8f2df6c6de88b51bb236b8f800dbc83d37eb168c4525bef01990a1e4016f65868a68e0244fd01113bba9b297e9fc10c41499b1b540c4c3778b61da5e + languageName: node + linkType: hard + +"@mui/private-theming@npm:^9.1.1": + version: 9.1.1 + resolution: "@mui/private-theming@npm:9.1.1" + dependencies: + "@babel/runtime": "npm:^7.29.2" + "@mui/utils": "npm:^9.1.1" + prop-types: "npm:^15.8.1" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/edf9cd75aee97a6b95e2ea98cbb4c8d3f72db48db909c445f3129a6a5fad00ca917ec1bfdd1d107481ecc20b9c9d9560298cb588102f069c0b0a5a9c7198eb49 + languageName: node + linkType: hard + +"@mui/styled-engine@npm:^9.1.1": + version: 9.1.1 + resolution: "@mui/styled-engine@npm:9.1.1" + dependencies: + "@babel/runtime": "npm:^7.29.2" + "@emotion/cache": "npm:^11.14.0" + "@emotion/serialize": "npm:^1.3.3" + "@emotion/sheet": "npm:^1.4.0" + csstype: "npm:^3.2.3" + prop-types: "npm:^15.8.1" + peerDependencies: + "@emotion/react": ^11.4.1 + "@emotion/styled": ^11.3.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/react": + optional: true + "@emotion/styled": + optional: true + checksum: 10c0/250bb2a94ac3399a3a9c2ba81871419100fed51b823b87a935215c50781aace3022585697039898073964e661e749abd9e30a6a241ce7567ad5eec47ef082467 + languageName: node + linkType: hard + +"@mui/system@npm:^9.1.2": + version: 9.1.2 + resolution: "@mui/system@npm:9.1.2" + dependencies: + "@babel/runtime": "npm:^7.29.2" + "@mui/private-theming": "npm:^9.1.1" + "@mui/styled-engine": "npm:^9.1.1" + "@mui/types": "npm:^9.1.1" + "@mui/utils": "npm:^9.1.1" + clsx: "npm:^2.1.1" + csstype: "npm:^3.2.3" + prop-types: "npm:^15.8.1" + peerDependencies: + "@emotion/react": ^11.5.0 + "@emotion/styled": ^11.3.0 + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/react": + optional: true + "@emotion/styled": + optional: true + "@types/react": + optional: true + checksum: 10c0/9f274cf009e4235a9bbb9a6524aa2de6ba59a3fc01e91157004be1a4d5c6d4db5f16d91dfe95d3c3acb36fa355a8ac7d811b146a547f3b9292c2a1c981adb707 + languageName: node + linkType: hard + +"@mui/types@npm:^9.1.1": + version: 9.1.1 + resolution: "@mui/types@npm:9.1.1" + dependencies: + "@babel/runtime": "npm:^7.29.2" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/83cb89cafba0c55c909a8a89bd165550a71f92a67bbd191823b6ec304e5f59b43438052fecc4f69cc27e4e557c6bce3d5a073b9f5d5787d62d8cdc055e479905 + languageName: node + linkType: hard + +"@mui/utils@npm:^9.1.1": + version: 9.1.1 + resolution: "@mui/utils@npm:9.1.1" + dependencies: + "@babel/runtime": "npm:^7.29.2" + "@mui/types": "npm:^9.1.1" + "@types/prop-types": "npm:^15.7.15" + clsx: "npm:^2.1.1" + prop-types: "npm:^15.8.1" + react-is: "npm:^19.2.6" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/a39936fa287ba3f53c47ef3072b813b797a75b43ed95212e817e9d3828e2de8079ae834061fc7e76b096eb0ceddd39468f4f0423ac25b6ac39aa77d70945966b + languageName: node + linkType: hard + +"@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1": + version: 5.1.1-v1 + resolution: "@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1" + dependencies: + eslint-scope: "npm:5.1.1" + checksum: 10c0/75dda3e623b8ad7369ca22552d6beee337a814b2d0e8a32d23edd13fcb65c8082b32c5d86e436f3860dd7ade30d91d5db55d4ef9a08fb5a976c718ecc0d88a74 + languageName: node + linkType: hard + +"@popperjs/core@npm:^2.11.8": + version: 2.11.8 + resolution: "@popperjs/core@npm:2.11.8" + checksum: 10c0/4681e682abc006d25eb380d0cf3efc7557043f53b6aea7a5057d0d1e7df849a00e281cd8ea79c902a35a414d7919621fc2ba293ecec05f413598e0b23d5a1e63 + languageName: node + linkType: hard + +"@preact/preset-vite@npm:^2.10.2": + version: 2.10.5 + resolution: "@preact/preset-vite@npm:2.10.5" + dependencies: + "@babel/plugin-transform-react-jsx": "npm:^7.27.1" + "@babel/plugin-transform-react-jsx-development": "npm:^7.27.1" + "@prefresh/vite": "npm:^2.4.11" + "@rollup/pluginutils": "npm:^5.0.0" + babel-plugin-transform-hook-names: "npm:^1.0.2" + debug: "npm:^4.4.3" + magic-string: "npm:^0.30.21" + picocolors: "npm:^1.1.1" + vite-prerender-plugin: "npm:^0.5.8" + zimmerframe: "npm:^1.1.4" + peerDependencies: + "@babel/core": 7.x + vite: 2.x || 3.x || 4.x || 5.x || 6.x || 7.x || 8.x + checksum: 10c0/fb548ffa0f7a90699ddc909b318d70d1f6f255a26193628578ef81517258d63d50d412b9dc87a5a4d9b13c4a62d47e9688aeee575bc8cdeeeefe5145e62ea741 + languageName: node + linkType: hard + +"@prefresh/babel-plugin@npm:^0.5.2": + version: 0.5.3 + resolution: "@prefresh/babel-plugin@npm:0.5.3" + checksum: 10c0/59cb7bde2dac2265f28f18c8fc3799efd75ebb117c7df19c7fea597a03db4af973ee56a21e9fa2588f707a3ef8a90ddc19e95d1d151641a068d98a690b0bc6ea + languageName: node + linkType: hard + +"@prefresh/core@npm:^1.5.0": + version: 1.5.10 + resolution: "@prefresh/core@npm:1.5.10" + peerDependencies: + preact: ^10.0.0 || ^11.0.0-0 + checksum: 10c0/61320c197b8075f0a2895b2cde75d9600b471b4241eb4a5855547fdef20298f732480e27522bb6e9ca64d47d645dd45717d9c0571446523c5b0701063c486c60 + languageName: node + linkType: hard + +"@prefresh/utils@npm:^1.2.0": + version: 1.2.1 + resolution: "@prefresh/utils@npm:1.2.1" + checksum: 10c0/d36bcc8995128ee9028e2c48cb7812c7736a0c8e228ded586de4595f587b239ec9daac2c82221a476ffd341412dbb62082d09f7191d3ee7f5d0b8a99a45f01a8 + languageName: node + linkType: hard + +"@prefresh/vite@npm:^2.4.11": + version: 2.4.12 + resolution: "@prefresh/vite@npm:2.4.12" + dependencies: + "@babel/core": "npm:^7.22.1" + "@prefresh/babel-plugin": "npm:^0.5.2" + "@prefresh/core": "npm:^1.5.0" + "@prefresh/utils": "npm:^1.2.0" + "@rollup/pluginutils": "npm:^4.2.1" + peerDependencies: + preact: ^10.4.0 || ^11.0.0-0 + vite: ">=2.0.0" + checksum: 10c0/b3e9957a6821831c294457fd0b5063fa83828fc9837b01472a377c858d3335a3c88920e99ce77381de3a63f8394459423d812e973d9afd32950b4e0db66970df + languageName: node + linkType: hard + +"@rollup/pluginutils@npm:^4.2.1": + version: 4.2.1 + resolution: "@rollup/pluginutils@npm:4.2.1" + dependencies: + estree-walker: "npm:^2.0.1" + picomatch: "npm:^2.2.2" + checksum: 10c0/3ee56b2c8f1ed8dfd0a92631da1af3a2dfdd0321948f089b3752b4de1b54dc5076701eadd0e5fc18bd191b77af594ac1db6279e83951238ba16bf8a414c64c48 + languageName: node + linkType: hard + +"@rollup/pluginutils@npm:^5.0.0": + version: 5.4.0 + resolution: "@rollup/pluginutils@npm:5.4.0" + dependencies: + "@types/estree": "npm:^1.0.0" + estree-walker: "npm:^2.0.2" + picomatch: "npm:^4.0.2" + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 10c0/ccc2cbd3a05df642df60ab05ffb81b2e564bd945e2a118bb8a474ea75b941033c8f44273133d4865643cca1492d0c80b14de1281f74779a64285a80fc3a194d8 + languageName: node + linkType: hard + +"@rollup/rollup-android-arm-eabi@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.62.2" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@rollup/rollup-android-arm64@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-android-arm64@npm:4.62.2" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-arm64@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-darwin-arm64@npm:4.62.2" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-x64@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-darwin-x64@npm:4.62.2" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-freebsd-arm64@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.62.2" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-freebsd-x64@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-freebsd-x64@npm:4.62.2" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-gnueabihf@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.62.2" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-musleabihf@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.62.2" + conditions: os=linux & cpu=arm & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-gnu@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.62.2" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-musl@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.62.2" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-loong64-gnu@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.62.2" + conditions: os=linux & cpu=loong64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-loong64-musl@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-linux-loong64-musl@npm:4.62.2" + conditions: os=linux & cpu=loong64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-ppc64-gnu@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.62.2" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-ppc64-musl@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-linux-ppc64-musl@npm:4.62.2" + conditions: os=linux & cpu=ppc64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-gnu@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.62.2" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-musl@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.62.2" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-s390x-gnu@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.62.2" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-gnu@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.62.2" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-musl@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.62.2" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-openbsd-x64@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-openbsd-x64@npm:4.62.2" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-openharmony-arm64@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-openharmony-arm64@npm:4.62.2" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-arm64-msvc@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.62.2" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-ia32-msvc@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.62.2" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-gnu@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-win32-x64-gnu@npm:4.62.2" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-msvc@npm:4.62.2": + version: 4.62.2 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.62.2" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@types/esrecurse@npm:^4.3.1": + version: 4.3.1 + resolution: "@types/esrecurse@npm:4.3.1" + checksum: 10c0/90dad74d5da3ad27606d8e8e757322f33171cfeaa15ad558b615cf71bb2a516492d18f55f4816384685a3eb2412142e732bbae9a4a7cd2cf3deb7572aa4ebe03 + languageName: node + linkType: hard + +"@types/estree@npm:1.0.9, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6, @types/estree@npm:^1.0.8": + version: 1.0.9 + resolution: "@types/estree@npm:1.0.9" + checksum: 10c0/3ad3286ca2988cd550dafb8f2ad599c8474868e954fa601a36655bdfefd8039f7c714b8c1c7f2ae219ffbd58bd4660e66fa7479a0120fc02d4777057d4865387 + languageName: node + linkType: hard + +"@types/gensync@npm:^1.0.5": + version: 1.0.5 + resolution: "@types/gensync@npm:1.0.5" + checksum: 10c0/7c37c8fc3b1a49efd8889f635a6204008f1c1cc86a09ac6a96e219cf3fc52cf1ff091c4dddc3160e93261d6e599fbba39f5fb698fbf936518d1c410289cdd640 + languageName: node + linkType: hard + +"@types/jsesc@npm:^2.5.0": + version: 2.5.1 + resolution: "@types/jsesc@npm:2.5.1" + checksum: 10c0/12ba7bf5968aeeb36408269f4b5a39718efc6411fa197cf0f5e967ba36ad7b7d555b78787fc480db43ce63ebe6ab0ffe5fd9f64b1ea3b0d073877f0747491b30 + languageName: node + linkType: hard + +"@types/json-schema@npm:^7.0.15": + version: 7.0.15 + resolution: "@types/json-schema@npm:7.0.15" + checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db + languageName: node + linkType: hard + +"@types/parse-json@npm:^4.0.0": + version: 4.0.2 + resolution: "@types/parse-json@npm:4.0.2" + checksum: 10c0/b1b863ac34a2c2172fbe0807a1ec4d5cb684e48d422d15ec95980b81475fac4fdb3768a8b13eef39130203a7c04340fc167bae057c7ebcafd7dec9fe6c36aeb1 + languageName: node + linkType: hard + +"@types/prop-types@npm:^15.7.15": + version: 15.7.15 + resolution: "@types/prop-types@npm:15.7.15" + checksum: 10c0/b59aad1ad19bf1733cf524fd4e618196c6c7690f48ee70a327eb450a42aab8e8a063fbe59ca0a5701aebe2d92d582292c0fb845ea57474f6a15f6994b0e260b2 + languageName: node + linkType: hard + +"@types/react-transition-group@npm:^4.4.12": + version: 4.4.12 + resolution: "@types/react-transition-group@npm:4.4.12" + peerDependencies: + "@types/react": "*" + checksum: 10c0/0441b8b47c69312c89ec0760ba477ba1a0808a10ceef8dc1c64b1013ed78517332c30f18681b0ec0b53542731f1ed015169fed1d127cc91222638ed955478ec7 + languageName: node + linkType: hard + +"abbrev@npm:^5.0.0": + version: 5.0.0 + resolution: "abbrev@npm:5.0.0" + checksum: 10c0/8e88f5c798ea4562d28c5a3e9ad69e3879890bc5d695d8f2dffb8609be4c890aacc8f80ef4553fdd2c6a62d70c2ce8bc57b38074e383beb7487bdafa9ed42ea5 + languageName: node + linkType: hard + +"acorn-jsx@npm:^5.3.2": + version: 5.3.2 + resolution: "acorn-jsx@npm:5.3.2" + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 10c0/4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1 + languageName: node + linkType: hard + +"acorn@npm:^8.16.0": + version: 8.17.0 + resolution: "acorn@npm:8.17.0" + bin: + acorn: bin/acorn + checksum: 10c0/5dcefea5f8f023b6cc24cbe71fb5a8112b601d36c4fa07d14e4e6ffc2ee47383332c46b36c766d9437725aa6660156eae50efa0c838719823b50d7c327c4ed42 + languageName: node + linkType: hard + +"agent-base@npm:6": + version: 6.0.2 + resolution: "agent-base@npm:6.0.2" + dependencies: + debug: "npm:4" + checksum: 10c0/dc4f757e40b5f3e3d674bc9beb4f1048f4ee83af189bae39be99f57bf1f48dde166a8b0a5342a84b5944ee8e6ed1e5a9d801858f4ad44764e84957122fe46261 + languageName: node + linkType: hard + +"ajv@npm:^6.14.0": + version: 6.15.0 + resolution: "ajv@npm:6.15.0" + dependencies: + fast-deep-equal: "npm:^3.1.1" + fast-json-stable-stringify: "npm:^2.0.0" + json-schema-traverse: "npm:^0.4.1" + uri-js: "npm:^4.2.2" + checksum: 10c0/67966499dd272ecde1c2e467084411132891523d057487587879d39ac04207f4351b7b2324c83198013967fbfa632c1612adc960114a30770fbe07a0773b32c2 + languageName: node + linkType: hard + +"array-buffer-byte-length@npm:^1.0.1, array-buffer-byte-length@npm:^1.0.2": + version: 1.0.2 + resolution: "array-buffer-byte-length@npm:1.0.2" + dependencies: + call-bound: "npm:^1.0.3" + is-array-buffer: "npm:^3.0.5" + checksum: 10c0/74e1d2d996941c7a1badda9cabb7caab8c449db9086407cad8a1b71d2604cc8abf105db8ca4e02c04579ec58b7be40279ddb09aea4784832984485499f48432d + languageName: node + linkType: hard + +"array-includes@npm:^3.1.6, array-includes@npm:^3.1.8": + version: 3.1.9 + resolution: "array-includes@npm:3.1.9" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.4" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.24.0" + es-object-atoms: "npm:^1.1.1" + get-intrinsic: "npm:^1.3.0" + is-string: "npm:^1.1.1" + math-intrinsics: "npm:^1.1.0" + checksum: 10c0/0235fa69078abeac05ac4250699c44996bc6f774a9cbe45db48674ce6bd142f09b327d31482ff75cf03344db4ea03eae23edb862d59378b484b47ed842574856 + languageName: node + linkType: hard + +"array.prototype.findlast@npm:^1.2.5": + version: 1.2.5 + resolution: "array.prototype.findlast@npm:1.2.5" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.2" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" + es-shim-unscopables: "npm:^1.0.2" + checksum: 10c0/ddc952b829145ab45411b9d6adcb51a8c17c76bf89c9dd64b52d5dffa65d033da8c076ed2e17091779e83bc892b9848188d7b4b33453c5565e65a92863cb2775 + languageName: node + linkType: hard + +"array.prototype.flat@npm:^1.3.1": + version: 1.3.3 + resolution: "array.prototype.flat@npm:1.3.3" + dependencies: + call-bind: "npm:^1.0.8" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.5" + es-shim-unscopables: "npm:^1.0.2" + checksum: 10c0/d90e04dfbc43bb96b3d2248576753d1fb2298d2d972e29ca7ad5ec621f0d9e16ff8074dae647eac4f31f4fb7d3f561a7ac005fb01a71f51705a13b5af06a7d8a + languageName: node + linkType: hard + +"array.prototype.flatmap@npm:^1.3.3": + version: 1.3.3 + resolution: "array.prototype.flatmap@npm:1.3.3" + dependencies: + call-bind: "npm:^1.0.8" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.5" + es-shim-unscopables: "npm:^1.0.2" + checksum: 10c0/ba899ea22b9dc9bf276e773e98ac84638ed5e0236de06f13d63a90b18ca9e0ec7c97d622d899796e3773930b946cd2413d098656c0c5d8cc58c6f25c21e6bd54 + languageName: node + linkType: hard + +"array.prototype.tosorted@npm:^1.1.4": + version: 1.1.4 + resolution: "array.prototype.tosorted@npm:1.1.4" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.3" + es-errors: "npm:^1.3.0" + es-shim-unscopables: "npm:^1.0.2" + checksum: 10c0/eb3c4c4fc0381b0bf6dba2ea4d48d367c2827a0d4236a5718d97caaccc6b78f11f4cadf090736e86301d295a6aa4967ed45568f92ced51be8cbbacd9ca410943 + languageName: node + linkType: hard + +"arraybuffer.prototype.slice@npm:^1.0.4": + version: 1.0.4 + resolution: "arraybuffer.prototype.slice@npm:1.0.4" + dependencies: + array-buffer-byte-length: "npm:^1.0.1" + call-bind: "npm:^1.0.8" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.5" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.6" + is-array-buffer: "npm:^3.0.4" + checksum: 10c0/2f2459caa06ae0f7f615003f9104b01f6435cc803e11bd2a655107d52a1781dc040532dc44d93026b694cc18793993246237423e13a5337e86b43ed604932c06 + languageName: node + linkType: hard + +"ast-metadata-inferer@npm:^0.8.1": + version: 0.8.1 + resolution: "ast-metadata-inferer@npm:0.8.1" + dependencies: + "@mdn/browser-compat-data": "npm:^5.6.19" + checksum: 10c0/4bfa6c268951f31123c2ea902d13d8fda5a226679a028eab7ccc063b5cc10964b07a30f075c3876fadaec315df9a894490ed24e6cb5c185afd373da42fff7a4f + languageName: node + linkType: hard + +"async-function@npm:^1.0.0": + version: 1.0.0 + resolution: "async-function@npm:1.0.0" + checksum: 10c0/669a32c2cb7e45091330c680e92eaeb791bc1d4132d827591e499cd1f776ff5a873e77e5f92d0ce795a8d60f10761dec9ddfe7225a5de680f5d357f67b1aac73 + languageName: node + linkType: hard + +"asynckit@npm:^0.4.0": + version: 0.4.0 + resolution: "asynckit@npm:0.4.0" + checksum: 10c0/d73e2ddf20c4eb9337e1b3df1a0f6159481050a5de457c55b14ea2e5cb6d90bb69e004c9af54737a5ee0917fcf2c9e25de67777bbe58261847846066ba75bc9d + languageName: node + linkType: hard + +"available-typed-arrays@npm:^1.0.7": + version: 1.0.7 + resolution: "available-typed-arrays@npm:1.0.7" + dependencies: + possible-typed-array-names: "npm:^1.0.0" + checksum: 10c0/d07226ef4f87daa01bd0fe80f8f310982e345f372926da2e5296aecc25c41cab440916bbaa4c5e1034b453af3392f67df5961124e4b586df1e99793a1374bdb2 + languageName: node + linkType: hard + +"axios@npm:^1.18.1": + version: 1.18.1 + resolution: "axios@npm:1.18.1" + dependencies: + follow-redirects: "npm:^1.16.0" + form-data: "npm:^4.0.5" + https-proxy-agent: "npm:^5.0.1" + proxy-from-env: "npm:^2.1.0" + checksum: 10c0/9d9378a3af0d0ad730a52ad9d15ec7201f3926ad6e7e8bbffc5ae21ca2835ad11d1d9598698f5dd9718917486039f55ea1d7dc23d8e44fa827a55cc3262c02fc + languageName: node + linkType: hard + +"babel-plugin-macros@npm:^3.1.0": + version: 3.1.0 + resolution: "babel-plugin-macros@npm:3.1.0" + dependencies: + "@babel/runtime": "npm:^7.12.5" + cosmiconfig: "npm:^7.0.0" + resolve: "npm:^1.19.0" + checksum: 10c0/c6dfb15de96f67871d95bd2e8c58b0c81edc08b9b087dc16755e7157f357dc1090a8dc60ebab955e92587a9101f02eba07e730adc253a1e4cf593ca3ebd3839c + languageName: node + linkType: hard + +"babel-plugin-transform-hook-names@npm:^1.0.2": + version: 1.0.2 + resolution: "babel-plugin-transform-hook-names@npm:1.0.2" + peerDependencies: + "@babel/core": ^7.12.10 + checksum: 10c0/517b85fe0611d742b3fffad5d0e119fcbd29bf69f95c6970b9ede4cb66453c7106a2d3bf048b35255b78a9d6a9565ad37e73b46c0be1fe557e941c792fad79f0 + languageName: node + linkType: hard + +"balanced-match@npm:^1.0.0": + version: 1.0.2 + resolution: "balanced-match@npm:1.0.2" + checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee + languageName: node + linkType: hard + +"balanced-match@npm:^4.0.2": + version: 4.0.4 + resolution: "balanced-match@npm:4.0.4" + checksum: 10c0/07e86102a3eb2ee2a6a1a89164f29d0dbaebd28f2ca3f5ca786f36b8b23d9e417eb3be45a4acf754f837be5ac0a2317de90d3fcb7f4f4dc95720a1f36b26a17b + languageName: node + linkType: hard + +"baseline-browser-mapping@npm:^2.10.12": + version: 2.10.38 + resolution: "baseline-browser-mapping@npm:2.10.38" + bin: + baseline-browser-mapping: dist/cli.cjs + checksum: 10c0/44bbea61ec54df6845f5f6f149c99057370081f1041d6e8dbc92835630ce37da9adc102528ebebd37f563342da2a5eea525d24698ced6674cdcfadb2ed613136 + languageName: node + linkType: hard + +"boolbase@npm:^1.0.0": + version: 1.0.0 + resolution: "boolbase@npm:1.0.0" + checksum: 10c0/e4b53deb4f2b85c52be0e21a273f2045c7b6a6ea002b0e139c744cb6f95e9ec044439a52883b0d74dedd1ff3da55ed140cfdddfed7fb0cccbed373de5dce1bcf + languageName: node + linkType: hard + +"brace-expansion@npm:^1.1.7": + version: 1.1.15 + resolution: "brace-expansion@npm:1.1.15" + dependencies: + balanced-match: "npm:^1.0.0" + concat-map: "npm:0.0.1" + checksum: 10c0/648e273f57cfa9ed67d8a77bdb15b408205465d33da9331808ee3c188d8b55674c9cdbf1f320b65bc562e485e1263360ae62ad355e128e0435891f6430e795d7 + languageName: node + linkType: hard + +"brace-expansion@npm:^5.0.5": + version: 5.0.6 + resolution: "brace-expansion@npm:5.0.6" + dependencies: + balanced-match: "npm:^4.0.2" + checksum: 10c0/8c919869b90f61d533b341d3340be5ee4413232ea89b8246cbc2f38eb014f1d8182785c98a006eaf6111d02dc9eeffefdc240d5ac158625b2ed084dccd4bbf9b + languageName: node + linkType: hard + +"browserslist@npm:^4.24.0, browserslist@npm:^4.25.2": + version: 4.28.2 + resolution: "browserslist@npm:4.28.2" + dependencies: + baseline-browser-mapping: "npm:^2.10.12" + caniuse-lite: "npm:^1.0.30001782" + electron-to-chromium: "npm:^1.5.328" + node-releases: "npm:^2.0.36" + update-browserslist-db: "npm:^1.2.3" + bin: + browserslist: cli.js + checksum: 10c0/c0228b6330f785b7fa59d2d360124ec6d9322f96ed9f3ee1f873e33ecc9503a6f0ffc3b71191a28c4ff6e930b753b30043da1c33844a9548f3018d491f09ce60 + languageName: node + linkType: hard + +"call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": + version: 1.0.2 + resolution: "call-bind-apply-helpers@npm:1.0.2" + dependencies: + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + checksum: 10c0/47bd9901d57b857590431243fea704ff18078b16890a6b3e021e12d279bbf211d039155e27d7566b374d49ee1f8189344bac9833dec7a20cdec370506361c938 + languageName: node + linkType: hard + +"call-bind@npm:^1.0.7, call-bind@npm:^1.0.8, call-bind@npm:^1.0.9": + version: 1.0.9 + resolution: "call-bind@npm:1.0.9" + dependencies: + call-bind-apply-helpers: "npm:^1.0.2" + es-define-property: "npm:^1.0.1" + get-intrinsic: "npm:^1.3.0" + set-function-length: "npm:^1.2.2" + checksum: 10c0/a6621f6da1444481919ce3b4983dff725691e0754d3507ae483ce56e54985f2da7d6f1df512c56dbf28660745cf1ca52553f1fc9aef5557f3ce353ef14fab714 + languageName: node + linkType: hard + +"call-bound@npm:^1.0.2, call-bound@npm:^1.0.3, call-bound@npm:^1.0.4": + version: 1.0.4 + resolution: "call-bound@npm:1.0.4" + dependencies: + call-bind-apply-helpers: "npm:^1.0.2" + get-intrinsic: "npm:^1.3.0" + checksum: 10c0/f4796a6a0941e71c766aea672f63b72bc61234c4f4964dc6d7606e3664c307e7d77845328a8f3359ce39ddb377fed67318f9ee203dea1d47e46165dcf2917644 + languageName: node + linkType: hard + +"callsites@npm:^3.0.0": + version: 3.1.0 + resolution: "callsites@npm:3.1.0" + checksum: 10c0/fff92277400eb06c3079f9e74f3af120db9f8ea03bad0e84d9aede54bbe2d44a56cccb5f6cf12211f93f52306df87077ecec5b712794c5a9b5dac6d615a3f301 + languageName: node + linkType: hard + +"caniuse-lite@npm:^1.0.30001782": + version: 1.0.30001799 + resolution: "caniuse-lite@npm:1.0.30001799" + checksum: 10c0/f24f9834edc7b60188f368ce44714695c3901bc4acb7f2a977dd9b7b697e39ddc0f9947fad6224a955b789f36a73432cb888d620aa7280d728f582d3bd8927a7 + languageName: node + linkType: hard + +"chownr@npm:^3.0.0": + version: 3.0.0 + resolution: "chownr@npm:3.0.0" + checksum: 10c0/43925b87700f7e3893296c8e9c56cc58f926411cce3a6e5898136daaf08f08b9a8eb76d37d3267e707d0dcc17aed2e2ebdf5848c0c3ce95cf910a919935c1b10 + languageName: node + linkType: hard + +"clsx@npm:^2.1.1": + version: 2.1.1 + resolution: "clsx@npm:2.1.1" + checksum: 10c0/c4c8eb865f8c82baab07e71bfa8897c73454881c4f99d6bc81585aecd7c441746c1399d08363dc096c550cceaf97bd4ce1e8854e1771e9998d9f94c4fe075839 + languageName: node + linkType: hard + +"combined-stream@npm:^1.0.8": + version: 1.0.8 + resolution: "combined-stream@npm:1.0.8" + dependencies: + delayed-stream: "npm:~1.0.0" + checksum: 10c0/0dbb829577e1b1e839fa82b40c07ffaf7de8a09b935cadd355a73652ae70a88b4320db322f6634a4ad93424292fa80973ac6480986247f1734a1137debf271d5 + languageName: node + linkType: hard + +"concat-map@npm:0.0.1": + version: 0.0.1 + resolution: "concat-map@npm:0.0.1" + checksum: 10c0/c996b1cfdf95b6c90fee4dae37e332c8b6eb7d106430c17d538034c0ad9a1630cb194d2ab37293b1bdd4d779494beee7786d586a50bd9376fd6f7bcc2bd4c98f + languageName: node + linkType: hard + +"convert-source-map@npm:^1.5.0": + version: 1.9.0 + resolution: "convert-source-map@npm:1.9.0" + checksum: 10c0/281da55454bf8126cbc6625385928c43479f2060984180c42f3a86c8b8c12720a24eac260624a7d1e090004028d2dee78602330578ceec1a08e27cb8bb0a8a5b + languageName: node + linkType: hard + +"convert-source-map@npm:^2.0.0": + version: 2.0.0 + resolution: "convert-source-map@npm:2.0.0" + checksum: 10c0/8f2f7a27a1a011cc6cc88cc4da2d7d0cfa5ee0369508baae3d98c260bb3ac520691464e5bbe4ae7cdf09860c1d69ecc6f70c63c6e7c7f7e3f18ec08484dc7d9b + languageName: node + linkType: hard + +"cosmiconfig@npm:^7.0.0": + version: 7.1.0 + resolution: "cosmiconfig@npm:7.1.0" + dependencies: + "@types/parse-json": "npm:^4.0.0" + import-fresh: "npm:^3.2.1" + parse-json: "npm:^5.0.0" + path-type: "npm:^4.0.0" + yaml: "npm:^1.10.0" + checksum: 10c0/b923ff6af581638128e5f074a5450ba12c0300b71302398ea38dbeabd33bbcaa0245ca9adbedfcf284a07da50f99ede5658c80bb3e39e2ce770a99d28a21ef03 + languageName: node + linkType: hard + +"cross-spawn@npm:^7.0.6": + version: 7.0.6 + resolution: "cross-spawn@npm:7.0.6" + dependencies: + path-key: "npm:^3.1.0" + shebang-command: "npm:^2.0.0" + which: "npm:^2.0.1" + checksum: 10c0/053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1 + languageName: node + linkType: hard + +"css-select@npm:^5.1.0": + version: 5.2.2 + resolution: "css-select@npm:5.2.2" + dependencies: + boolbase: "npm:^1.0.0" + css-what: "npm:^6.1.0" + domhandler: "npm:^5.0.2" + domutils: "npm:^3.0.1" + nth-check: "npm:^2.0.1" + checksum: 10c0/d79fffa97106007f2802589f3ed17b8c903f1c961c0fc28aa8a051eee0cbad394d8446223862efd4c1b40445a6034f626bb639cf2035b0bfc468544177593c99 + languageName: node + linkType: hard + +"css-what@npm:^6.1.0": + version: 6.2.2 + resolution: "css-what@npm:6.2.2" + checksum: 10c0/91e24c26fb977b4ccef30d7007d2668c1c10ac0154cc3f42f7304410e9594fb772aea4f30c832d2993b132ca8d99338050866476210316345ec2e7d47b248a56 + languageName: node + linkType: hard + +"csstype@npm:^3.0.2, csstype@npm:^3.2.3": + version: 3.2.3 + resolution: "csstype@npm:3.2.3" + checksum: 10c0/cd29c51e70fa822f1cecd8641a1445bed7063697469d35633b516e60fe8c1bde04b08f6c5b6022136bb669b64c63d4173af54864510fbb4ee23281801841a3ce + languageName: node + linkType: hard + +"data-view-buffer@npm:^1.0.2": + version: 1.0.2 + resolution: "data-view-buffer@npm:1.0.2" + dependencies: + call-bound: "npm:^1.0.3" + es-errors: "npm:^1.3.0" + is-data-view: "npm:^1.0.2" + checksum: 10c0/7986d40fc7979e9e6241f85db8d17060dd9a71bd53c894fa29d126061715e322a4cd47a00b0b8c710394854183d4120462b980b8554012acc1c0fa49df7ad38c + languageName: node + linkType: hard + +"data-view-byte-length@npm:^1.0.2": + version: 1.0.2 + resolution: "data-view-byte-length@npm:1.0.2" + dependencies: + call-bound: "npm:^1.0.3" + es-errors: "npm:^1.3.0" + is-data-view: "npm:^1.0.2" + checksum: 10c0/f8a4534b5c69384d95ac18137d381f18a5cfae1f0fc1df0ef6feef51ef0d568606d970b69e02ea186c6c0f0eac77fe4e6ad96fec2569cc86c3afcc7475068c55 + languageName: node + linkType: hard + +"data-view-byte-offset@npm:^1.0.1": + version: 1.0.1 + resolution: "data-view-byte-offset@npm:1.0.1" + dependencies: + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + is-data-view: "npm:^1.0.1" + checksum: 10c0/fa7aa40078025b7810dcffc16df02c480573b7b53ef1205aa6a61533011005c1890e5ba17018c692ce7c900212b547262d33279fde801ad9843edc0863bf78c4 + languageName: node + linkType: hard + +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.4.3": + version: 4.4.3 + resolution: "debug@npm:4.4.3" + dependencies: + ms: "npm:^2.1.3" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 10c0/d79136ec6c83ecbefd0f6a5593da6a9c91ec4d7ddc4b54c883d6e71ec9accb5f67a1a5e96d00a328196b5b5c86d365e98d8a3a70856aaf16b4e7b1985e67f5a6 + languageName: node + linkType: hard + +"deep-is@npm:^0.1.3": + version: 0.1.4 + resolution: "deep-is@npm:0.1.4" + checksum: 10c0/7f0ee496e0dff14a573dc6127f14c95061b448b87b995fc96c017ce0a1e66af1675e73f1d6064407975bc4ea6ab679497a29fff7b5b9c4e99cb10797c1ad0b4c + languageName: node + linkType: hard + +"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4": + version: 1.1.4 + resolution: "define-data-property@npm:1.1.4" + dependencies: + es-define-property: "npm:^1.0.0" + es-errors: "npm:^1.3.0" + gopd: "npm:^1.0.1" + checksum: 10c0/dea0606d1483eb9db8d930d4eac62ca0fa16738b0b3e07046cddfacf7d8c868bbe13fa0cb263eb91c7d0d527960dc3f2f2471a69ed7816210307f6744fe62e37 + languageName: node + linkType: hard + +"define-properties@npm:^1.1.3, define-properties@npm:^1.2.1": + version: 1.2.1 + resolution: "define-properties@npm:1.2.1" + dependencies: + define-data-property: "npm:^1.0.1" + has-property-descriptors: "npm:^1.0.0" + object-keys: "npm:^1.1.1" + checksum: 10c0/88a152319ffe1396ccc6ded510a3896e77efac7a1bfbaa174a7b00414a1747377e0bb525d303794a47cf30e805c2ec84e575758512c6e44a993076d29fd4e6c3 + languageName: node + linkType: hard + +"delayed-stream@npm:~1.0.0": + version: 1.0.0 + resolution: "delayed-stream@npm:1.0.0" + checksum: 10c0/d758899da03392e6712f042bec80aa293bbe9e9ff1b2634baae6a360113e708b91326594c8a486d475c69d6259afb7efacdc3537bfcda1c6c648e390ce601b19 + languageName: node + linkType: hard + +"doctrine@npm:^2.1.0": + version: 2.1.0 + resolution: "doctrine@npm:2.1.0" + dependencies: + esutils: "npm:^2.0.2" + checksum: 10c0/b6416aaff1f380bf56c3b552f31fdf7a69b45689368deca72d28636f41c16bb28ec3ebc40ace97db4c1afc0ceeb8120e8492fe0046841c94c2933b2e30a7d5ac + languageName: node + linkType: hard + +"dom-helpers@npm:^5.0.1": + version: 5.2.1 + resolution: "dom-helpers@npm:5.2.1" + dependencies: + "@babel/runtime": "npm:^7.8.7" + csstype: "npm:^3.0.2" + checksum: 10c0/f735074d66dd759b36b158fa26e9d00c9388ee0e8c9b16af941c38f014a37fc80782de83afefd621681b19ac0501034b4f1c4a3bff5caa1b8667f0212b5e124c + languageName: node + linkType: hard + +"dom-serializer@npm:^2.0.0": + version: 2.0.0 + resolution: "dom-serializer@npm:2.0.0" + dependencies: + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.2" + entities: "npm:^4.2.0" + checksum: 10c0/d5ae2b7110ca3746b3643d3ef60ef823f5f078667baf530cec096433f1627ec4b6fa8c072f09d079d7cda915fd2c7bc1b7b935681e9b09e591e1e15f4040b8e2 + languageName: node + linkType: hard + +"domelementtype@npm:^2.3.0": + version: 2.3.0 + resolution: "domelementtype@npm:2.3.0" + checksum: 10c0/686f5a9ef0fff078c1412c05db73a0dce096190036f33e400a07e2a4518e9f56b1e324f5c576a0a747ef0e75b5d985c040b0d51945ce780c0dd3c625a18cd8c9 + languageName: node + linkType: hard + +"domhandler@npm:^5.0.2, domhandler@npm:^5.0.3": + version: 5.0.3 + resolution: "domhandler@npm:5.0.3" + dependencies: + domelementtype: "npm:^2.3.0" + checksum: 10c0/bba1e5932b3e196ad6862286d76adc89a0dbf0c773e5ced1eb01f9af930c50093a084eff14b8de5ea60b895c56a04d5de8bbc4930c5543d029091916770b2d2a + languageName: node + linkType: hard + +"domutils@npm:^3.0.1": + version: 3.2.2 + resolution: "domutils@npm:3.2.2" + dependencies: + dom-serializer: "npm:^2.0.0" + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.3" + checksum: 10c0/47938f473b987ea71cd59e59626eb8666d3aa8feba5266e45527f3b636c7883cca7e582d901531961f742c519d7514636b7973353b648762b2e3bedbf235fada + languageName: node + linkType: hard + +"dunder-proto@npm:^1.0.0, dunder-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "dunder-proto@npm:1.0.1" + dependencies: + call-bind-apply-helpers: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + gopd: "npm:^1.2.0" + checksum: 10c0/199f2a0c1c16593ca0a145dbf76a962f8033ce3129f01284d48c45ed4e14fea9bbacd7b3610b6cdc33486cef20385ac054948fefc6272fcce645c09468f93031 + languageName: node + linkType: hard + +"electron-to-chromium@npm:^1.5.328": + version: 1.5.376 + resolution: "electron-to-chromium@npm:1.5.376" + checksum: 10c0/c57e306ef12ad258e427218f90e14d155dfba68b23699674d7b66e528ce41ff69b46a78f38545ee7690d080d25d3ebb98338282e95d65510e8fa5fd4f7455a86 + languageName: node + linkType: hard + +"empathic@npm:^2.0.1": + version: 2.0.1 + resolution: "empathic@npm:2.0.1" + checksum: 10c0/577f2868bfcad4ffbf911b57c75016125eb8cc8a7d32cf2d3e9fbcb31bfe6e9e6b66d9457ac34ccb2cd38bff353b3af34287899e0360b8c561ff6d4a048aca62 + languageName: node + linkType: hard + +"entities@npm:^4.2.0": + version: 4.5.0 + resolution: "entities@npm:4.5.0" + checksum: 10c0/5b039739f7621f5d1ad996715e53d964035f75ad3b9a4d38c6b3804bb226e282ffeae2443624d8fdd9c47d8e926ae9ac009c54671243f0c3294c26af7cc85250 + languageName: node + linkType: hard + +"env-paths@npm:^2.2.0": + version: 2.2.1 + resolution: "env-paths@npm:2.2.1" + checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 + languageName: node + linkType: hard + +"error-ex@npm:^1.3.1": + version: 1.3.4 + resolution: "error-ex@npm:1.3.4" + dependencies: + is-arrayish: "npm:^0.2.1" + checksum: 10c0/b9e34ff4778b8f3b31a8377e1c654456f4c41aeaa3d10a1138c3b7635d8b7b2e03eb2475d46d8ae055c1f180a1063e100bffabf64ea7e7388b37735df5328664 + languageName: node + linkType: hard + +"es-abstract-get@npm:^1.0.0": + version: 1.0.0 + resolution: "es-abstract-get@npm:1.0.0" + dependencies: + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.1.2" + is-callable: "npm:^1.2.7" + object-inspect: "npm:^1.13.4" + checksum: 10c0/f9b4838ae719752207383a6d95a74590f891122bf26b92f5e72eeedbe53771029e4561f1cf75ea19330b71bcf3d4f536fb0c8f7e2b601fe24d284f46e488c7e3 + languageName: node + linkType: hard + +"es-abstract@npm:^1.17.5, es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.3, es-abstract@npm:^1.23.5, es-abstract@npm:^1.23.6, es-abstract@npm:^1.23.9, es-abstract@npm:^1.24.0, es-abstract@npm:^1.24.2": + version: 1.24.2 + resolution: "es-abstract@npm:1.24.2" + dependencies: + array-buffer-byte-length: "npm:^1.0.2" + arraybuffer.prototype.slice: "npm:^1.0.4" + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.4" + data-view-buffer: "npm:^1.0.2" + data-view-byte-length: "npm:^1.0.2" + data-view-byte-offset: "npm:^1.0.1" + es-define-property: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.1.1" + es-set-tostringtag: "npm:^2.1.0" + es-to-primitive: "npm:^1.3.0" + function.prototype.name: "npm:^1.1.8" + get-intrinsic: "npm:^1.3.0" + get-proto: "npm:^1.0.1" + get-symbol-description: "npm:^1.1.0" + globalthis: "npm:^1.0.4" + gopd: "npm:^1.2.0" + has-property-descriptors: "npm:^1.0.2" + has-proto: "npm:^1.2.0" + has-symbols: "npm:^1.1.0" + hasown: "npm:^2.0.2" + internal-slot: "npm:^1.1.0" + is-array-buffer: "npm:^3.0.5" + is-callable: "npm:^1.2.7" + is-data-view: "npm:^1.0.2" + is-negative-zero: "npm:^2.0.3" + is-regex: "npm:^1.2.1" + is-set: "npm:^2.0.3" + is-shared-array-buffer: "npm:^1.0.4" + is-string: "npm:^1.1.1" + is-typed-array: "npm:^1.1.15" + is-weakref: "npm:^1.1.1" + math-intrinsics: "npm:^1.1.0" + object-inspect: "npm:^1.13.4" + object-keys: "npm:^1.1.1" + object.assign: "npm:^4.1.7" + own-keys: "npm:^1.0.1" + regexp.prototype.flags: "npm:^1.5.4" + safe-array-concat: "npm:^1.1.3" + safe-push-apply: "npm:^1.0.0" + safe-regex-test: "npm:^1.1.0" + set-proto: "npm:^1.0.0" + stop-iteration-iterator: "npm:^1.1.0" + string.prototype.trim: "npm:^1.2.10" + string.prototype.trimend: "npm:^1.0.9" + string.prototype.trimstart: "npm:^1.0.8" + typed-array-buffer: "npm:^1.0.3" + typed-array-byte-length: "npm:^1.0.3" + typed-array-byte-offset: "npm:^1.0.4" + typed-array-length: "npm:^1.0.7" + unbox-primitive: "npm:^1.1.0" + which-typed-array: "npm:^1.1.19" + checksum: 10c0/67a5bf21ef5c7d775e6f6131a836323900b4d87194cf544394ac68fe31c57fa53828b978af4a4f551ef307f83a2f910a16b6b982760ad3ddc3dc471f98d5fd1b + languageName: node + linkType: hard + +"es-define-property@npm:^1.0.0, es-define-property@npm:^1.0.1": + version: 1.0.1 + resolution: "es-define-property@npm:1.0.1" + checksum: 10c0/3f54eb49c16c18707949ff25a1456728c883e81259f045003499efba399c08bad00deebf65cccde8c0e07908c1a225c9d472b7107e558f2a48e28d530e34527c + languageName: node + linkType: hard + +"es-errors@npm:^1.3.0": + version: 1.3.0 + resolution: "es-errors@npm:1.3.0" + checksum: 10c0/0a61325670072f98d8ae3b914edab3559b6caa980f08054a3b872052640d91da01d38df55df797fcc916389d77fc92b8d5906cf028f4db46d7e3003abecbca85 + languageName: node + linkType: hard + +"es-iterator-helpers@npm:^1.2.1": + version: 1.3.3 + resolution: "es-iterator-helpers@npm:1.3.3" + dependencies: + call-bind: "npm:^1.0.9" + call-bound: "npm:^1.0.4" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.24.2" + es-errors: "npm:^1.3.0" + es-set-tostringtag: "npm:^2.1.0" + function-bind: "npm:^1.1.2" + get-intrinsic: "npm:^1.3.0" + globalthis: "npm:^1.0.4" + gopd: "npm:^1.2.0" + has-property-descriptors: "npm:^1.0.2" + has-proto: "npm:^1.2.0" + has-symbols: "npm:^1.1.0" + internal-slot: "npm:^1.1.0" + iterator.prototype: "npm:^1.1.5" + math-intrinsics: "npm:^1.1.0" + checksum: 10c0/14d45ce96c1eeec1dfb76607f4277163c847cc799a417c69346bfd2a9cce04b1d1426e34cb867dbc3266d2ca516084259ff1836cd2da6bc70b3e25e02f3532a9 + languageName: node + linkType: hard + +"es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1, es-object-atoms@npm:^1.1.2": + version: 1.1.2 + resolution: "es-object-atoms@npm:1.1.2" + dependencies: + es-errors: "npm:^1.3.0" + checksum: 10c0/1772861f094f739d6f41b579cfb9a18579daffeb434552a370a5fbef50a32d22227e27b63fdbb757b7ddd429d1b42fe52ccae7966d9302a2ec221b6f1b41bbc4 + languageName: node + linkType: hard + +"es-set-tostringtag@npm:^2.1.0": + version: 2.1.0 + resolution: "es-set-tostringtag@npm:2.1.0" + dependencies: + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.6" + has-tostringtag: "npm:^1.0.2" + hasown: "npm:^2.0.2" + checksum: 10c0/ef2ca9ce49afe3931cb32e35da4dcb6d86ab02592cfc2ce3e49ced199d9d0bb5085fc7e73e06312213765f5efa47cc1df553a6a5154584b21448e9fb8355b1af + languageName: node + linkType: hard + +"es-shim-unscopables@npm:^1.0.2": + version: 1.1.0 + resolution: "es-shim-unscopables@npm:1.1.0" + dependencies: + hasown: "npm:^2.0.2" + checksum: 10c0/1b9702c8a1823fc3ef39035a4e958802cf294dd21e917397c561d0b3e195f383b978359816b1732d02b255ccf63e1e4815da0065b95db8d7c992037be3bbbcdb + languageName: node + linkType: hard + +"es-to-primitive@npm:^1.3.0": + version: 1.3.1 + resolution: "es-to-primitive@npm:1.3.1" + dependencies: + es-abstract-get: "npm:^1.0.0" + es-errors: "npm:^1.3.0" + is-callable: "npm:^1.2.7" + is-date-object: "npm:^1.1.0" + is-symbol: "npm:^1.1.1" + checksum: 10c0/288ec25e5d08c2718bab9faa87924e11f42f2b0b59854fc241f1fbbedcadf2682ab3a9a9fb4676fa40c483ce563ea63cfd3e33777cbb53833e94d5f60a851cde + languageName: node + linkType: hard + +"esbuild@npm:^0.27.0": + version: 0.27.7 + resolution: "esbuild@npm:0.27.7" + dependencies: + "@esbuild/aix-ppc64": "npm:0.27.7" + "@esbuild/android-arm": "npm:0.27.7" + "@esbuild/android-arm64": "npm:0.27.7" + "@esbuild/android-x64": "npm:0.27.7" + "@esbuild/darwin-arm64": "npm:0.27.7" + "@esbuild/darwin-x64": "npm:0.27.7" + "@esbuild/freebsd-arm64": "npm:0.27.7" + "@esbuild/freebsd-x64": "npm:0.27.7" + "@esbuild/linux-arm": "npm:0.27.7" + "@esbuild/linux-arm64": "npm:0.27.7" + "@esbuild/linux-ia32": "npm:0.27.7" + "@esbuild/linux-loong64": "npm:0.27.7" + "@esbuild/linux-mips64el": "npm:0.27.7" + "@esbuild/linux-ppc64": "npm:0.27.7" + "@esbuild/linux-riscv64": "npm:0.27.7" + "@esbuild/linux-s390x": "npm:0.27.7" + "@esbuild/linux-x64": "npm:0.27.7" + "@esbuild/netbsd-arm64": "npm:0.27.7" + "@esbuild/netbsd-x64": "npm:0.27.7" + "@esbuild/openbsd-arm64": "npm:0.27.7" + "@esbuild/openbsd-x64": "npm:0.27.7" + "@esbuild/openharmony-arm64": "npm:0.27.7" + "@esbuild/sunos-x64": "npm:0.27.7" + "@esbuild/win32-arm64": "npm:0.27.7" + "@esbuild/win32-ia32": "npm:0.27.7" + "@esbuild/win32-x64": "npm:0.27.7" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-arm64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/openharmony-arm64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10c0/ccd51f0555708bc9ff4ec9dc3ac92d3daacd45ecaac949ca8645984c5c323bf8cefe98c2df307418685e0b4ce37f9a3bdbfe8e3651fe632a0059a436195a17d4 + languageName: node + linkType: hard + +"escalade@npm:^3.2.0": + version: 3.2.0 + resolution: "escalade@npm:3.2.0" + checksum: 10c0/ced4dd3a78e15897ed3be74e635110bbf3b08877b0a41be50dcb325ee0e0b5f65fc2d50e9845194d7c4633f327e2e1c6cce00a71b617c5673df0374201d67f65 + languageName: node + linkType: hard + +"escape-string-regexp@npm:^4.0.0": + version: 4.0.0 + resolution: "escape-string-regexp@npm:4.0.0" + checksum: 10c0/9497d4dd307d845bd7f75180d8188bb17ea8c151c1edbf6b6717c100e104d629dc2dfb687686181b0f4b7d732c7dfdc4d5e7a8ff72de1b0ca283a75bbb3a9cd9 + languageName: node + linkType: hard + +"eslint-config-preact@npm:^2.0.0": + version: 2.0.0 + resolution: "eslint-config-preact@npm:2.0.0" + dependencies: + "@babel/core": "npm:^7.13.16" + "@babel/eslint-parser": "npm:^7.27.5" + "@babel/plugin-syntax-class-properties": "npm:^7.12.13" + "@babel/plugin-syntax-jsx": "npm:^7.12.13" + "@eslint/js": "npm:^9.29.0" + eslint-plugin-compat: "npm:^6.0.2" + eslint-plugin-react: "npm:^7.37.5" + eslint-plugin-react-hooks: "npm:^5.2.0" + globals: "npm:^16.2.0" + peerDependencies: + eslint: ^8.57.1 || ^9.0.0 + checksum: 10c0/aebc4b09eb48d8b8b152d76cec56df59840397c497ea7bb0017d4855c94bb5b87fb211cc386acbddacade50011aa745169fff255893c3e8f23fde9981cb00012 + languageName: node + linkType: hard + +"eslint-plugin-compat@npm:^6.0.2": + version: 6.2.1 + resolution: "eslint-plugin-compat@npm:6.2.1" + dependencies: + "@mdn/browser-compat-data": "npm:^6.1.1" + ast-metadata-inferer: "npm:^0.8.1" + browserslist: "npm:^4.25.2" + find-up: "npm:^5.0.0" + globals: "npm:^15.7.0" + lodash.memoize: "npm:^4.1.2" + semver: "npm:^7.6.2" + peerDependencies: + eslint: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 + checksum: 10c0/08dc5ea7c46eed9cd2e656bfc32318fb2d3e5ba661bbd1b88633b316e5ab3ab898f7987353645f5b525c6b9ffa81d47b8c7d4f77b24fed9991c206b156d9a1ae + languageName: node + linkType: hard + +"eslint-plugin-react-hooks@npm:^5.2.0": + version: 5.2.0 + resolution: "eslint-plugin-react-hooks@npm:5.2.0" + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + checksum: 10c0/1c8d50fa5984c6dea32470651807d2922cc3934cf3425e78f84a24c2dfd972e7f019bee84aefb27e0cf2c13fea0ac1d4473267727408feeb1c56333ca1489385 + languageName: node + linkType: hard + +"eslint-plugin-react@npm:^7.37.5": + version: 7.37.5 + resolution: "eslint-plugin-react@npm:7.37.5" + dependencies: + array-includes: "npm:^3.1.8" + array.prototype.findlast: "npm:^1.2.5" + array.prototype.flatmap: "npm:^1.3.3" + array.prototype.tosorted: "npm:^1.1.4" + doctrine: "npm:^2.1.0" + es-iterator-helpers: "npm:^1.2.1" + estraverse: "npm:^5.3.0" + hasown: "npm:^2.0.2" + jsx-ast-utils: "npm:^2.4.1 || ^3.0.0" + minimatch: "npm:^3.1.2" + object.entries: "npm:^1.1.9" + object.fromentries: "npm:^2.0.8" + object.values: "npm:^1.2.1" + prop-types: "npm:^15.8.1" + resolve: "npm:^2.0.0-next.5" + semver: "npm:^6.3.1" + string.prototype.matchall: "npm:^4.0.12" + string.prototype.repeat: "npm:^1.0.0" + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + checksum: 10c0/c850bfd556291d4d9234f5ca38db1436924a1013627c8ab1853f77cac73ec19b020e861e6c7b783436a48b6ffcdfba4547598235a37ad4611b6739f65fd8ad57 + languageName: node + linkType: hard + +"eslint-scope@npm:5.1.1": + version: 5.1.1 + resolution: "eslint-scope@npm:5.1.1" + dependencies: + esrecurse: "npm:^4.3.0" + estraverse: "npm:^4.1.1" + checksum: 10c0/d30ef9dc1c1cbdece34db1539a4933fe3f9b14e1ffb27ecc85987902ee663ad7c9473bbd49a9a03195a373741e62e2f807c4938992e019b511993d163450e70a + languageName: node + linkType: hard + +"eslint-scope@npm:^9.1.2": + version: 9.1.2 + resolution: "eslint-scope@npm:9.1.2" + dependencies: + "@types/esrecurse": "npm:^4.3.1" + "@types/estree": "npm:^1.0.8" + esrecurse: "npm:^4.3.0" + estraverse: "npm:^5.2.0" + checksum: 10c0/9fb8bca5a73e5741efb6cec84467027b6cb6f4203ff9b43a938e272c5cd30800bde46a5c20dfd1609f840225f0b62b7673be391b20acadf8658ca9fa4729b3dd + languageName: node + linkType: hard + +"eslint-visitor-keys@npm:^2.1.0": + version: 2.1.0 + resolution: "eslint-visitor-keys@npm:2.1.0" + checksum: 10c0/9f0e3a2db751d84067d15977ac4b4472efd6b303e369e6ff241a99feac04da758f46d5add022c33d06b53596038dbae4b4aceb27c7e68b8dfc1055b35e495787 + languageName: node + linkType: hard + +"eslint-visitor-keys@npm:^3.4.3": + version: 3.4.3 + resolution: "eslint-visitor-keys@npm:3.4.3" + checksum: 10c0/92708e882c0a5ffd88c23c0b404ac1628cf20104a108c745f240a13c332a11aac54f49a22d5762efbffc18ecbc9a580d1b7ad034bf5f3cc3307e5cbff2ec9820 + languageName: node + linkType: hard + +"eslint-visitor-keys@npm:^5.0.1": + version: 5.0.1 + resolution: "eslint-visitor-keys@npm:5.0.1" + checksum: 10c0/16190bdf2cbae40a1109384c94450c526a79b0b9c3cb21e544256ed85ac48a4b84db66b74a6561d20fe6ab77447f150d711c2ad5ad74df4fcc133736bce99678 + languageName: node + linkType: hard + +"eslint@npm:^10.5.0": + version: 10.5.0 + resolution: "eslint@npm:10.5.0" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.8.0" + "@eslint-community/regexpp": "npm:^4.12.2" + "@eslint/config-array": "npm:^0.23.5" + "@eslint/config-helpers": "npm:^0.6.0" + "@eslint/core": "npm:^1.2.1" + "@eslint/plugin-kit": "npm:^0.7.2" + "@humanfs/node": "npm:^0.16.6" + "@humanwhocodes/module-importer": "npm:^1.0.1" + "@humanwhocodes/retry": "npm:^0.4.2" + "@types/estree": "npm:^1.0.6" + ajv: "npm:^6.14.0" + cross-spawn: "npm:^7.0.6" + debug: "npm:^4.3.2" + escape-string-regexp: "npm:^4.0.0" + eslint-scope: "npm:^9.1.2" + eslint-visitor-keys: "npm:^5.0.1" + espree: "npm:^11.2.0" + esquery: "npm:^1.7.0" + esutils: "npm:^2.0.2" + fast-deep-equal: "npm:^3.1.3" + file-entry-cache: "npm:^8.0.0" + find-up: "npm:^5.0.0" + glob-parent: "npm:^6.0.2" + ignore: "npm:^5.2.0" + imurmurhash: "npm:^0.1.4" + is-glob: "npm:^4.0.0" + json-stable-stringify-without-jsonify: "npm:^1.0.1" + minimatch: "npm:^10.2.4" + natural-compare: "npm:^1.4.0" + optionator: "npm:^0.9.3" + peerDependencies: + jiti: "*" + peerDependenciesMeta: + jiti: + optional: true + bin: + eslint: bin/eslint.js + checksum: 10c0/e1f7a1d442027e5478945cb07b6a382adc3f149fbfd3dbc14951a7a9fa312546b27fb35b0556897ca1d04539ad16ee85bda75ad9f724873e1153d1fbca0d6145 + languageName: node + linkType: hard + +"espree@npm:^11.2.0": + version: 11.2.0 + resolution: "espree@npm:11.2.0" + dependencies: + acorn: "npm:^8.16.0" + acorn-jsx: "npm:^5.3.2" + eslint-visitor-keys: "npm:^5.0.1" + checksum: 10c0/cf87e18ffd9dc113eb8d16588e7757701bc10c9934a71cce8b89c2611d51672681a918307bd6b19ac3ccd0e7ba1cbccc2f815b36b52fa7e73097b251014c3d81 + languageName: node + linkType: hard + +"esquery@npm:^1.7.0": + version: 1.7.0 + resolution: "esquery@npm:1.7.0" + dependencies: + estraverse: "npm:^5.1.0" + checksum: 10c0/77d5173db450b66f3bc685d11af4c90cffeedb340f34a39af96d43509a335ce39c894fd79233df32d38f5e4e219fa0f7076f6ec90bae8320170ba082c0db4793 + languageName: node + linkType: hard + +"esrecurse@npm:^4.3.0": + version: 4.3.0 + resolution: "esrecurse@npm:4.3.0" + dependencies: + estraverse: "npm:^5.2.0" + checksum: 10c0/81a37116d1408ded88ada45b9fb16dbd26fba3aadc369ce50fcaf82a0bac12772ebd7b24cd7b91fc66786bf2c1ac7b5f196bc990a473efff972f5cb338877cf5 + languageName: node + linkType: hard + +"estraverse@npm:^4.1.1": + version: 4.3.0 + resolution: "estraverse@npm:4.3.0" + checksum: 10c0/9cb46463ef8a8a4905d3708a652d60122a0c20bb58dec7e0e12ab0e7235123d74214fc0141d743c381813e1b992767e2708194f6f6e0f9fd00c1b4e0887b8b6d + languageName: node + linkType: hard + +"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0, estraverse@npm:^5.3.0": + version: 5.3.0 + resolution: "estraverse@npm:5.3.0" + checksum: 10c0/1ff9447b96263dec95d6d67431c5e0771eb9776427421260a3e2f0fdd5d6bd4f8e37a7338f5ad2880c9f143450c9b1e4fc2069060724570a49cf9cf0312bd107 + languageName: node + linkType: hard + +"estree-walker@npm:^2.0.1, estree-walker@npm:^2.0.2": + version: 2.0.2 + resolution: "estree-walker@npm:2.0.2" + checksum: 10c0/53a6c54e2019b8c914dc395890153ffdc2322781acf4bd7d1a32d7aedc1710807bdcd866ac133903d5629ec601fbb50abe8c2e5553c7f5a0afdd9b6af6c945af + languageName: node + linkType: hard + +"esutils@npm:^2.0.2": + version: 2.0.3 + resolution: "esutils@npm:2.0.3" + checksum: 10c0/9a2fe69a41bfdade834ba7c42de4723c97ec776e40656919c62cbd13607c45e127a003f05f724a1ea55e5029a4cf2de444b13009f2af71271e42d93a637137c7 + languageName: node + linkType: hard + +"exponential-backoff@npm:^3.1.1": + version: 3.1.3 + resolution: "exponential-backoff@npm:3.1.3" + checksum: 10c0/77e3ae682b7b1f4972f563c6dbcd2b0d54ac679e62d5d32f3e5085feba20483cf28bd505543f520e287a56d4d55a28d7874299941faf637e779a1aa5994d1267 + languageName: node + linkType: hard + +"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": + version: 3.1.3 + resolution: "fast-deep-equal@npm:3.1.3" + checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 + languageName: node + linkType: hard + +"fast-json-stable-stringify@npm:^2.0.0": + version: 2.1.0 + resolution: "fast-json-stable-stringify@npm:2.1.0" + checksum: 10c0/7f081eb0b8a64e0057b3bb03f974b3ef00135fbf36c1c710895cd9300f13c94ba809bb3a81cf4e1b03f6e5285610a61abbd7602d0652de423144dfee5a389c9b + languageName: node + linkType: hard + +"fast-levenshtein@npm:^2.0.6": + version: 2.0.6 + resolution: "fast-levenshtein@npm:2.0.6" + checksum: 10c0/111972b37338bcb88f7d9e2c5907862c280ebf4234433b95bc611e518d192ccb2d38119c4ac86e26b668d75f7f3894f4ff5c4982899afced7ca78633b08287c4 + languageName: node + linkType: hard + +"fdir@npm:^6.5.0": + version: 6.5.0 + resolution: "fdir@npm:6.5.0" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 10c0/e345083c4306b3aed6cb8ec551e26c36bab5c511e99ea4576a16750ddc8d3240e63826cc624f5ae17ad4dc82e68a253213b60d556c11bfad064b7607847ed07f + languageName: node + linkType: hard + +"file-entry-cache@npm:^8.0.0": + version: 8.0.0 + resolution: "file-entry-cache@npm:8.0.0" + dependencies: + flat-cache: "npm:^4.0.0" + checksum: 10c0/9e2b5938b1cd9b6d7e3612bdc533afd4ac17b2fc646569e9a8abbf2eb48e5eb8e316bc38815a3ef6a1b456f4107f0d0f055a614ca613e75db6bf9ff4d72c1638 + languageName: node + linkType: hard + +"find-root@npm:^1.1.0": + version: 1.1.0 + resolution: "find-root@npm:1.1.0" + checksum: 10c0/1abc7f3bf2f8d78ff26d9e00ce9d0f7b32e5ff6d1da2857bcdf4746134c422282b091c672cde0572cac3840713487e0a7a636af9aa1b74cb11894b447a521efa + languageName: node + linkType: hard + +"find-up@npm:^5.0.0": + version: 5.0.0 + resolution: "find-up@npm:5.0.0" + dependencies: + locate-path: "npm:^6.0.0" + path-exists: "npm:^4.0.0" + checksum: 10c0/062c5a83a9c02f53cdd6d175a37ecf8f87ea5bbff1fdfb828f04bfa021441bc7583e8ebc0872a4c1baab96221fb8a8a275a19809fb93fbc40bd69ec35634069a + languageName: node + linkType: hard + +"flat-cache@npm:^4.0.0": + version: 4.0.1 + resolution: "flat-cache@npm:4.0.1" + dependencies: + flatted: "npm:^3.2.9" + keyv: "npm:^4.5.4" + checksum: 10c0/2c59d93e9faa2523e4fda6b4ada749bed432cfa28c8e251f33b25795e426a1c6dbada777afb1f74fcfff33934fdbdea921ee738fcc33e71adc9d6eca984a1cfc + languageName: node + linkType: hard + +"flatted@npm:^3.2.9": + version: 3.4.2 + resolution: "flatted@npm:3.4.2" + checksum: 10c0/a65b67aae7172d6cdf63691be7de6c5cd5adbdfdfe2e9da1a09b617c9512ed794037741ee53d93114276bff3f93cd3b0d97d54f9b316e1e4885dde6e9ffdf7ed + languageName: node + linkType: hard + +"follow-redirects@npm:^1.16.0": + version: 1.16.0 + resolution: "follow-redirects@npm:1.16.0" + peerDependenciesMeta: + debug: + optional: true + checksum: 10c0/a1e2900163e6f1b4d1ed5c221b607f41decbab65534c63fe7e287e40a5d552a6496e7d9d7d976fa4ba77b4c51c11e5e9f683f10b43011ea11e442ff128d0e181 + languageName: node + linkType: hard + +"for-each@npm:^0.3.3, for-each@npm:^0.3.5": + version: 0.3.5 + resolution: "for-each@npm:0.3.5" + dependencies: + is-callable: "npm:^1.2.7" + checksum: 10c0/0e0b50f6a843a282637d43674d1fb278dda1dd85f4f99b640024cfb10b85058aac0cc781bf689d5fe50b4b7f638e91e548560723a4e76e04fe96ae35ef039cee + languageName: node + linkType: hard + +"form-data@npm:^4.0.5": + version: 4.0.6 + resolution: "form-data@npm:4.0.6" + dependencies: + asynckit: "npm:^0.4.0" + combined-stream: "npm:^1.0.8" + es-set-tostringtag: "npm:^2.1.0" + hasown: "npm:^2.0.4" + mime-types: "npm:^2.1.35" + checksum: 10c0/43947a77bf0ff45c6ceed789778982d47a3f3e720a74b71721174ebf3310a5f1a8be1d6b38a3ee3688e8a18a2c4273073ec0844cd37efda3eaf46d41c9c318ff + languageName: node + linkType: hard + +"fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": + version: 2.3.3 + resolution: "fsevents@npm:2.3.3" + dependencies: + node-gyp: "npm:latest" + checksum: 10c0/a1f0c44595123ed717febbc478aa952e47adfc28e2092be66b8ab1635147254ca6cfe1df792a8997f22716d4cbafc73309899ff7bfac2ac3ad8cf2e4ecc3ec60 + conditions: os=darwin + languageName: node + linkType: hard + +"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": + version: 2.3.3 + resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" + dependencies: + node-gyp: "npm:latest" + conditions: os=darwin + languageName: node + linkType: hard + +"function-bind@npm:^1.1.2": + version: 1.1.2 + resolution: "function-bind@npm:1.1.2" + checksum: 10c0/d8680ee1e5fcd4c197e4ac33b2b4dce03c71f4d91717292785703db200f5c21f977c568d28061226f9b5900cbcd2c84463646134fd5337e7925e0942bc3f46d5 + languageName: node + linkType: hard + +"function.prototype.name@npm:^1.1.6, function.prototype.name@npm:^1.1.8": + version: 1.2.0 + resolution: "function.prototype.name@npm:1.2.0" + dependencies: + call-bind: "npm:^1.0.9" + call-bound: "npm:^1.0.4" + es-define-property: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + functions-have-names: "npm:^1.2.3" + has-property-descriptors: "npm:^1.0.2" + hasown: "npm:^2.0.4" + is-callable: "npm:^1.2.7" + is-document.all: "npm:^1.0.0" + checksum: 10c0/b20e6370ef4f7d56d0bedf5719f6684a517a8dd3334209b4d9f51e8834859302a584187156bf024cda9f50ba2479e4d6764ac34af9532ea47d2f4d9fa6bcf90d + languageName: node + linkType: hard + +"functions-have-names@npm:^1.2.3": + version: 1.2.3 + resolution: "functions-have-names@npm:1.2.3" + checksum: 10c0/33e77fd29bddc2d9bb78ab3eb854c165909201f88c75faa8272e35899e2d35a8a642a15e7420ef945e1f64a9670d6aa3ec744106b2aa42be68ca5114025954ca + languageName: node + linkType: hard + +"generator-function@npm:^2.0.0": + version: 2.0.1 + resolution: "generator-function@npm:2.0.1" + checksum: 10c0/8a9f59df0f01cfefafdb3b451b80555e5cf6d76487095db91ac461a0e682e4ff7a9dbce15f4ecec191e53586d59eece01949e05a4b4492879600bbbe8e28d6b8 + languageName: node + linkType: hard + +"gensync@npm:^1.0.0-beta.2": + version: 1.0.0-beta.2 + resolution: "gensync@npm:1.0.0-beta.2" + checksum: 10c0/782aba6cba65b1bb5af3b095d96249d20edbe8df32dbf4696fd49be2583faf676173bf4809386588828e4dd76a3354fcbeb577bab1c833ccd9fc4577f26103f8 + languageName: node + linkType: hard + +"get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.2.7, get-intrinsic@npm:^1.3.0": + version: 1.3.0 + resolution: "get-intrinsic@npm:1.3.0" + dependencies: + call-bind-apply-helpers: "npm:^1.0.2" + es-define-property: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.1.1" + function-bind: "npm:^1.1.2" + get-proto: "npm:^1.0.1" + gopd: "npm:^1.2.0" + has-symbols: "npm:^1.1.0" + hasown: "npm:^2.0.2" + math-intrinsics: "npm:^1.1.0" + checksum: 10c0/52c81808af9a8130f581e6a6a83e1ba4a9f703359e7a438d1369a5267a25412322f03dcbd7c549edaef0b6214a0630a28511d7df0130c93cfd380f4fa0b5b66a + languageName: node + linkType: hard + +"get-proto@npm:^1.0.0, get-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "get-proto@npm:1.0.1" + dependencies: + dunder-proto: "npm:^1.0.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/9224acb44603c5526955e83510b9da41baf6ae73f7398875fba50edc5e944223a89c4a72b070fcd78beb5f7bdda58ecb6294adc28f7acfc0da05f76a2399643c + languageName: node + linkType: hard + +"get-symbol-description@npm:^1.1.0": + version: 1.1.0 + resolution: "get-symbol-description@npm:1.1.0" + dependencies: + call-bound: "npm:^1.0.3" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.6" + checksum: 10c0/d6a7d6afca375779a4b307738c9e80dbf7afc0bdbe5948768d54ab9653c865523d8920e670991a925936eb524b7cb6a6361d199a760b21d0ca7620194455aa4b + languageName: node + linkType: hard + +"glob-parent@npm:^6.0.2": + version: 6.0.2 + resolution: "glob-parent@npm:6.0.2" + dependencies: + is-glob: "npm:^4.0.3" + checksum: 10c0/317034d88654730230b3f43bb7ad4f7c90257a426e872ea0bf157473ac61c99bf5d205fad8f0185f989be8d2fa6d3c7dce1645d99d545b6ea9089c39f838e7f8 + languageName: node + linkType: hard + +"globals@npm:^15.7.0": + version: 15.15.0 + resolution: "globals@npm:15.15.0" + checksum: 10c0/f9ae80996392ca71316495a39bec88ac43ae3525a438b5626cd9d5ce9d5500d0a98a266409605f8cd7241c7acf57c354a48111ea02a767ba4f374b806d6861fe + languageName: node + linkType: hard + +"globals@npm:^16.2.0": + version: 16.5.0 + resolution: "globals@npm:16.5.0" + checksum: 10c0/615241dae7851c8012f5aa0223005b1ed6607713d6813de0741768bd4ddc39353117648f1a7086b4b0fa45eae733f1c0a0fe369aa4e543bb63f8de8990178ea9 + languageName: node + linkType: hard + +"globalthis@npm:^1.0.4": + version: 1.0.4 + resolution: "globalthis@npm:1.0.4" + dependencies: + define-properties: "npm:^1.2.1" + gopd: "npm:^1.0.1" + checksum: 10c0/9d156f313af79d80b1566b93e19285f481c591ad6d0d319b4be5e03750d004dde40a39a0f26f7e635f9007a3600802f53ecd85a759b86f109e80a5f705e01846 + languageName: node + linkType: hard + +"gopd@npm:^1.0.1, gopd@npm:^1.2.0": + version: 1.2.0 + resolution: "gopd@npm:1.2.0" + checksum: 10c0/50fff1e04ba2b7737c097358534eacadad1e68d24cccee3272e04e007bed008e68d2614f3987788428fd192a5ae3889d08fb2331417e4fc4a9ab366b2043cead + languageName: node + linkType: hard + +"graceful-fs@npm:^4.2.6": + version: 4.2.11 + resolution: "graceful-fs@npm:4.2.11" + checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 + languageName: node + linkType: hard + +"has-bigints@npm:^1.0.2": + version: 1.1.0 + resolution: "has-bigints@npm:1.1.0" + checksum: 10c0/2de0cdc4a1ccf7a1e75ffede1876994525ac03cc6f5ae7392d3415dd475cd9eee5bceec63669ab61aa997ff6cceebb50ef75561c7002bed8988de2b9d1b40788 + languageName: node + linkType: hard + +"has-property-descriptors@npm:^1.0.0, has-property-descriptors@npm:^1.0.2": + version: 1.0.2 + resolution: "has-property-descriptors@npm:1.0.2" + dependencies: + es-define-property: "npm:^1.0.0" + checksum: 10c0/253c1f59e80bb476cf0dde8ff5284505d90c3bdb762983c3514d36414290475fe3fd6f574929d84de2a8eec00d35cf07cb6776205ff32efd7c50719125f00236 + languageName: node + linkType: hard + +"has-proto@npm:^1.2.0": + version: 1.2.0 + resolution: "has-proto@npm:1.2.0" + dependencies: + dunder-proto: "npm:^1.0.0" + checksum: 10c0/46538dddab297ec2f43923c3d35237df45d8c55a6fc1067031e04c13ed8a9a8f94954460632fd4da84c31a1721eefee16d901cbb1ae9602bab93bb6e08f93b95 + languageName: node + linkType: hard + +"has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0": + version: 1.1.0 + resolution: "has-symbols@npm:1.1.0" + checksum: 10c0/dde0a734b17ae51e84b10986e651c664379018d10b91b6b0e9b293eddb32f0f069688c841fb40f19e9611546130153e0a2a48fd7f512891fb000ddfa36f5a20e + languageName: node + linkType: hard + +"has-tostringtag@npm:^1.0.2": + version: 1.0.2 + resolution: "has-tostringtag@npm:1.0.2" + dependencies: + has-symbols: "npm:^1.0.3" + checksum: 10c0/a8b166462192bafe3d9b6e420a1d581d93dd867adb61be223a17a8d6dad147aa77a8be32c961bb2f27b3ef893cae8d36f564ab651f5e9b7938ae86f74027c48c + languageName: node + linkType: hard + +"hasown@npm:^2.0.2, hasown@npm:^2.0.3, hasown@npm:^2.0.4": + version: 2.0.4 + resolution: "hasown@npm:2.0.4" + dependencies: + function-bind: "npm:^1.1.2" + checksum: 10c0/2d8de939e270b70618f8cebb69746620db10617dbb495bc66ddad326955ea24d3ca4af133aff3eb7c1853e0218f867bc2b050ec26fe02e3aea58f880ffc5e506 + languageName: node + linkType: hard + +"he@npm:1.2.0": + version: 1.2.0 + resolution: "he@npm:1.2.0" + bin: + he: bin/he + checksum: 10c0/a27d478befe3c8192f006cdd0639a66798979dfa6e2125c6ac582a19a5ebfec62ad83e8382e6036170d873f46e4536a7e795bf8b95bf7c247f4cc0825ccc8c17 + languageName: node + linkType: hard + +"hoist-non-react-statics@npm:^3.3.1": + version: 3.3.2 + resolution: "hoist-non-react-statics@npm:3.3.2" + dependencies: + react-is: "npm:^16.7.0" + checksum: 10c0/fe0889169e845d738b59b64badf5e55fa3cf20454f9203d1eb088df322d49d4318df774828e789898dcb280e8a5521bb59b3203385662ca5e9218a6ca5820e74 + languageName: node + linkType: hard + +"https-proxy-agent@npm:^5.0.1": + version: 5.0.1 + resolution: "https-proxy-agent@npm:5.0.1" + dependencies: + agent-base: "npm:6" + debug: "npm:4" + checksum: 10c0/6dd639f03434003577c62b27cafdb864784ef19b2de430d8ae2a1d45e31c4fd60719e5637b44db1a88a046934307da7089e03d6089ec3ddacc1189d8de8897d1 + languageName: node + linkType: hard + +"ignore@npm:^5.2.0": + version: 5.3.2 + resolution: "ignore@npm:5.3.2" + checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337 + languageName: node + linkType: hard + +"import-fresh@npm:^3.2.1": + version: 3.3.1 + resolution: "import-fresh@npm:3.3.1" + dependencies: + parent-module: "npm:^1.0.0" + resolve-from: "npm:^4.0.0" + checksum: 10c0/bf8cc494872fef783249709385ae883b447e3eb09db0ebd15dcead7d9afe7224dad7bd7591c6b73b0b19b3c0f9640eb8ee884f01cfaf2887ab995b0b36a0cbec + languageName: node + linkType: hard + +"import-meta-resolve@npm:^4.2.0": + version: 4.2.0 + resolution: "import-meta-resolve@npm:4.2.0" + checksum: 10c0/3ee8aeecb61d19b49d2703987f977e9d1c7d4ba47db615a570eaa02fe414f40dfa63f7b953e842cbe8470d26df6371332bfcf21b2fd92b0112f9fea80dde2c4c + languageName: node + linkType: hard + +"imurmurhash@npm:^0.1.4": + version: 0.1.4 + resolution: "imurmurhash@npm:0.1.4" + checksum: 10c0/8b51313850dd33605c6c9d3fd9638b714f4c4c40250cff658209f30d40da60f78992fb2df5dabee4acf589a6a82bbc79ad5486550754bd9ec4e3fc0d4a57d6a6 + languageName: node + linkType: hard + +"internal-slot@npm:^1.1.0": + version: 1.1.0 + resolution: "internal-slot@npm:1.1.0" + dependencies: + es-errors: "npm:^1.3.0" + hasown: "npm:^2.0.2" + side-channel: "npm:^1.1.0" + checksum: 10c0/03966f5e259b009a9bf1a78d60da920df198af4318ec004f57b8aef1dd3fe377fbc8cce63a96e8c810010302654de89f9e19de1cd8ad0061d15be28a695465c7 + languageName: node + linkType: hard + +"is-array-buffer@npm:^3.0.4, is-array-buffer@npm:^3.0.5": + version: 3.0.5 + resolution: "is-array-buffer@npm:3.0.5" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.3" + get-intrinsic: "npm:^1.2.6" + checksum: 10c0/c5c9f25606e86dbb12e756694afbbff64bc8b348d1bc989324c037e1068695131930199d6ad381952715dad3a9569333817f0b1a72ce5af7f883ce802e49c83d + languageName: node + linkType: hard + +"is-arrayish@npm:^0.2.1": + version: 0.2.1 + resolution: "is-arrayish@npm:0.2.1" + checksum: 10c0/e7fb686a739068bb70f860b39b67afc62acc62e36bb61c5f965768abce1873b379c563e61dd2adad96ebb7edf6651111b385e490cf508378959b0ed4cac4e729 + languageName: node + linkType: hard + +"is-async-function@npm:^2.0.0": + version: 2.1.1 + resolution: "is-async-function@npm:2.1.1" + dependencies: + async-function: "npm:^1.0.0" + call-bound: "npm:^1.0.3" + get-proto: "npm:^1.0.1" + has-tostringtag: "npm:^1.0.2" + safe-regex-test: "npm:^1.1.0" + checksum: 10c0/d70c236a5e82de6fc4d44368ffd0c2fee2b088b893511ce21e679da275a5ecc6015ff59a7d7e1bdd7ca39f71a8dbdd253cf8cce5c6b3c91cdd5b42b5ce677298 + languageName: node + linkType: hard + +"is-bigint@npm:^1.1.0": + version: 1.1.0 + resolution: "is-bigint@npm:1.1.0" + dependencies: + has-bigints: "npm:^1.0.2" + checksum: 10c0/f4f4b905ceb195be90a6ea7f34323bf1c18e3793f18922e3e9a73c684c29eeeeff5175605c3a3a74cc38185fe27758f07efba3dbae812e5c5afbc0d2316b40e4 + languageName: node + linkType: hard + +"is-boolean-object@npm:^1.2.1": + version: 1.2.2 + resolution: "is-boolean-object@npm:1.2.2" + dependencies: + call-bound: "npm:^1.0.3" + has-tostringtag: "npm:^1.0.2" + checksum: 10c0/36ff6baf6bd18b3130186990026f5a95c709345c39cd368468e6c1b6ab52201e9fd26d8e1f4c066357b4938b0f0401e1a5000e08257787c1a02f3a719457001e + languageName: node + linkType: hard + +"is-callable@npm:^1.2.7": + version: 1.2.7 + resolution: "is-callable@npm:1.2.7" + checksum: 10c0/ceebaeb9d92e8adee604076971dd6000d38d6afc40bb843ea8e45c5579b57671c3f3b50d7f04869618242c6cee08d1b67806a8cb8edaaaf7c0748b3720d6066f + languageName: node + linkType: hard + +"is-core-module@npm:^2.16.1, is-core-module@npm:^2.16.2": + version: 2.16.2 + resolution: "is-core-module@npm:2.16.2" + dependencies: + hasown: "npm:^2.0.3" + checksum: 10c0/14b4258390283709c15476d023ec173e27458d5d014ccdb8ed39d576e551c3fa45498b7c9fe178f1529c4cb2648ddd58852a6a62107a019f6e349529f277518a + languageName: node + linkType: hard + +"is-data-view@npm:^1.0.1, is-data-view@npm:^1.0.2": + version: 1.0.2 + resolution: "is-data-view@npm:1.0.2" + dependencies: + call-bound: "npm:^1.0.2" + get-intrinsic: "npm:^1.2.6" + is-typed-array: "npm:^1.1.13" + checksum: 10c0/ef3548a99d7e7f1370ce21006baca6d40c73e9f15c941f89f0049c79714c873d03b02dae1c64b3f861f55163ecc16da06506c5b8a1d4f16650b3d9351c380153 + languageName: node + linkType: hard + +"is-date-object@npm:^1.1.0": + version: 1.1.0 + resolution: "is-date-object@npm:1.1.0" + dependencies: + call-bound: "npm:^1.0.2" + has-tostringtag: "npm:^1.0.2" + checksum: 10c0/1a4d199c8e9e9cac5128d32e6626fa7805175af9df015620ac0d5d45854ccf348ba494679d872d37301032e35a54fc7978fba1687e8721b2139aea7870cafa2f + languageName: node + linkType: hard + +"is-document.all@npm:^1.0.0": + version: 1.0.0 + resolution: "is-document.all@npm:1.0.0" + dependencies: + call-bound: "npm:^1.0.4" + checksum: 10c0/955c20ed5bf01d49da8243b4c714947a6ff64b6d9ba0e12bdbfa654a3e7c47f72cc01c6cd2905e85512d02bc3a1290edd73857bca8842566ff9dcfb7c3f92dae + languageName: node + linkType: hard + +"is-extglob@npm:^2.1.1": + version: 2.1.1 + resolution: "is-extglob@npm:2.1.1" + checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912 + languageName: node + linkType: hard + +"is-finalizationregistry@npm:^1.1.0": + version: 1.1.1 + resolution: "is-finalizationregistry@npm:1.1.1" + dependencies: + call-bound: "npm:^1.0.3" + checksum: 10c0/818dff679b64f19e228a8205a1e2d09989a98e98def3a817f889208cfcbf918d321b251aadf2c05918194803ebd2eb01b14fc9d0b2bea53d984f4137bfca5e97 + languageName: node + linkType: hard + +"is-generator-function@npm:^1.0.10": + version: 1.1.2 + resolution: "is-generator-function@npm:1.1.2" + dependencies: + call-bound: "npm:^1.0.4" + generator-function: "npm:^2.0.0" + get-proto: "npm:^1.0.1" + has-tostringtag: "npm:^1.0.2" + safe-regex-test: "npm:^1.1.0" + checksum: 10c0/83da102e89c3e3b71d67b51d47c9f9bc862bceb58f87201727e27f7fa19d1d90b0ab223644ecaee6fc6e3d2d622bb25c966fbdaf87c59158b01ce7c0fe2fa372 + languageName: node + linkType: hard + +"is-glob@npm:^4.0.0, is-glob@npm:^4.0.3": + version: 4.0.3 + resolution: "is-glob@npm:4.0.3" + dependencies: + is-extglob: "npm:^2.1.1" + checksum: 10c0/17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a + languageName: node + linkType: hard + +"is-map@npm:^2.0.3": + version: 2.0.3 + resolution: "is-map@npm:2.0.3" + checksum: 10c0/2c4d431b74e00fdda7162cd8e4b763d6f6f217edf97d4f8538b94b8702b150610e2c64961340015fe8df5b1fcee33ccd2e9b62619c4a8a3a155f8de6d6d355fc + languageName: node + linkType: hard + +"is-negative-zero@npm:^2.0.3": + version: 2.0.3 + resolution: "is-negative-zero@npm:2.0.3" + checksum: 10c0/bcdcf6b8b9714063ffcfa9929c575ac69bfdabb8f4574ff557dfc086df2836cf07e3906f5bbc4f2a5c12f8f3ba56af640c843cdfc74da8caed86c7c7d66fd08e + languageName: node + linkType: hard + +"is-number-object@npm:^1.1.1": + version: 1.1.1 + resolution: "is-number-object@npm:1.1.1" + dependencies: + call-bound: "npm:^1.0.3" + has-tostringtag: "npm:^1.0.2" + checksum: 10c0/97b451b41f25135ff021d85c436ff0100d84a039bb87ffd799cbcdbea81ef30c464ced38258cdd34f080be08fc3b076ca1f472086286d2aa43521d6ec6a79f53 + languageName: node + linkType: hard + +"is-regex@npm:^1.2.1": + version: 1.2.1 + resolution: "is-regex@npm:1.2.1" + dependencies: + call-bound: "npm:^1.0.2" + gopd: "npm:^1.2.0" + has-tostringtag: "npm:^1.0.2" + hasown: "npm:^2.0.2" + checksum: 10c0/1d3715d2b7889932349241680032e85d0b492cfcb045acb75ffc2c3085e8d561184f1f7e84b6f8321935b4aea39bc9c6ba74ed595b57ce4881a51dfdbc214e04 + languageName: node + linkType: hard + +"is-set@npm:^2.0.3": + version: 2.0.3 + resolution: "is-set@npm:2.0.3" + checksum: 10c0/f73732e13f099b2dc879c2a12341cfc22ccaca8dd504e6edae26484bd5707a35d503fba5b4daad530a9b088ced1ae6c9d8200fd92e09b428fe14ea79ce8080b7 + languageName: node + linkType: hard + +"is-shared-array-buffer@npm:^1.0.4": + version: 1.0.4 + resolution: "is-shared-array-buffer@npm:1.0.4" + dependencies: + call-bound: "npm:^1.0.3" + checksum: 10c0/65158c2feb41ff1edd6bbd6fd8403a69861cf273ff36077982b5d4d68e1d59278c71691216a4a64632bd76d4792d4d1d2553901b6666d84ade13bba5ea7bc7db + languageName: node + linkType: hard + +"is-string@npm:^1.1.1": + version: 1.1.1 + resolution: "is-string@npm:1.1.1" + dependencies: + call-bound: "npm:^1.0.3" + has-tostringtag: "npm:^1.0.2" + checksum: 10c0/2f518b4e47886bb81567faba6ffd0d8a8333cf84336e2e78bf160693972e32ad00fe84b0926491cc598dee576fdc55642c92e62d0cbe96bf36f643b6f956f94d + languageName: node + linkType: hard + +"is-symbol@npm:^1.1.1": + version: 1.1.1 + resolution: "is-symbol@npm:1.1.1" + dependencies: + call-bound: "npm:^1.0.2" + has-symbols: "npm:^1.1.0" + safe-regex-test: "npm:^1.1.0" + checksum: 10c0/f08f3e255c12442e833f75a9e2b84b2d4882fdfd920513cf2a4a2324f0a5b076c8fd913778e3ea5d258d5183e9d92c0cd20e04b03ab3df05316b049b2670af1e + languageName: node + linkType: hard + +"is-typed-array@npm:^1.1.13, is-typed-array@npm:^1.1.14, is-typed-array@npm:^1.1.15": + version: 1.1.15 + resolution: "is-typed-array@npm:1.1.15" + dependencies: + which-typed-array: "npm:^1.1.16" + checksum: 10c0/415511da3669e36e002820584e264997ffe277ff136643a3126cc949197e6ca3334d0f12d084e83b1994af2e9c8141275c741cf2b7da5a2ff62dd0cac26f76c4 + languageName: node + linkType: hard + +"is-weakmap@npm:^2.0.2": + version: 2.0.2 + resolution: "is-weakmap@npm:2.0.2" + checksum: 10c0/443c35bb86d5e6cc5929cd9c75a4024bb0fff9586ed50b092f94e700b89c43a33b186b76dbc6d54f3d3d09ece689ab38dcdc1af6a482cbe79c0f2da0a17f1299 + languageName: node + linkType: hard + +"is-weakref@npm:^1.0.2, is-weakref@npm:^1.1.1": + version: 1.1.1 + resolution: "is-weakref@npm:1.1.1" + dependencies: + call-bound: "npm:^1.0.3" + checksum: 10c0/8e0a9c07b0c780949a100e2cab2b5560a48ecd4c61726923c1a9b77b6ab0aa0046c9e7fb2206042296817045376dee2c8ab1dabe08c7c3dfbf195b01275a085b + languageName: node + linkType: hard + +"is-weakset@npm:^2.0.3": + version: 2.0.4 + resolution: "is-weakset@npm:2.0.4" + dependencies: + call-bound: "npm:^1.0.3" + get-intrinsic: "npm:^1.2.6" + checksum: 10c0/6491eba08acb8dc9532da23cb226b7d0192ede0b88f16199e592e4769db0a077119c1f5d2283d1e0d16d739115f70046e887e477eb0e66cd90e1bb29f28ba647 + languageName: node + linkType: hard + +"isarray@npm:^2.0.5": + version: 2.0.5 + resolution: "isarray@npm:2.0.5" + checksum: 10c0/4199f14a7a13da2177c66c31080008b7124331956f47bca57dd0b6ea9f11687aa25e565a2c7a2b519bc86988d10398e3049a1f5df13c9f6b7664154690ae79fd + languageName: node + linkType: hard + +"isexe@npm:^2.0.0": + version: 2.0.0 + resolution: "isexe@npm:2.0.0" + checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d + languageName: node + linkType: hard + +"isexe@npm:^4.0.0": + version: 4.0.0 + resolution: "isexe@npm:4.0.0" + checksum: 10c0/5884815115bceac452877659a9c7726382531592f43dc29e5d48b7c4100661aed54018cb90bd36cb2eaeba521092570769167acbb95c18d39afdccbcca06c5ce + languageName: node + linkType: hard + +"iterator.prototype@npm:^1.1.5": + version: 1.1.5 + resolution: "iterator.prototype@npm:1.1.5" + dependencies: + define-data-property: "npm:^1.1.4" + es-object-atoms: "npm:^1.0.0" + get-intrinsic: "npm:^1.2.6" + get-proto: "npm:^1.0.0" + has-symbols: "npm:^1.1.0" + set-function-name: "npm:^2.0.2" + checksum: 10c0/f7a262808e1b41049ab55f1e9c29af7ec1025a000d243b83edf34ce2416eedd56079b117fa59376bb4a724110690f13aa8427f2ee29a09eec63a7e72367626d0 + languageName: node + linkType: hard + +"js-tokens@npm:^10.0.0": + version: 10.0.0 + resolution: "js-tokens@npm:10.0.0" + checksum: 10c0/a93498747812ba3e0c8626f95f75ab29319f2a13613a0de9e610700405760931624433a0de59eb7c27ff8836e526768fb20783861b86ef89be96676f2c996b64 + languageName: node + linkType: hard + +"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": + version: 4.0.0 + resolution: "js-tokens@npm:4.0.0" + checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed + languageName: node + linkType: hard + +"jsesc@npm:^3.0.2": + version: 3.1.0 + resolution: "jsesc@npm:3.1.0" + bin: + jsesc: bin/jsesc + checksum: 10c0/531779df5ec94f47e462da26b4cbf05eb88a83d9f08aac2ba04206508fc598527a153d08bd462bae82fc78b3eaa1a908e1a4a79f886e9238641c4cdefaf118b1 + languageName: node + linkType: hard + +"json-buffer@npm:3.0.1": + version: 3.0.1 + resolution: "json-buffer@npm:3.0.1" + checksum: 10c0/0d1c91569d9588e7eef2b49b59851f297f3ab93c7b35c7c221e288099322be6b562767d11e4821da500f3219542b9afd2e54c5dc573107c1126ed1080f8e96d7 + languageName: node + linkType: hard + +"json-parse-even-better-errors@npm:^2.3.0": + version: 2.3.1 + resolution: "json-parse-even-better-errors@npm:2.3.1" + checksum: 10c0/140932564c8f0b88455432e0f33c4cb4086b8868e37524e07e723f4eaedb9425bdc2bafd71bd1d9765bd15fd1e2d126972bc83990f55c467168c228c24d665f3 + languageName: node + linkType: hard + +"json-schema-traverse@npm:^0.4.1": + version: 0.4.1 + resolution: "json-schema-traverse@npm:0.4.1" + checksum: 10c0/108fa90d4cc6f08243aedc6da16c408daf81793bf903e9fd5ab21983cda433d5d2da49e40711da016289465ec2e62e0324dcdfbc06275a607fe3233fde4942ce + languageName: node + linkType: hard + +"json-stable-stringify-without-jsonify@npm:^1.0.1": + version: 1.0.1 + resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" + checksum: 10c0/cb168b61fd4de83e58d09aaa6425ef71001bae30d260e2c57e7d09a5fd82223e2f22a042dedaab8db23b7d9ae46854b08bb1f91675a8be11c5cffebef5fb66a5 + languageName: node + linkType: hard + +"json5@npm:^2.2.3": + version: 2.2.3 + resolution: "json5@npm:2.2.3" + bin: + json5: lib/cli.js + checksum: 10c0/5a04eed94810fa55c5ea138b2f7a5c12b97c3750bc63d11e511dcecbfef758003861522a070c2272764ee0f4e3e323862f386945aeb5b85b87ee43f084ba586c + languageName: node + linkType: hard + +"jsx-ast-utils@npm:^2.4.1 || ^3.0.0": + version: 3.3.5 + resolution: "jsx-ast-utils@npm:3.3.5" + dependencies: + array-includes: "npm:^3.1.6" + array.prototype.flat: "npm:^1.3.1" + object.assign: "npm:^4.1.4" + object.values: "npm:^1.1.6" + checksum: 10c0/a32679e9cb55469cb6d8bbc863f7d631b2c98b7fc7bf172629261751a6e7bc8da6ae374ddb74d5fbd8b06cf0eb4572287b259813d92b36e384024ed35e4c13e1 + languageName: node + linkType: hard + +"keyv@npm:^4.5.4": + version: 4.5.4 + resolution: "keyv@npm:4.5.4" + dependencies: + json-buffer: "npm:3.0.1" + checksum: 10c0/aa52f3c5e18e16bb6324876bb8b59dd02acf782a4b789c7b2ae21107fab95fab3890ed448d4f8dba80ce05391eeac4bfabb4f02a20221342982f806fa2cf271e + languageName: node + linkType: hard + +"kolorist@npm:^1.6.0, kolorist@npm:^1.8.0": + version: 1.8.0 + resolution: "kolorist@npm:1.8.0" + checksum: 10c0/73075db44a692bf6c34a649f3b4b3aea4993b84f6b754cbf7a8577e7c7db44c0bad87752bd23b0ce533f49de2244ce2ce03b7b1b667a85ae170a94782cc50f9b + languageName: node + linkType: hard + +"levn@npm:^0.4.1": + version: 0.4.1 + resolution: "levn@npm:0.4.1" + dependencies: + prelude-ls: "npm:^1.2.1" + type-check: "npm:~0.4.0" + checksum: 10c0/effb03cad7c89dfa5bd4f6989364bfc79994c2042ec5966cb9b95990e2edee5cd8969ddf42616a0373ac49fac1403437deaf6e9050fbbaa3546093a59b9ac94e + languageName: node + linkType: hard + +"lines-and-columns@npm:^1.1.6": + version: 1.2.4 + resolution: "lines-and-columns@npm:1.2.4" + checksum: 10c0/3da6ee62d4cd9f03f5dc90b4df2540fb85b352081bee77fe4bbcd12c9000ead7f35e0a38b8d09a9bb99b13223446dd8689ff3c4959807620726d788701a83d2d + languageName: node + linkType: hard + +"locate-path@npm:^6.0.0": + version: 6.0.0 + resolution: "locate-path@npm:6.0.0" + dependencies: + p-locate: "npm:^5.0.0" + checksum: 10c0/d3972ab70dfe58ce620e64265f90162d247e87159b6126b01314dd67be43d50e96a50b517bce2d9452a79409c7614054c277b5232377de50416564a77ac7aad3 + languageName: node + linkType: hard + +"lodash.memoize@npm:^4.1.2": + version: 4.1.2 + resolution: "lodash.memoize@npm:4.1.2" + checksum: 10c0/c8713e51eccc650422716a14cece1809cfe34bc5ab5e242b7f8b4e2241c2483697b971a604252807689b9dd69bfe3a98852e19a5b89d506b000b4187a1285df8 + languageName: node + linkType: hard + +"loose-envify@npm:^1.4.0": + version: 1.4.0 + resolution: "loose-envify@npm:1.4.0" + dependencies: + js-tokens: "npm:^3.0.0 || ^4.0.0" + bin: + loose-envify: cli.js + checksum: 10c0/655d110220983c1a4b9c0c679a2e8016d4b67f6e9c7b5435ff5979ecdb20d0813f4dec0a08674fcbdd4846a3f07edbb50a36811fd37930b94aaa0d9daceb017e + languageName: node + linkType: hard + +"lru-cache@npm:^11.0.0": + version: 11.5.1 + resolution: "lru-cache@npm:11.5.1" + checksum: 10c0/7b341cea79a8efe9c6a6f20c8757a77eca5b25d7ff983ccf4e11e547b81f6787824baa1c84705251dff84ab4ffac85717ac354b9d02e465f86a9f8b166409979 + languageName: node + linkType: hard + +"lru-cache@npm:^5.1.1": + version: 5.1.1 + resolution: "lru-cache@npm:5.1.1" + dependencies: + yallist: "npm:^3.0.2" + checksum: 10c0/89b2ef2ef45f543011e38737b8a8622a2f8998cddf0e5437174ef8f1f70a8b9d14a918ab3e232cb3ba343b7abddffa667f0b59075b2b80e6b4d63c3de6127482 + languageName: node + linkType: hard + +"magic-string@npm:0.x >= 0.26.0, magic-string@npm:^0.30.21": + version: 0.30.21 + resolution: "magic-string@npm:0.30.21" + dependencies: + "@jridgewell/sourcemap-codec": "npm:^1.5.5" + checksum: 10c0/299378e38f9a270069fc62358522ddfb44e94244baa0d6a8980ab2a9b2490a1d03b236b447eee309e17eb3bddfa482c61259d47960eb018a904f0ded52780c4a + languageName: node + linkType: hard + +"math-intrinsics@npm:^1.1.0": + version: 1.1.0 + resolution: "math-intrinsics@npm:1.1.0" + checksum: 10c0/7579ff94e899e2f76ab64491d76cf606274c874d8f2af4a442c016bd85688927fcfca157ba6bf74b08e9439dc010b248ce05b96cc7c126a354c3bae7fcb48b7f + languageName: node + linkType: hard + +"mime-db@npm:1.52.0": + version: 1.52.0 + resolution: "mime-db@npm:1.52.0" + checksum: 10c0/0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa + languageName: node + linkType: hard + +"mime-types@npm:^2.1.35": + version: 2.1.35 + resolution: "mime-types@npm:2.1.35" + dependencies: + mime-db: "npm:1.52.0" + checksum: 10c0/82fb07ec56d8ff1fc999a84f2f217aa46cb6ed1033fefaabd5785b9a974ed225c90dc72fff460259e66b95b73648596dbcc50d51ed69cdf464af2d237d3149b2 + languageName: node + linkType: hard + +"minimatch@npm:^10.2.4": + version: 10.2.5 + resolution: "minimatch@npm:10.2.5" + dependencies: + brace-expansion: "npm:^5.0.5" + checksum: 10c0/6bb058bd6324104b9ec2f763476a35386d05079c1f5fe4fbf1f324a25237cd4534d6813ecd71f48208f4e635c1221899bef94c3c89f7df55698fe373aaae20fd + languageName: node + linkType: hard + +"minimatch@npm:^3.1.2": + version: 3.1.5 + resolution: "minimatch@npm:3.1.5" + dependencies: + brace-expansion: "npm:^1.1.7" + checksum: 10c0/2ecbdc0d33f07bddb0315a8b5afbcb761307a8778b48f0b312418ccbced99f104a2d17d8aca7573433c70e8ccd1c56823a441897a45e384ea76ef401a26ace70 + languageName: node + linkType: hard + +"minipass@npm:^7.0.4, minipass@npm:^7.1.2": + version: 7.1.3 + resolution: "minipass@npm:7.1.3" + checksum: 10c0/539da88daca16533211ea5a9ee98dc62ff5742f531f54640dd34429e621955e91cc280a91a776026264b7f9f6735947629f920944e9c1558369e8bf22eb33fbb + languageName: node + linkType: hard + +"minizlib@npm:^3.1.0": + version: 3.1.0 + resolution: "minizlib@npm:3.1.0" + dependencies: + minipass: "npm:^7.1.2" + checksum: 10c0/5aad75ab0090b8266069c9aabe582c021ae53eb33c6c691054a13a45db3b4f91a7fb1bd79151e6b4e9e9a86727b522527c0a06ec7d45206b745d54cd3097bcec + languageName: node + linkType: hard + +"ms@npm:^2.1.3": + version: 2.1.3 + resolution: "ms@npm:2.1.3" + checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 + languageName: node + linkType: hard + +"nanoid@npm:^3.3.12": + version: 3.3.13 + resolution: "nanoid@npm:3.3.13" + bin: + nanoid: bin/nanoid.cjs + checksum: 10c0/e913cd6d081e3b646788aa36e686964f2746f15935759425c98344053676b9444efedff4d87915bfb38b1626057e66c788f59ee7746b48c2b7886a4b049ca2ac + languageName: node + linkType: hard + +"natural-compare@npm:^1.4.0": + version: 1.4.0 + resolution: "natural-compare@npm:1.4.0" + checksum: 10c0/f5f9a7974bfb28a91afafa254b197f0f22c684d4a1731763dda960d2c8e375b36c7d690e0d9dc8fba774c537af14a7e979129bca23d88d052fbeb9466955e447 + languageName: node + linkType: hard + +"node-exports-info@npm:^1.6.0": + version: 1.6.0 + resolution: "node-exports-info@npm:1.6.0" + dependencies: + array.prototype.flatmap: "npm:^1.3.3" + es-errors: "npm:^1.3.0" + object.entries: "npm:^1.1.9" + semver: "npm:^6.3.1" + checksum: 10c0/3613f21c60b047e66f168d3499a6be0060d89fb01ddceaa7032c2fb318aff12e4b9b111449c1a9aeb3b848bfdc1d4b6bc8fab327af692319597d21a1e7063692 + languageName: node + linkType: hard + +"node-gyp@npm:latest": + version: 13.0.0 + resolution: "node-gyp@npm:13.0.0" + dependencies: + env-paths: "npm:^2.2.0" + exponential-backoff: "npm:^3.1.1" + graceful-fs: "npm:^4.2.6" + nopt: "npm:^10.0.0" + proc-log: "npm:^7.0.0" + semver: "npm:^7.3.5" + tar: "npm:^7.5.4" + tinyglobby: "npm:^0.2.12" + undici: "npm:^6.25.0" + which: "npm:^7.0.0" + bin: + node-gyp: bin/node-gyp.js + checksum: 10c0/e7525c427db2d16aa368b8947187de83083d2a8dda23e3e096a71c22ae637ac5bb8ed7cf6c871f1b9118cd2729dbfee4ff3a4245e2b79226900227b15831b492 + languageName: node + linkType: hard + +"node-html-parser@npm:^6.1.12": + version: 6.1.13 + resolution: "node-html-parser@npm:6.1.13" + dependencies: + css-select: "npm:^5.1.0" + he: "npm:1.2.0" + checksum: 10c0/ca36290507da8ec0fa131a0fd67ba62e300365c3950b5a6058b0e32b71b520ff43a5661b19e98a5c9797dbe3428b08db788b602f1f8aa62f2db5bb66e1d80782 + languageName: node + linkType: hard + +"node-releases@npm:^2.0.36": + version: 2.0.48 + resolution: "node-releases@npm:2.0.48" + checksum: 10c0/17eac8493c0be99130793e87fd67feb6291aecb9f4e473dea3b00f59c002cc8b9c0bdc923227c9aa84968da6b2e4c58e75251981503eb367ec9c742715175a34 + languageName: node + linkType: hard + +"nopt@npm:^10.0.0": + version: 10.0.1 + resolution: "nopt@npm:10.0.1" + dependencies: + abbrev: "npm:^5.0.0" + bin: + nopt: bin/nopt.js + checksum: 10c0/980d89257f9587f3e1f77877ddbf905d6aa3b738ec33e49a4fa1a059a0dd82eb28063982b150654a7ae9de386f2ead60e56172db7d37cf56de545f7392a2a26a + languageName: node + linkType: hard + +"nth-check@npm:^2.0.1": + version: 2.1.1 + resolution: "nth-check@npm:2.1.1" + dependencies: + boolbase: "npm:^1.0.0" + checksum: 10c0/5fee7ff309727763689cfad844d979aedd2204a817fbaaf0e1603794a7c20db28548d7b024692f953557df6ce4a0ee4ae46cd8ebd9b36cfb300b9226b567c479 + languageName: node + linkType: hard + +"object-assign@npm:^4.1.1": + version: 4.1.1 + resolution: "object-assign@npm:4.1.1" + checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414 + languageName: node + linkType: hard + +"object-inspect@npm:^1.13.3, object-inspect@npm:^1.13.4": + version: 1.13.4 + resolution: "object-inspect@npm:1.13.4" + checksum: 10c0/d7f8711e803b96ea3191c745d6f8056ce1f2496e530e6a19a0e92d89b0fa3c76d910c31f0aa270432db6bd3b2f85500a376a83aaba849a8d518c8845b3211692 + languageName: node + linkType: hard + +"object-keys@npm:^1.1.1": + version: 1.1.1 + resolution: "object-keys@npm:1.1.1" + checksum: 10c0/b11f7ccdbc6d406d1f186cdadb9d54738e347b2692a14439ca5ac70c225fa6db46db809711b78589866d47b25fc3e8dee0b4c722ac751e11180f9380e3d8601d + languageName: node + linkType: hard + +"object.assign@npm:^4.1.4, object.assign@npm:^4.1.7": + version: 4.1.7 + resolution: "object.assign@npm:4.1.7" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.3" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.0.0" + has-symbols: "npm:^1.1.0" + object-keys: "npm:^1.1.1" + checksum: 10c0/3b2732bd860567ea2579d1567525168de925a8d852638612846bd8082b3a1602b7b89b67b09913cbb5b9bd6e95923b2ae73580baa9d99cb4e990564e8cbf5ddc + languageName: node + linkType: hard + +"object.entries@npm:^1.1.9": + version: 1.1.9 + resolution: "object.entries@npm:1.1.9" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.4" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.1.1" + checksum: 10c0/d4b8c1e586650407da03370845f029aa14076caca4e4d4afadbc69cfb5b78035fd3ee7be417141abdb0258fa142e59b11923b4c44d8b1255b28f5ffcc50da7db + languageName: node + linkType: hard + +"object.fromentries@npm:^2.0.8": + version: 2.0.8 + resolution: "object.fromentries@npm:2.0.8" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.2" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/cd4327e6c3369cfa805deb4cbbe919bfb7d3aeebf0bcaba291bb568ea7169f8f8cdbcabe2f00b40db0c20cd20f08e11b5f3a5a36fb7dd3fe04850c50db3bf83b + languageName: node + linkType: hard + +"object.values@npm:^1.1.6, object.values@npm:^1.2.1": + version: 1.2.1 + resolution: "object.values@npm:1.2.1" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.3" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/3c47814fdc64842ae3d5a74bc9d06bdd8d21563c04d9939bf6716a9c00596a4ebc342552f8934013d1ec991c74e3671b26710a0c51815f0b603795605ab6b2c9 + languageName: node + linkType: hard + +"obug@npm:^2.1.1": + version: 2.1.3 + resolution: "obug@npm:2.1.3" + checksum: 10c0/cb8187fed0a5fc8445507c950e89f3c1bd43895658c398b5803f6b7804dfa0c562975ecce1e67f3d9247d521452a5bfade9e0e951cc0326b7444272f7c24d25f + languageName: node + linkType: hard + +"optionator@npm:^0.9.3": + version: 0.9.4 + resolution: "optionator@npm:0.9.4" + dependencies: + deep-is: "npm:^0.1.3" + fast-levenshtein: "npm:^2.0.6" + levn: "npm:^0.4.1" + prelude-ls: "npm:^1.2.1" + type-check: "npm:^0.4.0" + word-wrap: "npm:^1.2.5" + checksum: 10c0/4afb687a059ee65b61df74dfe87d8d6815cd6883cb8b3d5883a910df72d0f5d029821f37025e4bccf4048873dbdb09acc6d303d27b8f76b1a80dd5a7d5334675 + languageName: node + linkType: hard + +"own-keys@npm:^1.0.1": + version: 1.0.1 + resolution: "own-keys@npm:1.0.1" + dependencies: + get-intrinsic: "npm:^1.2.6" + object-keys: "npm:^1.1.1" + safe-push-apply: "npm:^1.0.0" + checksum: 10c0/6dfeb3455bff92ec3f16a982d4e3e65676345f6902d9f5ded1d8265a6318d0200ce461956d6d1c70053c7fe9f9fe65e552faac03f8140d37ef0fdd108e67013a + languageName: node + linkType: hard + +"p-limit@npm:^3.0.2": + version: 3.1.0 + resolution: "p-limit@npm:3.1.0" + dependencies: + yocto-queue: "npm:^0.1.0" + checksum: 10c0/9db675949dbdc9c3763c89e748d0ef8bdad0afbb24d49ceaf4c46c02c77d30db4e0652ed36d0a0a7a95154335fab810d95c86153105bb73b3a90448e2bb14e1a + languageName: node + linkType: hard + +"p-locate@npm:^5.0.0": + version: 5.0.0 + resolution: "p-locate@npm:5.0.0" + dependencies: + p-limit: "npm:^3.0.2" + checksum: 10c0/2290d627ab7903b8b70d11d384fee714b797f6040d9278932754a6860845c4d3190603a0772a663c8cb5a7b21d1b16acb3a6487ebcafa9773094edc3dfe6009a + languageName: node + linkType: hard + +"parent-module@npm:^1.0.0": + version: 1.0.1 + resolution: "parent-module@npm:1.0.1" + dependencies: + callsites: "npm:^3.0.0" + checksum: 10c0/c63d6e80000d4babd11978e0d3fee386ca7752a02b035fd2435960ffaa7219dc42146f07069fb65e6e8bf1caef89daf9af7535a39bddf354d78bf50d8294f556 + languageName: node + linkType: hard + +"parse-json@npm:^5.0.0": + version: 5.2.0 + resolution: "parse-json@npm:5.2.0" + dependencies: + "@babel/code-frame": "npm:^7.0.0" + error-ex: "npm:^1.3.1" + json-parse-even-better-errors: "npm:^2.3.0" + lines-and-columns: "npm:^1.1.6" + checksum: 10c0/77947f2253005be7a12d858aedbafa09c9ae39eb4863adf330f7b416ca4f4a08132e453e08de2db46459256fb66afaac5ee758b44fe6541b7cdaf9d252e59585 + languageName: node + linkType: hard + +"path-exists@npm:^4.0.0": + version: 4.0.0 + resolution: "path-exists@npm:4.0.0" + checksum: 10c0/8c0bd3f5238188197dc78dced15207a4716c51cc4e3624c44fc97acf69558f5ebb9a2afff486fe1b4ee148e0c133e96c5e11a9aa5c48a3006e3467da070e5e1b + languageName: node + linkType: hard + +"path-key@npm:^3.1.0": + version: 3.1.1 + resolution: "path-key@npm:3.1.1" + checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c + languageName: node + linkType: hard + +"path-parse@npm:^1.0.7": + version: 1.0.7 + resolution: "path-parse@npm:1.0.7" + checksum: 10c0/11ce261f9d294cc7a58d6a574b7f1b935842355ec66fba3c3fd79e0f036462eaf07d0aa95bb74ff432f9afef97ce1926c720988c6a7451d8a584930ae7de86e1 + languageName: node + linkType: hard + +"path-type@npm:^4.0.0": + version: 4.0.0 + resolution: "path-type@npm:4.0.0" + checksum: 10c0/666f6973f332f27581371efaf303fd6c272cc43c2057b37aa99e3643158c7e4b2626549555d88626e99ea9e046f82f32e41bbde5f1508547e9a11b149b52387c + languageName: node + linkType: hard + +"picocolors@npm:^1.1.1": + version: 1.1.1 + resolution: "picocolors@npm:1.1.1" + checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 + languageName: node + linkType: hard + +"picomatch@npm:^2.2.2": + version: 2.3.2 + resolution: "picomatch@npm:2.3.2" + checksum: 10c0/a554d1709e59be97d1acb9eaedbbc700a5c03dbd4579807baed95100b00420bc729335440ef15004ae2378984e2487a7c1cebd743cfdb72b6fa9ab69223c0d61 + languageName: node + linkType: hard + +"picomatch@npm:^4.0.2, picomatch@npm:^4.0.3, picomatch@npm:^4.0.4": + version: 4.0.4 + resolution: "picomatch@npm:4.0.4" + checksum: 10c0/e2c6023372cc7b5764719a5ffb9da0f8e781212fa7ca4bd0562db929df8e117460f00dff3cb7509dacfc06b86de924b247f504d0ce1806a37fac4633081466b0 + languageName: node + linkType: hard + +"possible-typed-array-names@npm:^1.0.0, possible-typed-array-names@npm:^1.1.0": + version: 1.1.0 + resolution: "possible-typed-array-names@npm:1.1.0" + checksum: 10c0/c810983414142071da1d644662ce4caebce890203eb2bc7bf119f37f3fe5796226e117e6cca146b521921fa6531072674174a3325066ac66fce089a53e1e5196 + languageName: node + linkType: hard + +"postcss@npm:^8.5.6": + version: 8.5.15 + resolution: "postcss@npm:8.5.15" + dependencies: + nanoid: "npm:^3.3.12" + picocolors: "npm:^1.1.1" + source-map-js: "npm:^1.2.1" + checksum: 10c0/7f2e63ae22fbe43aace1bf652bd99da4e90737c64194d49e51ddc9cd0f9e51ff2861a7d734379b494deffa03a880a5c65eec70bc29ee9ebaa7136dde3eee8f31 + languageName: node + linkType: hard + +"preact@npm:^10.26.9": + version: 10.29.2 + resolution: "preact@npm:10.29.2" + checksum: 10c0/2ee161274e475804524608d42bba8c79920636b322293248796a9e5bf4c3332336f8c0eca1b1566ed09cdee95e408eb20b5b7613d95820ea6b6eb8fc090ef60a + languageName: node + linkType: hard + +"prelude-ls@npm:^1.2.1": + version: 1.2.1 + resolution: "prelude-ls@npm:1.2.1" + checksum: 10c0/b00d617431e7886c520a6f498a2e14c75ec58f6d93ba48c3b639cf241b54232d90daa05d83a9e9b9fef6baa63cb7e1e4602c2372fea5bc169668401eb127d0cd + languageName: node + linkType: hard + +"proc-log@npm:^7.0.0": + version: 7.0.0 + resolution: "proc-log@npm:7.0.0" + checksum: 10c0/b89c2d862604f35fec795477b0c7e376feab3ba0d4f4d291c4e959567442697cf451ac557d0623c1cc38af45a78128b983410f397a10c5d3a67f76c33de4754b + languageName: node + linkType: hard + +"prop-types@npm:^15.6.2, prop-types@npm:^15.8.1": + version: 15.8.1 + resolution: "prop-types@npm:15.8.1" + dependencies: + loose-envify: "npm:^1.4.0" + object-assign: "npm:^4.1.1" + react-is: "npm:^16.13.1" + checksum: 10c0/59ece7ca2fb9838031d73a48d4becb9a7cc1ed10e610517c7d8f19a1e02fa47f7c27d557d8a5702bec3cfeccddc853579832b43f449e54635803f277b1c78077 + languageName: node + linkType: hard + +"proxy-from-env@npm:^2.1.0": + version: 2.1.0 + resolution: "proxy-from-env@npm:2.1.0" + checksum: 10c0/ed01729fd4d094eab619cd7e17ce3698b3413b31eb102c4904f9875e677cd207392795d5b4adee9cec359dfd31c44d5ad7595a3a3ad51c40250e141512281c58 + languageName: node + linkType: hard + +"punycode@npm:^2.1.0": + version: 2.3.1 + resolution: "punycode@npm:2.3.1" + checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 + languageName: node + linkType: hard + +"react-is@npm:^16.13.1, react-is@npm:^16.7.0": + version: 16.13.1 + resolution: "react-is@npm:16.13.1" + checksum: 10c0/33977da7a5f1a287936a0c85639fec6ca74f4f15ef1e59a6bc20338fc73dc69555381e211f7a3529b8150a1f71e4225525b41b60b52965bda53ce7d47377ada1 + languageName: node + linkType: hard + +"react-is@npm:^19.2.6": + version: 19.2.7 + resolution: "react-is@npm:19.2.7" + checksum: 10c0/419fe54d5bd7fdf5414a5bb7bd9a1e0e36f9fae28ffb4cb73290fbe342bde15d8584a90d1db62547f6aa03018dce517b178a041abb522136cd4b4b51b4e94c83 + languageName: node + linkType: hard + +"react-transition-group@npm:^4.4.5": + version: 4.4.5 + resolution: "react-transition-group@npm:4.4.5" + dependencies: + "@babel/runtime": "npm:^7.5.5" + dom-helpers: "npm:^5.0.1" + loose-envify: "npm:^1.4.0" + prop-types: "npm:^15.6.2" + peerDependencies: + react: ">=16.6.0" + react-dom: ">=16.6.0" + checksum: 10c0/2ba754ba748faefa15f87c96dfa700d5525054a0141de8c75763aae6734af0740e77e11261a1e8f4ffc08fd9ab78510122e05c21c2d79066c38bb6861a886c82 + languageName: node + linkType: hard + +"reflect.getprototypeof@npm:^1.0.10, reflect.getprototypeof@npm:^1.0.9": + version: 1.0.10 + resolution: "reflect.getprototypeof@npm:1.0.10" + dependencies: + call-bind: "npm:^1.0.8" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.9" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" + get-intrinsic: "npm:^1.2.7" + get-proto: "npm:^1.0.1" + which-builtin-type: "npm:^1.2.1" + checksum: 10c0/7facec28c8008876f8ab98e80b7b9cb4b1e9224353fd4756dda5f2a4ab0d30fa0a5074777c6df24e1e0af463a2697513b0a11e548d99cf52f21f7bc6ba48d3ac + languageName: node + linkType: hard + +"regexp.prototype.flags@npm:^1.5.3, regexp.prototype.flags@npm:^1.5.4": + version: 1.5.4 + resolution: "regexp.prototype.flags@npm:1.5.4" + dependencies: + call-bind: "npm:^1.0.8" + define-properties: "npm:^1.2.1" + es-errors: "npm:^1.3.0" + get-proto: "npm:^1.0.1" + gopd: "npm:^1.2.0" + set-function-name: "npm:^2.0.2" + checksum: 10c0/83b88e6115b4af1c537f8dabf5c3744032cb875d63bc05c288b1b8c0ef37cbe55353f95d8ca817e8843806e3e150b118bc624e4279b24b4776b4198232735a77 + languageName: node + linkType: hard + +"reselect@npm:^5.2.0": + version: 5.2.0 + resolution: "reselect@npm:5.2.0" + checksum: 10c0/d0a8497e404b25a769fe792eacae88b9b576c30870450cd243d76ec9427d91a59c4a2cc00d824d283448b444c4c698a8f961d771c8ae39c759313afb31950e2e + languageName: node + linkType: hard + +"resolve-from@npm:^4.0.0": + version: 4.0.0 + resolution: "resolve-from@npm:4.0.0" + checksum: 10c0/8408eec31a3112ef96e3746c37be7d64020cda07c03a920f5024e77290a218ea758b26ca9529fd7b1ad283947f34b2291c1c0f6aa0ed34acfdda9c6014c8d190 + languageName: node + linkType: hard + +"resolve@npm:^1.19.0": + version: 1.22.12 + resolution: "resolve@npm:1.22.12" + dependencies: + es-errors: "npm:^1.3.0" + is-core-module: "npm:^2.16.1" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10c0/b16dc9b537c02e8c3388f7d3dcff9741d3071625f9a97ac1c885f2b0ca51e78df22328fb6d6ef214dd9101fb7cfc19aa2836fe3410402a94f3f7b8639c7149bf + languageName: node + linkType: hard + +"resolve@npm:^2.0.0-next.5": + version: 2.0.0-next.7 + resolution: "resolve@npm:2.0.0-next.7" + dependencies: + es-errors: "npm:^1.3.0" + is-core-module: "npm:^2.16.2" + node-exports-info: "npm:^1.6.0" + object-keys: "npm:^1.1.1" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10c0/8c6fa17ccdb826a3a52387ed8c42bf705dbc19d5494da52a86661b124b5b88fad5d8edbbb4434a1b563ecf7768368b7da9fb9489e20f36e02f7551a4ea87d707 + languageName: node + linkType: hard + +"resolve@patch:resolve@npm%3A^1.19.0#optional!builtin": + version: 1.22.12 + resolution: "resolve@patch:resolve@npm%3A1.22.12#optional!builtin::version=1.22.12&hash=c3c19d" + dependencies: + es-errors: "npm:^1.3.0" + is-core-module: "npm:^2.16.1" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10c0/fc6519984ae1f894d877c0060ba8b1f5ba3bc0e85a02f74e141929c118c23d74d9735619a9cc2965397387e514884245c65d72a40731dcb6cfc84c7bcdc8321e + languageName: node + linkType: hard + +"resolve@patch:resolve@npm%3A^2.0.0-next.5#optional!builtin": + version: 2.0.0-next.7 + resolution: "resolve@patch:resolve@npm%3A2.0.0-next.7#optional!builtin::version=2.0.0-next.7&hash=c3c19d" + dependencies: + es-errors: "npm:^1.3.0" + is-core-module: "npm:^2.16.2" + node-exports-info: "npm:^1.6.0" + object-keys: "npm:^1.1.1" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10c0/6bb6f1d8a1789f7a5b4e35d950e76bc0ba632ff7d51fe86b6f34fb5f41e1ce0f7b884ec166828cfc0728ddffeaee49527711d752d12398297f90c51acd22195e + languageName: node + linkType: hard + +"rollup@npm:^4.43.0": + version: 4.62.2 + resolution: "rollup@npm:4.62.2" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.62.2" + "@rollup/rollup-android-arm64": "npm:4.62.2" + "@rollup/rollup-darwin-arm64": "npm:4.62.2" + "@rollup/rollup-darwin-x64": "npm:4.62.2" + "@rollup/rollup-freebsd-arm64": "npm:4.62.2" + "@rollup/rollup-freebsd-x64": "npm:4.62.2" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.62.2" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.62.2" + "@rollup/rollup-linux-arm64-gnu": "npm:4.62.2" + "@rollup/rollup-linux-arm64-musl": "npm:4.62.2" + "@rollup/rollup-linux-loong64-gnu": "npm:4.62.2" + "@rollup/rollup-linux-loong64-musl": "npm:4.62.2" + "@rollup/rollup-linux-ppc64-gnu": "npm:4.62.2" + "@rollup/rollup-linux-ppc64-musl": "npm:4.62.2" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.62.2" + "@rollup/rollup-linux-riscv64-musl": "npm:4.62.2" + "@rollup/rollup-linux-s390x-gnu": "npm:4.62.2" + "@rollup/rollup-linux-x64-gnu": "npm:4.62.2" + "@rollup/rollup-linux-x64-musl": "npm:4.62.2" + "@rollup/rollup-openbsd-x64": "npm:4.62.2" + "@rollup/rollup-openharmony-arm64": "npm:4.62.2" + "@rollup/rollup-win32-arm64-msvc": "npm:4.62.2" + "@rollup/rollup-win32-ia32-msvc": "npm:4.62.2" + "@rollup/rollup-win32-x64-gnu": "npm:4.62.2" + "@rollup/rollup-win32-x64-msvc": "npm:4.62.2" + "@types/estree": "npm:1.0.9" + fsevents: "npm:~2.3.2" + dependenciesMeta: + "@rollup/rollup-android-arm-eabi": + optional: true + "@rollup/rollup-android-arm64": + optional: true + "@rollup/rollup-darwin-arm64": + optional: true + "@rollup/rollup-darwin-x64": + optional: true + "@rollup/rollup-freebsd-arm64": + optional: true + "@rollup/rollup-freebsd-x64": + optional: true + "@rollup/rollup-linux-arm-gnueabihf": + optional: true + "@rollup/rollup-linux-arm-musleabihf": + optional: true + "@rollup/rollup-linux-arm64-gnu": + optional: true + "@rollup/rollup-linux-arm64-musl": + optional: true + "@rollup/rollup-linux-loong64-gnu": + optional: true + "@rollup/rollup-linux-loong64-musl": + optional: true + "@rollup/rollup-linux-ppc64-gnu": + optional: true + "@rollup/rollup-linux-ppc64-musl": + optional: true + "@rollup/rollup-linux-riscv64-gnu": + optional: true + "@rollup/rollup-linux-riscv64-musl": + optional: true + "@rollup/rollup-linux-s390x-gnu": + optional: true + "@rollup/rollup-linux-x64-gnu": + optional: true + "@rollup/rollup-linux-x64-musl": + optional: true + "@rollup/rollup-openbsd-x64": + optional: true + "@rollup/rollup-openharmony-arm64": + optional: true + "@rollup/rollup-win32-arm64-msvc": + optional: true + "@rollup/rollup-win32-ia32-msvc": + optional: true + "@rollup/rollup-win32-x64-gnu": + optional: true + "@rollup/rollup-win32-x64-msvc": + optional: true + fsevents: + optional: true + bin: + rollup: dist/bin/rollup + checksum: 10c0/83ff5f4a1fea3fa05db2ef56beceee8c33d4a72b818e19c562f1e85c41076fe5b12aadc44048bb73e60b83336df82154b017fa6bf0186f3141643e6f215fbdcb + languageName: node + linkType: hard + +"root-workspace-0b6124@workspace:.": + version: 0.0.0-use.local + resolution: "root-workspace-0b6124@workspace:." + dependencies: + "@babel/core": "npm:^8.0.1" + "@base-ui/react": "npm:^1.6.0" + "@emotion/react": "npm:^11.14.0" + "@emotion/styled": "npm:^11.14.1" + "@fontsource/roboto": "npm:^5.2.10" + "@mui/icons-material": "npm:^9.1.1" + "@mui/material": "npm:^9.1.2" + "@preact/preset-vite": "npm:^2.10.2" + axios: "npm:^1.18.1" + eslint: "npm:^10.5.0" + eslint-config-preact: "npm:^2.0.0" + preact: "npm:^10.26.9" + typescript: "npm:^6.0.3" + vite: "npm:^7.0.4" + languageName: unknown + linkType: soft + +"safe-array-concat@npm:^1.1.3": + version: 1.1.4 + resolution: "safe-array-concat@npm:1.1.4" + dependencies: + call-bind: "npm:^1.0.9" + call-bound: "npm:^1.0.4" + get-intrinsic: "npm:^1.3.0" + has-symbols: "npm:^1.1.0" + isarray: "npm:^2.0.5" + checksum: 10c0/95fb4904ab1d9360a666fe5ba6d88f1c4a3a39682739e4512cff809fc6b5722a94bd95189211015bfb45859a7ffbc3340ea303ae22721c91c59e8946d310975a + languageName: node + linkType: hard + +"safe-push-apply@npm:^1.0.0": + version: 1.0.0 + resolution: "safe-push-apply@npm:1.0.0" + dependencies: + es-errors: "npm:^1.3.0" + isarray: "npm:^2.0.5" + checksum: 10c0/831f1c9aae7436429e7862c7e46f847dfe490afac20d0ee61bae06108dbf5c745a0de3568ada30ccdd3eeb0864ca8331b2eef703abd69bfea0745b21fd320750 + languageName: node + linkType: hard + +"safe-regex-test@npm:^1.1.0": + version: 1.1.0 + resolution: "safe-regex-test@npm:1.1.0" + dependencies: + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + is-regex: "npm:^1.2.1" + checksum: 10c0/f2c25281bbe5d39cddbbce7f86fca5ea9b3ce3354ea6cd7c81c31b006a5a9fff4286acc5450a3b9122c56c33eba69c56b9131ad751457b2b4a585825e6a10665 + languageName: node + linkType: hard + +"semver@npm:^6.3.1": + version: 6.3.1 + resolution: "semver@npm:6.3.1" + bin: + semver: bin/semver.js + checksum: 10c0/e3d79b609071caa78bcb6ce2ad81c7966a46a7431d9d58b8800cfa9cb6a63699b3899a0e4bcce36167a284578212d9ae6942b6929ba4aa5015c079a67751d42d + languageName: node + linkType: hard + +"semver@npm:^7.3.5, semver@npm:^7.7.3": + version: 7.8.5 + resolution: "semver@npm:7.8.5" + bin: + semver: bin/semver.js + checksum: 10c0/b1f3127a5be8125a94f37188b361c212466c292c6910adce3ec106cff5dc211ccaedc4739c11bb70fda59d6fc1f040a9bca289f4e093451521a2372e5231fe0c + languageName: node + linkType: hard + +"semver@npm:^7.6.2": + version: 7.8.4 + resolution: "semver@npm:7.8.4" + bin: + semver: bin/semver.js + checksum: 10c0/81b7c296fd7927b80f67fa516b75fa1017caac8167795320de28e76ccbc6f7f01763c30ecd10d6a0d8fd089708ab0548a5aebb94b0870e99c2a2b4600a46389b + languageName: node + linkType: hard + +"set-function-length@npm:^1.2.2": + version: 1.2.2 + resolution: "set-function-length@npm:1.2.2" + dependencies: + define-data-property: "npm:^1.1.4" + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + get-intrinsic: "npm:^1.2.4" + gopd: "npm:^1.0.1" + has-property-descriptors: "npm:^1.0.2" + checksum: 10c0/82850e62f412a258b71e123d4ed3873fa9377c216809551192bb6769329340176f109c2eeae8c22a8d386c76739855f78e8716515c818bcaef384b51110f0f3c + languageName: node + linkType: hard + +"set-function-name@npm:^2.0.2": + version: 2.0.2 + resolution: "set-function-name@npm:2.0.2" + dependencies: + define-data-property: "npm:^1.1.4" + es-errors: "npm:^1.3.0" + functions-have-names: "npm:^1.2.3" + has-property-descriptors: "npm:^1.0.2" + checksum: 10c0/fce59f90696c450a8523e754abb305e2b8c73586452619c2bad5f7bf38c7b6b4651895c9db895679c5bef9554339cf3ef1c329b66ece3eda7255785fbe299316 + languageName: node + linkType: hard + +"set-proto@npm:^1.0.0": + version: 1.0.0 + resolution: "set-proto@npm:1.0.0" + dependencies: + dunder-proto: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/ca5c3ccbba479d07c30460e367e66337cec825560b11e8ba9c5ebe13a2a0d6021ae34eddf94ff3dfe17a3104dc1f191519cb6c48378b503e5c3f36393938776a + languageName: node + linkType: hard + +"shebang-command@npm:^2.0.0": + version: 2.0.0 + resolution: "shebang-command@npm:2.0.0" + dependencies: + shebang-regex: "npm:^3.0.0" + checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e + languageName: node + linkType: hard + +"shebang-regex@npm:^3.0.0": + version: 3.0.0 + resolution: "shebang-regex@npm:3.0.0" + checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690 + languageName: node + linkType: hard + +"side-channel-list@npm:^1.0.1": + version: 1.0.1 + resolution: "side-channel-list@npm:1.0.1" + dependencies: + es-errors: "npm:^1.3.0" + object-inspect: "npm:^1.13.4" + checksum: 10c0/d346c787fd2f9f1c2fdea14f00e8250118db0e7596d85a6cb9faa75f105d31a73a8f7a341c93d7df2a2429098c3d37a77bd3be9e88c37094b8c01807bc77c7a2 + languageName: node + linkType: hard + +"side-channel-map@npm:^1.0.1": + version: 1.0.1 + resolution: "side-channel-map@npm:1.0.1" + dependencies: + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.5" + object-inspect: "npm:^1.13.3" + checksum: 10c0/010584e6444dd8a20b85bc926d934424bd809e1a3af941cace229f7fdcb751aada0fb7164f60c2e22292b7fa3c0ff0bce237081fd4cdbc80de1dc68e95430672 + languageName: node + linkType: hard + +"side-channel-weakmap@npm:^1.0.2": + version: 1.0.2 + resolution: "side-channel-weakmap@npm:1.0.2" + dependencies: + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.5" + object-inspect: "npm:^1.13.3" + side-channel-map: "npm:^1.0.1" + checksum: 10c0/71362709ac233e08807ccd980101c3e2d7efe849edc51455030327b059f6c4d292c237f94dc0685031dd11c07dd17a68afde235d6cf2102d949567f98ab58185 + languageName: node + linkType: hard + +"side-channel@npm:^1.1.0": + version: 1.1.1 + resolution: "side-channel@npm:1.1.1" + dependencies: + es-errors: "npm:^1.3.0" + object-inspect: "npm:^1.13.4" + side-channel-list: "npm:^1.0.1" + side-channel-map: "npm:^1.0.1" + side-channel-weakmap: "npm:^1.0.2" + checksum: 10c0/dc0ab81d67f61bda9247d053ce93f41c3fd8ad2bdcb9cf9d8d2f8540d488f26d87a5e99ebfc07eea49ec025867b2452b705442d974b1478f0395e69f6bfb3270 + languageName: node + linkType: hard + +"simple-code-frame@npm:^1.3.0": + version: 1.3.0 + resolution: "simple-code-frame@npm:1.3.0" + dependencies: + kolorist: "npm:^1.6.0" + checksum: 10c0/f74332d839689b30deddc079f52845c05e455160888c2076056dd070d0088b8e84a0f36b6d273d38a8698e738dc5f34bbe6ecdcc86146b9d4250c67374f975c5 + languageName: node + linkType: hard + +"source-map-js@npm:^1.2.1": + version: 1.2.1 + resolution: "source-map-js@npm:1.2.1" + checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf + languageName: node + linkType: hard + +"source-map@npm:^0.5.7": + version: 0.5.7 + resolution: "source-map@npm:0.5.7" + checksum: 10c0/904e767bb9c494929be013017380cbba013637da1b28e5943b566031e29df04fba57edf3f093e0914be094648b577372bd8ad247fa98cfba9c600794cd16b599 + languageName: node + linkType: hard + +"source-map@npm:^0.7.4": + version: 0.7.6 + resolution: "source-map@npm:0.7.6" + checksum: 10c0/59f6f05538539b274ba771d2e9e32f6c65451982510564438e048bc1352f019c6efcdc6dd07909b1968144941c14015c2c7d4369fb7c4d7d53ae769716dcc16c + languageName: node + linkType: hard + +"stack-trace@npm:^1.0.0-pre2": + version: 1.0.0 + resolution: "stack-trace@npm:1.0.0" + checksum: 10c0/630e0a95137eeed8051b5359e0978baf86ae6b12f9ad8d4056398afb39c3953e39d94e104c415f4116b930527946c03df572414f289d435bf5f778490593a9de + languageName: node + linkType: hard + +"stop-iteration-iterator@npm:^1.1.0": + version: 1.1.0 + resolution: "stop-iteration-iterator@npm:1.1.0" + dependencies: + es-errors: "npm:^1.3.0" + internal-slot: "npm:^1.1.0" + checksum: 10c0/de4e45706bb4c0354a4b1122a2b8cc45a639e86206807ce0baf390ee9218d3ef181923fa4d2b67443367c491aa255c5fbaa64bb74648e3c5b48299928af86c09 + languageName: node + linkType: hard + +"string.prototype.matchall@npm:^4.0.12": + version: 4.0.12 + resolution: "string.prototype.matchall@npm:4.0.12" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.3" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.6" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" + get-intrinsic: "npm:^1.2.6" + gopd: "npm:^1.2.0" + has-symbols: "npm:^1.1.0" + internal-slot: "npm:^1.1.0" + regexp.prototype.flags: "npm:^1.5.3" + set-function-name: "npm:^2.0.2" + side-channel: "npm:^1.1.0" + checksum: 10c0/1a53328ada73f4a77f1fdf1c79414700cf718d0a8ef6672af5603e709d26a24f2181208144aed7e858b1bcc1a0d08567a570abfb45567db4ae47637ed2c2f85c + languageName: node + linkType: hard + +"string.prototype.repeat@npm:^1.0.0": + version: 1.0.0 + resolution: "string.prototype.repeat@npm:1.0.0" + dependencies: + define-properties: "npm:^1.1.3" + es-abstract: "npm:^1.17.5" + checksum: 10c0/94c7978566cffa1327d470fd924366438af9b04b497c43a9805e476e2e908aa37a1fd34cc0911156c17556dab62159d12c7b92b3cc304c3e1281fe4c8e668f40 + languageName: node + linkType: hard + +"string.prototype.trim@npm:^1.2.10": + version: 1.2.11 + resolution: "string.prototype.trim@npm:1.2.11" + dependencies: + call-bind: "npm:^1.0.9" + call-bound: "npm:^1.0.4" + define-data-property: "npm:^1.1.4" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.24.2" + es-object-atoms: "npm:^1.1.2" + has-property-descriptors: "npm:^1.0.2" + safe-regex-test: "npm:^1.1.0" + checksum: 10c0/b153cf8ed06db82ff40e27829e88e5c13f45eff9799f1d5707626e25989b488b059d6f5d57011e07f77745e28451e16735f295bc59c8ae146a4fd73a442366b0 + languageName: node + linkType: hard + +"string.prototype.trimend@npm:^1.0.9": + version: 1.0.10 + resolution: "string.prototype.trimend@npm:1.0.10" + dependencies: + call-bind: "npm:^1.0.9" + call-bound: "npm:^1.0.4" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.1.2" + checksum: 10c0/cc09233181769047a5330becfd5740fec5f0c8137886e7b553626788b00f75df9f34db1159bc52dbb7fc389b8ebb6e1dab44c8c9e31eb600039729a542013286 + languageName: node + linkType: hard + +"string.prototype.trimstart@npm:^1.0.8": + version: 1.0.8 + resolution: "string.prototype.trimstart@npm:1.0.8" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/d53af1899959e53c83b64a5fd120be93e067da740e7e75acb433849aa640782fb6c7d4cd5b84c954c84413745a3764df135a8afeb22908b86a835290788d8366 + languageName: node + linkType: hard + +"stylis@npm:4.2.0": + version: 4.2.0 + resolution: "stylis@npm:4.2.0" + checksum: 10c0/a7128ad5a8ed72652c6eba46bed4f416521bc9745a460ef5741edc725252cebf36ee45e33a8615a7057403c93df0866ab9ee955960792db210bb80abd5ac6543 + languageName: node + linkType: hard + +"supports-preserve-symlinks-flag@npm:^1.0.0": + version: 1.0.0 + resolution: "supports-preserve-symlinks-flag@npm:1.0.0" + checksum: 10c0/6c4032340701a9950865f7ae8ef38578d8d7053f5e10518076e6554a9381fa91bd9c6850193695c141f32b21f979c985db07265a758867bac95de05f7d8aeb39 + languageName: node + linkType: hard + +"tar@npm:^7.5.4": + version: 7.5.16 + resolution: "tar@npm:7.5.16" + dependencies: + "@isaacs/fs-minipass": "npm:^4.0.0" + chownr: "npm:^3.0.0" + minipass: "npm:^7.1.2" + minizlib: "npm:^3.1.0" + yallist: "npm:^5.0.0" + checksum: 10c0/4f37f3c4bd2ca2755fd736a5df1d573c1a868ec1b1e893346aeafa95ac510f9e2fd1469420bd866cc7904799e5bd4ac62b5d4f03fe27747d6e1e373b44505c5c + languageName: node + linkType: hard + +"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.15": + version: 0.2.17 + resolution: "tinyglobby@npm:0.2.17" + dependencies: + fdir: "npm:^6.5.0" + picomatch: "npm:^4.0.4" + checksum: 10c0/7f7bb0f197c88bc4b20c231e0deca4240ca3bf313a88f5a7fee93a872b84966a4d50220947c0455ad07a60b3b360961c5b7fd979222aeb716a9f99b412002e4c + languageName: node + linkType: hard + +"type-check@npm:^0.4.0, type-check@npm:~0.4.0": + version: 0.4.0 + resolution: "type-check@npm:0.4.0" + dependencies: + prelude-ls: "npm:^1.2.1" + checksum: 10c0/7b3fd0ed43891e2080bf0c5c504b418fbb3e5c7b9708d3d015037ba2e6323a28152ec163bcb65212741fa5d2022e3075ac3c76440dbd344c9035f818e8ecee58 + languageName: node + linkType: hard + +"typed-array-buffer@npm:^1.0.3": + version: 1.0.3 + resolution: "typed-array-buffer@npm:1.0.3" + dependencies: + call-bound: "npm:^1.0.3" + es-errors: "npm:^1.3.0" + is-typed-array: "npm:^1.1.14" + checksum: 10c0/1105071756eb248774bc71646bfe45b682efcad93b55532c6ffa4518969fb6241354e4aa62af679ae83899ec296d69ef88f1f3763657cdb3a4d29321f7b83079 + languageName: node + linkType: hard + +"typed-array-byte-length@npm:^1.0.3": + version: 1.0.3 + resolution: "typed-array-byte-length@npm:1.0.3" + dependencies: + call-bind: "npm:^1.0.8" + for-each: "npm:^0.3.3" + gopd: "npm:^1.2.0" + has-proto: "npm:^1.2.0" + is-typed-array: "npm:^1.1.14" + checksum: 10c0/6ae083c6f0354f1fce18b90b243343b9982affd8d839c57bbd2c174a5d5dc71be9eb7019ffd12628a96a4815e7afa85d718d6f1e758615151d5f35df841ffb3e + languageName: node + linkType: hard + +"typed-array-byte-offset@npm:^1.0.4": + version: 1.0.4 + resolution: "typed-array-byte-offset@npm:1.0.4" + dependencies: + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.8" + for-each: "npm:^0.3.3" + gopd: "npm:^1.2.0" + has-proto: "npm:^1.2.0" + is-typed-array: "npm:^1.1.15" + reflect.getprototypeof: "npm:^1.0.9" + checksum: 10c0/3d805b050c0c33b51719ee52de17c1cd8e6a571abdf0fffb110e45e8dd87a657e8b56eee94b776b13006d3d347a0c18a730b903cf05293ab6d92e99ff8f77e53 + languageName: node + linkType: hard + +"typed-array-length@npm:^1.0.7": + version: 1.0.8 + resolution: "typed-array-length@npm:1.0.8" + dependencies: + call-bind: "npm:^1.0.9" + for-each: "npm:^0.3.5" + gopd: "npm:^1.2.0" + is-typed-array: "npm:^1.1.15" + possible-typed-array-names: "npm:^1.1.0" + reflect.getprototypeof: "npm:^1.0.10" + checksum: 10c0/5319f740fc426a3217182c2f7c87656acb0903e046de5a938e30167337d26abf1bb3ad4b32833a72521a4cc58223aec80627b38b357d0a3d5fd64881427e77ab + languageName: node + linkType: hard + +"typescript@npm:^6.0.3": + version: 6.0.3 + resolution: "typescript@npm:6.0.3" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/4a25ff5045b984370f48f196b3a0120779b1b343d40b9a68d114ea5e5fff099809b2bb777576991a63a5cd59cf7bffd96ff6fe10afcefbcb8bd6fb96ad4b6606 + languageName: node + linkType: hard + +"typescript@patch:typescript@npm%3A^6.0.3#optional!builtin": + version: 6.0.3 + resolution: "typescript@patch:typescript@npm%3A6.0.3#optional!builtin::version=6.0.3&hash=5786d5" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/2f25c74e65663c248fa1ade2b8459d9ce5372ff9dad07067310f132966ebec1d93f6c42f0baf77a6b6a7a91460463f708e6887013aaade22111037457c6b25df + languageName: node + linkType: hard + +"unbox-primitive@npm:^1.1.0": + version: 1.1.0 + resolution: "unbox-primitive@npm:1.1.0" + dependencies: + call-bound: "npm:^1.0.3" + has-bigints: "npm:^1.0.2" + has-symbols: "npm:^1.1.0" + which-boxed-primitive: "npm:^1.1.1" + checksum: 10c0/7dbd35ab02b0e05fe07136c72cb9355091242455473ec15057c11430129bab38b7b3624019b8778d02a881c13de44d63cd02d122ee782fb519e1de7775b5b982 + languageName: node + linkType: hard + +"undici@npm:^6.25.0": + version: 6.27.0 + resolution: "undici@npm:6.27.0" + checksum: 10c0/f88c3dae3957dbf9d93cb481440aced317bd3c4941b5914fea5efba516d51138988cdb5c76006f0bb1337e41d56c3443351055d492e73af2428521c37ba2a76f + languageName: node + linkType: hard + +"update-browserslist-db@npm:^1.2.3": + version: 1.2.3 + resolution: "update-browserslist-db@npm:1.2.3" + dependencies: + escalade: "npm:^3.2.0" + picocolors: "npm:^1.1.1" + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 10c0/13a00355ea822388f68af57410ce3255941d5fb9b7c49342c4709a07c9f230bbef7f7499ae0ca7e0de532e79a82cc0c4edbd125f1a323a1845bf914efddf8bec + languageName: node + linkType: hard + +"uri-js@npm:^4.2.2": + version: 4.4.1 + resolution: "uri-js@npm:4.4.1" + dependencies: + punycode: "npm:^2.1.0" + checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c + languageName: node + linkType: hard + +"use-sync-external-store@npm:^1.6.0": + version: 1.6.0 + resolution: "use-sync-external-store@npm:1.6.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 10c0/35e1179f872a53227bdf8a827f7911da4c37c0f4091c29b76b1e32473d1670ebe7bcd880b808b7549ba9a5605c233350f800ffab963ee4a4ee346ee983b6019b + languageName: node + linkType: hard + +"vite-prerender-plugin@npm:^0.5.8": + version: 0.5.13 + resolution: "vite-prerender-plugin@npm:0.5.13" + dependencies: + kolorist: "npm:^1.8.0" + magic-string: "npm:0.x >= 0.26.0" + node-html-parser: "npm:^6.1.12" + simple-code-frame: "npm:^1.3.0" + source-map: "npm:^0.7.4" + stack-trace: "npm:^1.0.0-pre2" + peerDependencies: + vite: 5.x || 6.x || 7.x || 8.x + checksum: 10c0/474feed1faac452f62c501330f0109e9c2a9ddac84bd27acc4ecb8ff92f1f0670abc1949ed8eff45957108ce65b94cd24f3b1ceae45cf3ffa75e11e0591f4bc4 + languageName: node + linkType: hard + +"vite@npm:^7.0.4": + version: 7.3.5 + resolution: "vite@npm:7.3.5" + dependencies: + esbuild: "npm:^0.27.0" + fdir: "npm:^6.5.0" + fsevents: "npm:~2.3.3" + picomatch: "npm:^4.0.3" + postcss: "npm:^8.5.6" + rollup: "npm:^4.43.0" + tinyglobby: "npm:^0.2.15" + peerDependencies: + "@types/node": ^20.19.0 || >=22.12.0 + jiti: ">=1.21.0" + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: ">=0.54.8" + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + dependenciesMeta: + fsevents: + optional: true + peerDependenciesMeta: + "@types/node": + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + bin: + vite: bin/vite.js + checksum: 10c0/4ad700649ed2ebd1e726d32f3f6e41eecbec4e29bcb5977805f3d43a5659280518aa431b0fc61adc1879df4fe1978d7cfc7dbbe54cdf014022385052967721e8 + languageName: node + linkType: hard + +"which-boxed-primitive@npm:^1.1.0, which-boxed-primitive@npm:^1.1.1": + version: 1.1.1 + resolution: "which-boxed-primitive@npm:1.1.1" + dependencies: + is-bigint: "npm:^1.1.0" + is-boolean-object: "npm:^1.2.1" + is-number-object: "npm:^1.1.1" + is-string: "npm:^1.1.1" + is-symbol: "npm:^1.1.1" + checksum: 10c0/aceea8ede3b08dede7dce168f3883323f7c62272b49801716e8332ff750e7ae59a511ae088840bc6874f16c1b7fd296c05c949b0e5b357bfe3c431b98c417abe + languageName: node + linkType: hard + +"which-builtin-type@npm:^1.2.1": + version: 1.2.1 + resolution: "which-builtin-type@npm:1.2.1" + dependencies: + call-bound: "npm:^1.0.2" + function.prototype.name: "npm:^1.1.6" + has-tostringtag: "npm:^1.0.2" + is-async-function: "npm:^2.0.0" + is-date-object: "npm:^1.1.0" + is-finalizationregistry: "npm:^1.1.0" + is-generator-function: "npm:^1.0.10" + is-regex: "npm:^1.2.1" + is-weakref: "npm:^1.0.2" + isarray: "npm:^2.0.5" + which-boxed-primitive: "npm:^1.1.0" + which-collection: "npm:^1.0.2" + which-typed-array: "npm:^1.1.16" + checksum: 10c0/8dcf323c45e5c27887800df42fbe0431d0b66b1163849bb7d46b5a730ad6a96ee8bfe827d078303f825537844ebf20c02459de41239a0a9805e2fcb3cae0d471 + languageName: node + linkType: hard + +"which-collection@npm:^1.0.2": + version: 1.0.2 + resolution: "which-collection@npm:1.0.2" + dependencies: + is-map: "npm:^2.0.3" + is-set: "npm:^2.0.3" + is-weakmap: "npm:^2.0.2" + is-weakset: "npm:^2.0.3" + checksum: 10c0/3345fde20964525a04cdf7c4a96821f85f0cc198f1b2ecb4576e08096746d129eb133571998fe121c77782ac8f21cbd67745a3d35ce100d26d4e684c142ea1f2 + languageName: node + linkType: hard + +"which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.19": + version: 1.1.22 + resolution: "which-typed-array@npm:1.1.22" + dependencies: + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.9" + call-bound: "npm:^1.0.4" + for-each: "npm:^0.3.5" + get-proto: "npm:^1.0.1" + gopd: "npm:^1.2.0" + has-tostringtag: "npm:^1.0.2" + checksum: 10c0/e59db184a4e78b461fac3b05fafc1e7badbbedafbf04a967ee1de73717f1f9723a79699e7b5de71d449541cb5da8353efc01a4f8a72a152479850e54fa196c40 + languageName: node + linkType: hard + +"which@npm:^2.0.1": + version: 2.0.2 + resolution: "which@npm:2.0.2" + dependencies: + isexe: "npm:^2.0.0" + bin: + node-which: ./bin/node-which + checksum: 10c0/66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f + languageName: node + linkType: hard + +"which@npm:^7.0.0": + version: 7.0.0 + resolution: "which@npm:7.0.0" + dependencies: + isexe: "npm:^4.0.0" + bin: + node-which: bin/which.js + checksum: 10c0/ca0b54f198f78bbc4b7c02e34bda8d335cb352e0adb4cbca1c37b1a957af3a879a82c4c27ca6525bc942f548d8b64f816ef6528360af9f3de55ffb9b979b620d + languageName: node + linkType: hard + +"word-wrap@npm:^1.2.5": + version: 1.2.5 + resolution: "word-wrap@npm:1.2.5" + checksum: 10c0/e0e4a1ca27599c92a6ca4c32260e8a92e8a44f4ef6ef93f803f8ed823f486e0889fc0b93be4db59c8d51b3064951d25e43d434e95dc8c960cc3a63d65d00ba20 + languageName: node + linkType: hard + +"yallist@npm:^3.0.2": + version: 3.1.1 + resolution: "yallist@npm:3.1.1" + checksum: 10c0/c66a5c46bc89af1625476f7f0f2ec3653c1a1791d2f9407cfb4c2ba812a1e1c9941416d71ba9719876530e3340a99925f697142989371b72d93b9ee628afd8c1 + languageName: node + linkType: hard + +"yallist@npm:^5.0.0": + version: 5.0.0 + resolution: "yallist@npm:5.0.0" + checksum: 10c0/a499c81ce6d4a1d260d4ea0f6d49ab4da09681e32c3f0472dee16667ed69d01dae63a3b81745a24bd78476ec4fcf856114cb4896ace738e01da34b2c42235416 + languageName: node + linkType: hard + +"yaml@npm:^1.10.0": + version: 1.10.3 + resolution: "yaml@npm:1.10.3" + checksum: 10c0/c309ff85a0a569a981d71ab9cf0fef68672a16b9cdf40639d1c3b30034f6cd16ee428602bd6d64ecf006f8c8bee499023cac236538f79898aa99fb5db529a2ed + languageName: node + linkType: hard + +"yocto-queue@npm:^0.1.0": + version: 0.1.0 + resolution: "yocto-queue@npm:0.1.0" + checksum: 10c0/dceb44c28578b31641e13695d200d34ec4ab3966a5729814d5445b194933c096b7ced71494ce53a0e8820685d1d010df8b2422e5bf2cdea7e469d97ffbea306f + languageName: node + linkType: hard + +"zimmerframe@npm:^1.1.4": + version: 1.1.4 + resolution: "zimmerframe@npm:1.1.4" + checksum: 10c0/9470cbf22cefae975ab413c7158a119d082b354ddcf0da48a842f2f42246fa15943cd9b92c047de39db38015e3b866e32f383bc217e8e4f4192945c7d425536b + languageName: node + linkType: hard