diff --git a/.gitignore b/.gitignore index 39a64c7..a43fa81 100644 --- a/.gitignore +++ b/.gitignore @@ -194,3 +194,6 @@ pip-log.txt # Mac crap .DS_Store + +# Nuke build tool +.nuke/temp \ No newline at end of file diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json new file mode 100644 index 0000000..c1999a9 --- /dev/null +++ b/.nuke/build.schema.json @@ -0,0 +1,134 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Build Schema", + "$ref": "#/definitions/build", + "definitions": { + "build": { + "type": "object", + "properties": { + "Configuration": { + "type": "string", + "description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)", + "enum": [ + "Debug", + "Release" + ] + }, + "Continue": { + "type": "boolean", + "description": "Indicates to continue a previously failed build attempt" + }, + "Help": { + "type": "boolean", + "description": "Shows the help text for this build assembly" + }, + "Host": { + "type": "string", + "description": "Host for execution. Default is 'automatic'", + "enum": [ + "AppVeyor", + "AzurePipelines", + "Bamboo", + "Bitbucket", + "Bitrise", + "GitHubActions", + "GitLab", + "Jenkins", + "Rider", + "SpaceAutomation", + "TeamCity", + "Terminal", + "TravisCI", + "VisualStudio", + "VSCode" + ] + }, + "NoLogo": { + "type": "boolean", + "description": "Disables displaying the NUKE logo" + }, + "Partition": { + "type": "string", + "description": "Partition to use on CI" + }, + "Plan": { + "type": "boolean", + "description": "Shows the execution plan (HTML)" + }, + "Profile": { + "type": "array", + "description": "Defines the profiles to load", + "items": { + "type": "string" + } + }, + "ReleaseNotesFilePath": { + "type": "string", + "description": "ReleaseNotesFilePath - To determine the SemanticVersion" + }, + "Root": { + "type": "string", + "description": "Root directory during build execution" + }, + "Skip": { + "type": "array", + "description": "List of targets to be skipped. Empty list skips all dependencies", + "items": { + "type": "string", + "enum": [ + "Clean", + "Compile", + "CopyFiles", + "CreatePackage", + "Default", + "Package", + "PrePublish", + "Publish", + "PublishPackage", + "PublishPreRelease", + "PublishRelease", + "Restore", + "RunUnitTests" + ] + } + }, + "Solution": { + "type": "string", + "description": "Path to a solution file that is automatically loaded" + }, + "Target": { + "type": "array", + "description": "List of targets to be invoked. Default is '{default_target}'", + "items": { + "type": "string", + "enum": [ + "Clean", + "Compile", + "CopyFiles", + "CreatePackage", + "Default", + "Package", + "PrePublish", + "Publish", + "PublishPackage", + "PublishPreRelease", + "PublishRelease", + "Restore", + "RunUnitTests" + ] + } + }, + "Verbosity": { + "type": "string", + "description": "Logging verbosity during build execution. Default is 'Normal'", + "enum": [ + "Minimal", + "Normal", + "Quiet", + "Verbose" + ] + } + } + } + } +} \ No newline at end of file diff --git a/.nuke/parameters.json b/.nuke/parameters.json new file mode 100644 index 0000000..4dcccaa --- /dev/null +++ b/.nuke/parameters.json @@ -0,0 +1,4 @@ +{ + "$schema": "./build.schema.json", + "Solution": "src/AngleSharp.Js.sln" +} \ No newline at end of file diff --git a/build.cake b/build.cake deleted file mode 100644 index 33ee873..0000000 --- a/build.cake +++ /dev/null @@ -1,14 +0,0 @@ -var target = Argument("target", "Default"); -var projectName = "AngleSharp.Js"; -var solutionName = "AngleSharp.Js"; -var frameworks = new Dictionary -{ - { "net46", "net46" }, - { "net461", "net461" }, - { "net472", "net472" }, - { "netstandard2.0", "netstandard2.0" }, -}; - -#load tools/anglesharp.cake - -RunTarget(target); diff --git a/build.cmd b/build.cmd new file mode 100644 index 0000000..b08cc59 --- /dev/null +++ b/build.cmd @@ -0,0 +1,7 @@ +:; set -eo pipefail +:; SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) +:; ${SCRIPT_DIR}/build.sh "$@" +:; exit $? + +@ECHO OFF +powershell -ExecutionPolicy ByPass -NoProfile -File "%~dp0build.ps1" %* diff --git a/build.ps1 b/build.ps1 index 6f27bfd..1f264e7 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,81 +1,69 @@ +[CmdletBinding()] Param( - [string]$Script = "build.cake", - [string]$Target = "Default", - [ValidateSet("Release", "Debug")] - [string]$Configuration = "Release", - [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] - [string]$Verbosity = "Verbose", - [switch]$Experimental, - [switch]$WhatIf, - [switch]$Mono, - [switch]$SkipToolPackageRestore, [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] - [string[]]$ScriptArgs + [string[]]$BuildArguments ) -$PSScriptRoot = split-path -parent $MyInvocation.MyCommand.Definition; -$UseDryRun = ""; -$UseMono = ""; -$TOOLS_DIR = Join-Path $PSScriptRoot "tools" -$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" -$NUGET_OLD_EXE = Join-Path $TOOLS_DIR "nuget_old.exe" -$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" -$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -$NUGET_OLD_URL = "https://dist.nuget.org/win-x86-commandline/v3.5.0/nuget.exe" +Write-Output "PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)" -# Should we use experimental build of Roslyn? -$UseExperimental = ""; -if ($Experimental.IsPresent) { - $UseExperimental = "--experimental" -} +Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { Write-Error $_ -ErrorAction Continue; exit 1 } +$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent -# Is this a dry run? -if ($WhatIf.IsPresent) { - $UseDryRun = "--dryrun" -} +########################################################################### +# CONFIGURATION +########################################################################### -# Should we use mono? -if ($Mono.IsPresent) { - $UseMono = "--mono" -} +$BuildProjectFile = "$PSScriptRoot\nuke\_build.csproj" +$TempDirectory = "$PSScriptRoot\\.nuke\temp" -# Try download NuGet.exe if do not exist. -if (!(Test-Path $NUGET_EXE)) { - (New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE) -} +$DotNetGlobalFile = "$PSScriptRoot\\global.json" +$DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1" +$DotNetChannel = "Current" -# Try download NuGet.exe if do not exist. -if (!(Test-Path $NUGET_OLD_URL)) { - (New-Object System.Net.WebClient).DownloadFile($NUGET_OLD_URL, $NUGET_OLD_EXE) -} +$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1 +$env:DOTNET_CLI_TELEMETRY_OPTOUT = 1 +$env:DOTNET_MULTILEVEL_LOOKUP = 0 -# Make sure NuGet (latest) exists where we expect it. -if (!(Test-Path $NUGET_EXE)) { - Throw "Could not find nuget.exe" +########################################################################### +# EXECUTION +########################################################################### + +function ExecSafe([scriptblock] $cmd) { + & $cmd + if ($LASTEXITCODE) { exit $LASTEXITCODE } } -# Make sure NuGet (v3.5.0) exists where we expect it. -if (!(Test-Path $NUGET_OLD_EXE)) { - Throw "Could not find nuget_old.exe" +# If dotnet CLI is installed globally and it matches requested version, use for execution +if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and ` + $(dotnet --version) -and $LASTEXITCODE -eq 0) { + $env:DOTNET_EXE = (Get-Command "dotnet").Path } +else { + # Download install script + $DotNetInstallFile = "$TempDirectory\dotnet-install.ps1" + New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + (New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile) -# Restore tools from NuGet? -if (-Not $SkipToolPackageRestore.IsPresent) -{ - Push-Location - Set-Location $TOOLS_DIR - Invoke-Expression "$NUGET_EXE install -ExcludeVersion" - Pop-Location - if ($LASTEXITCODE -ne 0) { - exit $LASTEXITCODE + # If global.json exists, load expected version + if (Test-Path $DotNetGlobalFile) { + $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json) + if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) { + $DotNetVersion = $DotNetGlobal.sdk.version + } } -} -# Make sure that Cake has been installed. -if (!(Test-Path $CAKE_EXE)) { - Throw "Could not find Cake.exe" + # Install by channel or version + $DotNetDirectory = "$TempDirectory\dotnet-win" + if (!(Test-Path variable:DotNetVersion)) { + ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath } + } else { + ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath } + } + $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe" } -# Start Cake -Invoke-Expression "$CAKE_EXE `"$Script`" --target=`"$Target`" --configuration=`"$Configuration`" --verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs" -exit $LASTEXITCODE \ No newline at end of file +Write-Output "Microsoft (R) .NET SDK version $(& $env:DOTNET_EXE --version)" + +ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet } +ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments } diff --git a/build.sh b/build.sh index c62ce5c..7534123 100755 --- a/build.sh +++ b/build.sh @@ -1,93 +1,62 @@ #!/usr/bin/env bash -############################################################### -# This is the Cake bootstrapper script that is responsible for -# downloading Cake and all specified tools from NuGet. -############################################################### -# Define directories. -SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) -TOOLS_DIR=$SCRIPT_DIR/tools -NUGET_EXE=$TOOLS_DIR/nuget.exe -NUGET_OLD_EXE=$TOOLS_DIR/nuget_old.exe -CAKE_EXE=$TOOLS_DIR/Cake/Cake.exe +bash --version 2>&1 | head -n 1 -# Define default arguments. -SCRIPT="build.cake" -TARGET="Default" -CONFIGURATION="Release" -VERBOSITY="verbose" -DRYRUN= -SHOW_VERSION=false -SCRIPT_ARGUMENTS=() +set -eo pipefail +SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) -# Parse arguments. -for i in "$@"; do - case $1 in - -s|--script) SCRIPT="$2"; shift ;; - -t|--target) TARGET="$2"; shift ;; - -c|--configuration) CONFIGURATION="$2"; shift ;; - -v|--verbosity) VERBOSITY="$2"; shift ;; - -d|--dryrun) DRYRUN="--dryrun" ;; - --version) SHOW_VERSION=true ;; - --) shift; SCRIPT_ARGUMENTS+=("$@"); break ;; - *) SCRIPT_ARGUMENTS+=("$1") ;; - esac - shift -done +########################################################################### +# CONFIGURATION +########################################################################### -# Make sure the tools folder exist. -if [ ! -d $TOOLS_DIR ]; then - mkdir $TOOLS_DIR -fi +BUILD_PROJECT_FILE="$SCRIPT_DIR/nuke/_build.csproj" +TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp" -# Make sure that packages.config exist. -if [ ! -f $TOOLS_DIR/packages.config ]; then - echo "Downloading packages.config..." - curl -Lsfo $TOOLS_DIR/packages.config http://cakebuild.net/bootstrapper/packages - if [ $? -ne 0 ]; then - echo "An error occured while downloading packages.config." - exit 1 - fi -fi +DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json" +DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh" +DOTNET_CHANNEL="Current" -# Download NuGet (v3.5.0) if it does not exist. -if [ ! -f $NUGET_OLD_EXE ]; then - echo "Downloading NuGet..." - curl -Lsfo $NUGET_OLD_EXE https://dist.nuget.org/win-x86-commandline/v3.5.0/nuget.exe - if [ $? -ne 0 ]; then - echo "An error occured while downloading nuget.exe." - exit 1 - fi -fi +export DOTNET_CLI_TELEMETRY_OPTOUT=1 +export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 +export DOTNET_MULTILEVEL_LOOKUP=0 + +########################################################################### +# EXECUTION +########################################################################### -# Download NuGet (latest) if it does not exist. -if [ ! -f $NUGET_EXE ]; then - echo "Downloading NuGet..." - curl -Lsfo $NUGET_EXE https://dist.nuget.org/win-x86-commandline/latest/nuget.exe - if [ $? -ne 0 ]; then - echo "An error occured while downloading nuget.exe." - exit 1 +function FirstJsonValue { + perl -nle 'print $1 if m{"'"$1"'": "([^"]+)",?}' <<< "${@:2}" +} + +# If dotnet CLI is installed globally and it matches requested version, use for execution +if [ -x "$(command -v dotnet)" ] && dotnet --version &>/dev/null; then + export DOTNET_EXE="$(command -v dotnet)" +else + # Download install script + DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh" + mkdir -p "$TEMP_DIRECTORY" + curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL" + chmod +x "$DOTNET_INSTALL_FILE" + + # If global.json exists, load expected version + if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then + DOTNET_VERSION=$(FirstJsonValue "version" "$(cat "$DOTNET_GLOBAL_FILE")") + if [[ "$DOTNET_VERSION" == "" ]]; then + unset DOTNET_VERSION + fi fi -fi -# Restore tools from NuGet. -pushd $TOOLS_DIR >/dev/null -mono $NUGET_EXE install -ExcludeVersion -if [ $? -ne 0 ]; then - echo "Could not restore NuGet packages." - exit 1 + # Install by channel or version + DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix" + if [[ -z ${DOTNET_VERSION+x} ]]; then + "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path + else + "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path + fi + export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet" fi -popd >/dev/null -# Make sure that Cake has been installed. -if [ ! -f $CAKE_EXE ]; then - echo "Could not find Cake.exe at '$CAKE_EXE'." - exit 1 -fi +echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)" -# Start Cake -if $SHOW_VERSION; then - exec mono $CAKE_EXE --version -else - exec mono $CAKE_EXE $SCRIPT --verbosity=$VERBOSITY --configuration=$CONFIGURATION --target=$TARGET $DRYRUN "${SCRIPT_ARGUMENTS[@]}" -fi \ No newline at end of file +"$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet +"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@" diff --git a/nuke/.editorconfig b/nuke/.editorconfig new file mode 100644 index 0000000..31e43dc --- /dev/null +++ b/nuke/.editorconfig @@ -0,0 +1,11 @@ +[*.cs] +dotnet_style_qualification_for_field = false:warning +dotnet_style_qualification_for_property = false:warning +dotnet_style_qualification_for_method = false:warning +dotnet_style_qualification_for_event = false:warning +dotnet_style_require_accessibility_modifiers = never:warning + +csharp_style_expression_bodied_methods = true:silent +csharp_style_expression_bodied_properties = true:warning +csharp_style_expression_bodied_indexers = true:warning +csharp_style_expression_bodied_accessors = true:warning diff --git a/nuke/Build.cs b/nuke/Build.cs new file mode 100644 index 0000000..43ecd98 --- /dev/null +++ b/nuke/Build.cs @@ -0,0 +1,298 @@ +using Microsoft.Build.Exceptions; +using Nuke.Common; +using Nuke.Common.CI.GitHubActions; +using Nuke.Common.IO; +using Nuke.Common.ProjectModel; +using Nuke.Common.Tools.DotNet; +using Nuke.Common.Tools.GitHub; +using Nuke.Common.Tools.NuGet; +using Nuke.Common.Utilities.Collections; +using Octokit; +using Octokit.Internal; +using Serilog; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Nuke.Common.Tooling; +using static Nuke.Common.IO.FileSystemTasks; +using static Nuke.Common.IO.PathConstruction; +using static Nuke.Common.Tools.DotNet.DotNetTasks; +using static Nuke.Common.Tools.NuGet.NuGetTasks; +using Project = Nuke.Common.ProjectModel.Project; + +class Build : NukeBuild +{ + /// Support plugins are available for: + /// - JetBrains ReSharper https://nuke.build/resharper + /// - JetBrains Rider https://nuke.build/rider + /// - Microsoft VisualStudio https://nuke.build/visualstudio + /// - Microsoft VSCode https://nuke.build/vscode + + public static int Main () => Execute(x => x.RunUnitTests); + + [Nuke.Common.Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")] + readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release; + + [Nuke.Common.Parameter("ReleaseNotesFilePath - To determine the SemanticVersion")] + readonly AbsolutePath ReleaseNotesFilePath = RootDirectory / "CHANGELOG.md"; + + [Solution] + readonly Solution Solution; + + string TargetProjectName => "AngleSharp.Js"; + + string TargetLibName => TargetProjectName; + + AbsolutePath SourceDirectory => RootDirectory / "src"; + + AbsolutePath BuildDirectory => SourceDirectory / TargetProjectName / "bin" / Configuration; + + AbsolutePath ResultDirectory => RootDirectory / "bin" / Version; + + AbsolutePath NugetDirectory => ResultDirectory / "nuget"; + + GitHubActions GitHubActions => GitHubActions.Instance; + + Project TargetProject { get; set; } + + // Note: The ChangeLogTasks from Nuke itself look buggy. So using the Cake source code. + IReadOnlyList ChangeLog { get; set; } + + ReleaseNotes LatestReleaseNotes { get; set; } + + SemVersion SemVersion { get; set; } + + string Version { get; set; } + + IReadOnlyCollection TargetFrameworks { get; set; } + + protected override void OnBuildInitialized() + { + var parser = new ReleaseNotesParser(); + + Log.Debug("Reading ChangeLog {FilePath}...", ReleaseNotesFilePath); + ChangeLog = parser.Parse(File.ReadAllText(ReleaseNotesFilePath)); + ChangeLog.NotNull("ChangeLog / ReleaseNotes could not be read!"); + + LatestReleaseNotes = ChangeLog.First(); + LatestReleaseNotes.NotNull("LatestVersion could not be read!"); + + Log.Debug("Using LastestVersion from ChangeLog: {LatestVersion}", LatestReleaseNotes.Version); + SemVersion = LatestReleaseNotes.SemVersion; + Version = LatestReleaseNotes.Version.ToString(); + + if (GitHubActions != null) + { + Log.Debug("Add Version Postfix if under CI - GithubAction(s)..."); + + var buildNumber = GitHubActions.RunNumber; + + if (ScheduledTargets.Contains(Default)) + { + Version = $"{Version}-ci.{buildNumber}"; + } + else if (ScheduledTargets.Contains(PrePublish)) + { + Version = $"{Version}-beta.{buildNumber}"; + } + } + + Log.Information("Building version: {Version}", Version); + + TargetProject = Solution.GetProject(SourceDirectory / TargetProjectName / $"{TargetLibName}.csproj" ); + TargetProject.NotNull("TargetProject could not be loaded!"); + + TargetFrameworks = TargetProject.GetTargetFrameworks(); + TargetFrameworks.NotNull("No TargetFramework(s) found to build for!"); + + Log.Information("Target Framework(s): {Frameworks}", TargetFrameworks); + } + + Target Clean => _ => _ + .Before(Restore) + .Executes(() => + { + SourceDirectory.GlobDirectories("**/bin", "**/obj").ForEach(DeleteDirectory); + }); + + Target Restore => _ => _ + .Executes(() => + { + DotNetRestore(s => s + .SetProjectFile(Solution)); + }); + + Target Compile => _ => _ + .DependsOn(Restore) + .Executes(() => + { + DotNetBuild(s => s + .SetProjectFile(Solution) + .SetConfiguration(Configuration) + .EnableNoRestore()); + }); + + Target RunUnitTests => _ => _ + .DependsOn(Compile) + .Executes(() => + { + DotNetTest(s => s + .SetProjectFile(Solution) + .SetConfiguration(Configuration) + .EnableNoRestore() + .EnableNoBuild() + .SetProcessEnvironmentVariable("prefetched", "false") + ); + + DotNetTest(s => s + .SetProjectFile(Solution) + .SetConfiguration(Configuration) + .EnableNoRestore() + .EnableNoBuild() + .SetProcessEnvironmentVariable("prefetched", "true") + ); + }); + + Target CopyFiles => _ => _ + .DependsOn(Compile) + .Executes(() => + { + foreach (var item in TargetFrameworks) + { + var targetDir = NugetDirectory / "lib" / item; + var srcDir = BuildDirectory / item; + + CopyFile(srcDir / $"{TargetProjectName}.dll", targetDir / $"{TargetProjectName}.dll", FileExistsPolicy.OverwriteIfNewer); + CopyFile(srcDir / $"{TargetProjectName}.pdb", targetDir / $"{TargetProjectName}.pdb", FileExistsPolicy.OverwriteIfNewer); + CopyFile(srcDir / $"{TargetProjectName}.xml", targetDir / $"{TargetProjectName}.xml", FileExistsPolicy.OverwriteIfNewer); + } + + CopyFile(SourceDirectory / $"{TargetProjectName}.nuspec", NugetDirectory / $"{TargetProjectName}.nuspec", FileExistsPolicy.OverwriteIfNewer); + CopyFile(RootDirectory / "logo.png", NugetDirectory / "logo.png", FileExistsPolicy.OverwriteIfNewer); + CopyFile(RootDirectory / "README.md", NugetDirectory / "README.md", FileExistsPolicy.OverwriteIfNewer); + }); + + Target CreatePackage => _ => _ + .DependsOn(CopyFiles) + .Executes(() => + { + var nuspec = NugetDirectory / $"{TargetProjectName}.nuspec"; + + NuGetPack(_ => _ + .SetTargetPath(nuspec) + .SetVersion(Version) + .SetOutputDirectory(NugetDirectory) + .SetSymbols(true) + .SetSymbolPackageFormat("snupkg") + .AddProperty("Configuration", Configuration) + ); + }); + + Target PublishPackage => _ => _ + .DependsOn(CreatePackage) + .DependsOn(RunUnitTests) + .Executes(() => + { + var apiKey = Environment.GetEnvironmentVariable("NUGET_API_KEY"); + + + if (apiKey.IsNullOrEmpty()) + { + throw new BuildAbortedException("Could not resolve the NuGet API key."); + } + + foreach (var nupkg in GlobFiles(NugetDirectory, "*.nupkg")) + { + NuGetPush(s => s + .SetTargetPath(nupkg) + .SetSource("https://api.nuget.org/v3/index.json") + .SetApiKey(apiKey)); + } + }); + + Target PublishPreRelease => _ => _ + .DependsOn(PublishPackage) + .Executes(() => + { + string gitHubToken; + + if (GitHubActions != null) + { + gitHubToken = GitHubActions.Token; + } + else + { + gitHubToken = Environment.GetEnvironmentVariable("GITHUB_TOKEN"); + } + + if (gitHubToken.IsNullOrEmpty()) + { + throw new BuildAbortedException("Could not resolve GitHub token."); + } + + var credentials = new Credentials(gitHubToken); + + GitHubTasks.GitHubClient = new GitHubClient( + new ProductHeaderValue(nameof(NukeBuild)), + new InMemoryCredentialStore(credentials)); + + GitHubTasks.GitHubClient.Repository.Release + .Create("AngleSharp", TargetProjectName, new NewRelease(Version) + { + Name = Version, + Body = String.Join(Environment.NewLine, LatestReleaseNotes.Notes), + Prerelease = true, + TargetCommitish = "devel", + }); + }); + + Target PublishRelease => _ => _ + .DependsOn(PublishPackage) + .Executes(() => + { + string gitHubToken; + + if (GitHubActions != null) + { + gitHubToken = GitHubActions.Token; + } + else + { + gitHubToken = Environment.GetEnvironmentVariable("GITHUB_TOKEN"); + } + + if (gitHubToken.IsNullOrEmpty()) + { + throw new BuildAbortedException("Could not resolve GitHub token."); + } + + var credentials = new Credentials(gitHubToken); + + GitHubTasks.GitHubClient = new GitHubClient( + new ProductHeaderValue(nameof(NukeBuild)), + new InMemoryCredentialStore(credentials)); + + GitHubTasks.GitHubClient.Repository.Release + .Create("AngleSharp", TargetProjectName, new NewRelease(Version) + { + Name = Version, + Body = String.Join(Environment.NewLine, LatestReleaseNotes.Notes), + Prerelease = false, + TargetCommitish = "main", + }); + }); + + Target Package => _ => _ + .DependsOn(RunUnitTests) + .DependsOn(CreatePackage); + + Target Default => _ => _ + .DependsOn(Package); + + Target Publish => _ => _ + .DependsOn(PublishRelease); + + Target PrePublish => _ => _ + .DependsOn(PublishPreRelease); +} diff --git a/nuke/Configuration.cs b/nuke/Configuration.cs new file mode 100644 index 0000000..9c08b1a --- /dev/null +++ b/nuke/Configuration.cs @@ -0,0 +1,16 @@ +using System; +using System.ComponentModel; +using System.Linq; +using Nuke.Common.Tooling; + +[TypeConverter(typeof(TypeConverter))] +public class Configuration : Enumeration +{ + public static Configuration Debug = new Configuration { Value = nameof(Debug) }; + public static Configuration Release = new Configuration { Value = nameof(Release) }; + + public static implicit operator string(Configuration configuration) + { + return configuration.Value; + } +} diff --git a/nuke/Directory.Build.props b/nuke/Directory.Build.props new file mode 100644 index 0000000..e147d63 --- /dev/null +++ b/nuke/Directory.Build.props @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/nuke/Directory.Build.targets b/nuke/Directory.Build.targets new file mode 100644 index 0000000..2532609 --- /dev/null +++ b/nuke/Directory.Build.targets @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/nuke/Extensions/StringExtensions.cs b/nuke/Extensions/StringExtensions.cs new file mode 100644 index 0000000..5dd4b54 --- /dev/null +++ b/nuke/Extensions/StringExtensions.cs @@ -0,0 +1,80 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +// ReSharper disable once CheckNamespace +/// +/// Contains extension methods for . +/// +/// +/// Original from Cake build tool source: +/// https://github.com/cake-build/cake/blob/9828d7b246d332054896e52ba56983822feb3f05/src/Cake.Core/Extensions/StringExtensions.cs +/// +public static class StringExtensions +{ + /// + /// Quotes the specified . + /// + /// The string to quote. + /// A quoted string. + public static string Quote(this string value) + { + if (!IsQuoted(value)) + { + value = string.Concat("\"", value, "\""); + } + + return value; + } + + /// + /// Unquote the specified . + /// + /// The string to unquote. + /// An unquoted string. + public static string UnQuote(this string value) + { + if (IsQuoted(value)) + { + value = value.Trim('"'); + } + + return value; + } + + /// + /// Splits the into lines. + /// + /// The string to split. + /// The lines making up the provided string. + public static string[] SplitLines(this string content) + { + content = NormalizeLineEndings(content); + return content.Split(new[] { "\r\n" }, StringSplitOptions.None); + } + + /// + /// Normalizes the line endings in a . + /// + /// The string to normalize line endings in. + /// A with normalized line endings. + public static string NormalizeLineEndings(this string value) + { + if (value != null) + { + value = value.Replace("\r\n", "\n"); + value = value.Replace("\r", string.Empty); + return value.Replace("\n", "\r\n"); + } + + return string.Empty; + } + + private static bool IsQuoted(this string value) + { + return value.StartsWith("\"", StringComparison.OrdinalIgnoreCase) + && value.EndsWith("\"", StringComparison.OrdinalIgnoreCase); + } +} \ No newline at end of file diff --git a/nuke/ReleaseNotes.cs b/nuke/ReleaseNotes.cs new file mode 100644 index 0000000..01dcdad --- /dev/null +++ b/nuke/ReleaseNotes.cs @@ -0,0 +1,81 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; + +/// +/// Represent release notes. +/// +/// +/// Original from Cake build tool source: +/// https://github.com/cake-build/cake/blob/9828d7b246d332054896e52ba56983822feb3f05/src/Cake.Common/ReleaseNotes.cs +/// +public sealed class ReleaseNotes +{ + private readonly List _notes; + + /// + /// Gets the version. + /// + /// The version. + public SemVersion SemVersion { get; } + + /// + /// Gets the version. + /// + /// The version. + public Version Version { get; } + + /// + /// Gets the release notes. + /// + /// The release notes. + public IReadOnlyList Notes => _notes; + + /// + /// Gets the raw text of the line that was extracted from. + /// + /// The raw text of the Version line. + public string RawVersionLine { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The semantic version. + /// The notes. + /// The raw text of the version line. + public ReleaseNotes(SemVersion semVersion, IEnumerable notes, string rawVersionLine) + : this( + semVersion?.AssemblyVersion ?? throw new ArgumentNullException(nameof(semVersion)), + semVersion, + notes, + rawVersionLine) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The version. + /// The notes. + /// The raw text of the version line. + public ReleaseNotes(Version version, IEnumerable notes, string rawVersionLine) + : this( + version ?? throw new ArgumentNullException(nameof(version)), + new SemVersion(version.Major, version.Minor, version.Build), + notes, + rawVersionLine) + { + } + + private ReleaseNotes(Version version, SemVersion semVersion, IEnumerable notes, string rawVersionLine) + { + Version = version ?? throw new ArgumentNullException(nameof(version)); + SemVersion = semVersion ?? throw new ArgumentNullException(nameof(semVersion)); + RawVersionLine = rawVersionLine; + _notes = new List(notes ?? Enumerable.Empty()); + } +} \ No newline at end of file diff --git a/nuke/ReleaseNotesParser.cs b/nuke/ReleaseNotesParser.cs new file mode 100644 index 0000000..d911c90 --- /dev/null +++ b/nuke/ReleaseNotesParser.cs @@ -0,0 +1,146 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using Microsoft.Build.Exceptions; + +/// +/// The release notes parser. +/// +/// +/// Original from Cake build tool source: +/// https://github.com/cake-build/cake/blob/9828d7b246d332054896e52ba56983822feb3f05/src/Cake.Common/ReleaseNotesParser.cs +/// +public sealed class ReleaseNotesParser +{ + /// + /// Parses all release notes. + /// + /// The content. + /// All release notes. + public IReadOnlyList Parse(string content) + { + if (content == null) + { + throw new ArgumentNullException(nameof(content)); + } + + var lines = content.SplitLines(); + if (lines.Length > 0) + { + var line = lines[0].Trim(); + + if (line.StartsWith("#", StringComparison.OrdinalIgnoreCase)) + { + return ParseComplexFormat(lines); + } + + if (line.StartsWith("*", StringComparison.OrdinalIgnoreCase)) + { + return ParseSimpleFormat(lines); + } + } + + throw new BuildAbortedException("Unknown release notes format."); + } + + private IReadOnlyList ParseComplexFormat(string[] lines) + { + var lineIndex = 0; + var result = new List(); + + while (true) + { + if (lineIndex >= lines.Length) + { + break; + } + + // Create release notes. + var semVer = SemVersion.Zero; + var version = SemVersion.TryParse(lines[lineIndex], out semVer); + if (!version) + { + throw new BuildAbortedException("Could not parse version from release notes header."); + } + + var rawVersionLine = lines[lineIndex]; + + // Increase the line index. + lineIndex++; + + // Parse content. + var notes = new List(); + while (true) + { + // Sanity checks. + if (lineIndex >= lines.Length) + { + break; + } + + if (lines[lineIndex].StartsWith("#", StringComparison.OrdinalIgnoreCase)) + { + break; + } + + // Get the current line. + var line = (lines[lineIndex] ?? string.Empty).Trim('*').Trim(); + if (!string.IsNullOrWhiteSpace(line)) + { + notes.Add(line); + } + + lineIndex++; + } + + result.Add(new ReleaseNotes(semVer, notes, rawVersionLine)); + } + + return result.OrderByDescending(x => x.SemVersion).ToArray(); + } + + private IReadOnlyList ParseSimpleFormat(string[] lines) + { + var lineIndex = 0; + var result = new List(); + + while (true) + { + if (lineIndex >= lines.Length) + { + break; + } + + // Trim the current line. + var line = (lines[lineIndex] ?? string.Empty).Trim('*', ' '); + if (string.IsNullOrWhiteSpace(line)) + { + lineIndex++; + continue; + } + + // Parse header. + var semVer = SemVersion.Zero; + var version = SemVersion.TryParse(lines[lineIndex], out semVer); + if (!version) + { + throw new BuildAbortedException("Could not parse version from release notes header."); + } + + // Parse the description. + line = line.Substring(semVer.ToString().Length).Trim('-', ' '); + + // Add the release notes to the result. + result.Add(new ReleaseNotes(semVer, new[] { line }, line)); + + lineIndex++; + } + + return result.OrderByDescending(x => x.SemVersion).ToArray(); + } +} \ No newline at end of file diff --git a/nuke/SemVersion.cs b/nuke/SemVersion.cs new file mode 100644 index 0000000..4a9a715 --- /dev/null +++ b/nuke/SemVersion.cs @@ -0,0 +1,378 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Globalization; +using System.Text; +using System.Text.RegularExpressions; + +/// +/// Class for representing semantic versions. +/// +/// +/// Original from Cake build tool source: +/// https://github.com/cake-build/cake/blob/9828d7b246d332054896e52ba56983822feb3f05/src/Cake.Common/SemanticVersion.cs +/// +public class SemVersion : IComparable, IComparable, IEquatable +{ + /// + /// Gets the default version of a SemanticVersion. + /// + public static SemVersion Zero { get; } = new SemVersion(0, 0, 0, null, null, "0.0.0"); + + /// + /// Regex property for parsing a semantic version number. + /// + public static readonly Regex SemVerRegex = + new Regex( + @"(?0|(?:[1-9]\d*))(?:\.(?0|(?:[1-9]\d*))(?:\.(?0|(?:[1-9]\d*)))?(?:\-(?[0-9A-Z\.-]+))?(?:\+(?[0-9A-Z\.-]+))?)?", + RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase); + + /// + /// Gets the major number of the version. + /// + public int Major { get; } + + /// + /// Gets the minor number of the version. + /// + public int Minor { get; } + + /// + /// Gets the patch number of the version. + /// + public int Patch { get; } + + /// + /// Gets the prerelease of the version. + /// + public string PreRelease { get; } + + /// + /// Gets the meta of the version. + /// + public string Meta { get; } + + /// + /// Gets a value indicating whether semantic version is a prerelease or not. + /// + public bool IsPreRelease { get; } + + /// + /// Gets a value indicating whether semantic version has meta or not. + /// + public bool HasMeta { get; } + + /// + /// Gets the VersionString of the semantic version. + /// + public string VersionString { get; } + + /// + /// Gets the AssemblyVersion of the semantic version. + /// + public Version AssemblyVersion { get; } + + /// + /// Initializes a new instance of the class. + /// + /// Major number. + /// Minor number. + /// Patch number. + /// Prerelease string. + /// Meta string. + public SemVersion(int major, int minor, int patch, string preRelease = null, string meta = null) : this(major, + minor, patch, preRelease, meta, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Major number. + /// Minor number. + /// Patch number. + /// Prerelease string. + /// Meta string. + /// The complete version number. + public SemVersion(int major, int minor, int patch, string preRelease, string meta, string versionString) + { + Major = major; + Minor = minor; + Patch = patch; + AssemblyVersion = new Version(major, minor, patch); + IsPreRelease = !string.IsNullOrEmpty(preRelease); + HasMeta = !string.IsNullOrEmpty(meta); + PreRelease = IsPreRelease ? preRelease : null; + Meta = HasMeta ? meta : null; + + if (!string.IsNullOrEmpty(versionString)) + { + VersionString = versionString; + } + else + { + var sb = new StringBuilder(); + sb.AppendFormat(CultureInfo.InvariantCulture, "{0}.{1}.{2}", Major, Minor, Patch); + + if (IsPreRelease) + { + sb.AppendFormat(CultureInfo.InvariantCulture, "-{0}", PreRelease); + } + + if (HasMeta) + { + sb.AppendFormat(CultureInfo.InvariantCulture, "+{0}", Meta); + } + + VersionString = sb.ToString(); + } + } + + /// + /// Method which tries to parse a semantic version string. + /// + /// the version that should be parsed. + /// the out parameter the parsed version should be stored in. + /// Returns a boolean indicating if the parse was successful. + public static bool TryParse(string version, + out SemVersion semVersion) + { + semVersion = Zero; + + if (string.IsNullOrEmpty(version)) + { + return false; + } + + var match = SemVerRegex.Match(version); + if (!match.Success) + { + return false; + } + + if (!int.TryParse( + match.Groups["Major"].Value, + NumberStyles.Integer, + CultureInfo.InvariantCulture, + out var major) || + !int.TryParse( + match.Groups["Minor"].Value, + NumberStyles.Integer, + CultureInfo.InvariantCulture, + out var minor) || + !int.TryParse( + match.Groups["Patch"].Value, + NumberStyles.Integer, + CultureInfo.InvariantCulture, + out var patch)) + { + return false; + } + + semVersion = new SemVersion( + major, + minor, + patch, + match.Groups["PreRelease"]?.Value, + match.Groups["Meta"]?.Value, + version); + + return true; + } + + /// + /// Checks if two SemVersion objects are equal. + /// + /// the other SemVersion want to test equality to. + /// A boolean indicating whether the objecst we're equal or not. + public bool Equals(SemVersion other) + { + return other is object + && Major == other.Major + && Minor == other.Minor + && Patch == other.Patch + && string.Equals(PreRelease, other.PreRelease, StringComparison.OrdinalIgnoreCase) + && string.Equals(Meta, other.Meta, StringComparison.OrdinalIgnoreCase); + } + + /// + /// Compares to SemVersion objects to and another. + /// + /// The SemVersion object we compare with. + /// Return 0 if the objects are identical, 1 if the version is newer and -1 if the version is older. + public int CompareTo(SemVersion other) + { + if (other is null) + { + return 1; + } + + if (Equals(other)) + { + return 0; + } + + if (Major > other.Major) + { + return 1; + } + + if (Major < other.Major) + { + return -1; + } + + if (Minor > other.Minor) + { + return 1; + } + + if (Minor < other.Minor) + { + return -1; + } + + if (Patch > other.Patch) + { + return 1; + } + + if (Patch < other.Patch) + { + return -1; + } + + if (IsPreRelease != other.IsPreRelease) + { + return other.IsPreRelease ? 1 : -1; + } + + switch (StringComparer.InvariantCultureIgnoreCase.Compare(PreRelease, other.PreRelease)) + { + case 1: + return 1; + + case -1: + return -1; + + default: + { + return (string.IsNullOrEmpty(Meta) != string.IsNullOrEmpty(other.Meta)) + ? string.IsNullOrEmpty(Meta) ? 1 : -1 + : StringComparer.InvariantCultureIgnoreCase.Compare(Meta, other.Meta); + } + } + } + + /// + /// Compares to SemVersion objects to and another. + /// + /// The object we compare with. + /// Return 0 if the objects are identical, 1 if the version is newer and -1 if the version is older. + public int CompareTo(object obj) + { + return (obj is SemVersion semVersion) + ? CompareTo(semVersion) + : -1; + } + + /// + /// Equals-method for the SemVersion class. + /// + /// the other SemVersion want to test equality to. + /// A boolean indicating whether the objecst we're equal or not. + public override bool Equals(object obj) + { + return (obj is SemVersion semVersion) + && Equals(semVersion); + } + + /// + /// Method for getting the hashcode of the SemVersion object. + /// + /// The hashcode of the SemVersion object. + public override int GetHashCode() + { + unchecked + { + var hashCode = Major; + hashCode = (hashCode * 397) ^ Minor; + hashCode = (hashCode * 397) ^ Patch; + hashCode = (hashCode * 397) ^ + (PreRelease != null ? StringComparer.OrdinalIgnoreCase.GetHashCode(PreRelease) : 0); + hashCode = (hashCode * 397) ^ (Meta != null ? StringComparer.OrdinalIgnoreCase.GetHashCode(Meta) : 0); + return hashCode; + } + } + + /// + /// Returns the string representation of an SemVersion object. + /// + /// The string representation of the object. + public override string ToString() + { + int[] verParts = { Major, Minor, Patch }; + string ver = string.Join(".", verParts); + return $"{ver}{(IsPreRelease ? "-" : string.Empty)}{PreRelease}{Meta}"; + } + + /// + /// The greater than-operator for the SemVersion class. + /// + /// first SemVersion. + /// second. SemVersion. + /// A value indicating if the operand1 was greater than operand2. + public static bool operator >(SemVersion operand1, SemVersion operand2) + => operand1 is { } && operand1.CompareTo(operand2) == 1; + + /// + /// The less than-operator for the SemVersion class. + /// + /// first SemVersion. + /// second. SemVersion. + /// A value indicating if the operand1 was less than operand2. + public static bool operator <(SemVersion operand1, SemVersion operand2) + => operand1 is { } + ? operand1.CompareTo(operand2) == -1 + : operand2 is { }; + + /// + /// The greater than or equal to-operator for the SemVersion class. + /// + /// first SemVersion. + /// second. SemVersion. + /// A value indicating if the operand1 was greater than or equal to operand2. + public static bool operator >=(SemVersion operand1, SemVersion operand2) + => operand1 is { } + ? operand1.CompareTo(operand2) >= 0 + : operand2 is null; + + /// + /// The lesser than or equal to-operator for the SemVersion class. + /// + /// first SemVersion. + /// second. SemVersion. + /// A value indicating if the operand1 was lesser than or equal to operand2. + public static bool operator <=(SemVersion operand1, SemVersion operand2) + => operand1 is null || operand1.CompareTo(operand2) <= 0; + + /// + /// The equal to-operator for the SemVersion class. + /// + /// first SemVersion. + /// second. SemVersion. + /// A value indicating if the operand1 was equal to operand2. + public static bool operator ==(SemVersion operand1, SemVersion operand2) + => operand1?.Equals(operand2) ?? operand2 is null; + + /// + /// The not equal to-operator for the SemVersion class. + /// + /// first SemVersion. + /// second. SemVersion. + /// A value indicating if the operand1 was not equal to operand2. + public static bool operator !=(SemVersion operand1, SemVersion operand2) + => !(operand1?.Equals(operand2) ?? operand2 is null); +} \ No newline at end of file diff --git a/nuke/_build.csproj b/nuke/_build.csproj new file mode 100644 index 0000000..7521e1b --- /dev/null +++ b/nuke/_build.csproj @@ -0,0 +1,21 @@ + + + + Exe + net6.0 + + CS0649;CS0169 + .. + .. + 1 + + + + + + + + + + + diff --git a/src/AngleSharp.Js.Tests/AngleSharp.Js.Tests.csproj b/src/AngleSharp.Js.Tests/AngleSharp.Js.Tests.csproj index 475e1ac..84dd112 100644 --- a/src/AngleSharp.Js.Tests/AngleSharp.Js.Tests.csproj +++ b/src/AngleSharp.Js.Tests/AngleSharp.Js.Tests.csproj @@ -17,12 +17,15 @@ - - - - - - - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + diff --git a/src/AngleSharp.Js.Tests/ComponentTests.cs b/src/AngleSharp.Js.Tests/ComponentTests.cs index 5ba0c4a..0e0072d 100644 --- a/src/AngleSharp.Js.Tests/ComponentTests.cs +++ b/src/AngleSharp.Js.Tests/ComponentTests.cs @@ -1,7 +1,7 @@ namespace AngleSharp.Js.Tests { using AngleSharp.Scripting; - using AngleSharp.Xml; + using Jint; using NUnit.Framework; using System; using System.Threading.Tasks; diff --git a/src/AngleSharp.Js.Tests/Constants.cs b/src/AngleSharp.Js.Tests/Constants.cs index 5dc8d04..d9be29d 100644 --- a/src/AngleSharp.Js.Tests/Constants.cs +++ b/src/AngleSharp.Js.Tests/Constants.cs @@ -265,5 +265,161 @@ static class Constants b,c,d){ob(c)?void 0:n(""200"");null==a||void 0===a._reactInternalFiber?n(""38""):void 0;return Wc(a,b,c,!1,d)},unmountComponentAtNode:function(a){ob(a)?void 0:n(""40"");return a._reactRootContainer?($g(function(){Wc(null,null,a,!1,function(){a._reactRootContainer=null})}),!0):!1},unstable_createPortal:function(){return ch.apply(void 0,arguments)},unstable_batchedUpdates:Zg,unstable_interactiveUpdates:ah,flushSync:function(a,b){w?n(""187""):void 0;var c=z;z=!0;try{return Tg(a,b)}finally{z=c,Z(1073741823,!1)}}, unstable_createRoot:function(a,b){ob(a)?void 0:n(""299"",""unstable_createRoot"");return new nb(a,!0,null!=b&&!0===b.hydrate)},unstable_flushControlled:function(a){var b=z;z=!0;try{Tg(a)}finally{(z=b)||w||Z(1073741823,!1)}},__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED:{Events:[Je,Da,dd,Ae.injectEventPluginsByName,Zc,Qa,function(a){ad(a,xh)},Ve,We,oc,cd]}};(function(a){var b=a.findFiberByHostInstance;return ai(B({},a,{overrideProps:null,currentDispatcherRef:Ma.ReactCurrentDispatcher,findHostInstanceByFiber:function(a){a= tf(a);return null===a?null:a.stateNode},findFiberByHostInstance:function(a){return b?b(a):null}}))})({findFiberByHostInstance:dc,bundleType:0,version:""16.8.6"",rendererPackageName:""react-dom""});var ph={default:oh},qh=ph&&oh||ph;return qh.default||qh});"; + + public static readonly String Bootstrap_5_3_3 = @"/*! * Bootstrap v5.3.3 (https://getbootstrap.com/) * Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ !function(t,e){""object""==typeof exports&&""undefined""!=typeof module?module.exports=e():""function""==typeof define&&define.amd?define(e):(t=""undefined""!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){""use strict"";const t=new Map,e={set(e,i,n){t.has(e)||t.set(e +,new Map);const s=t.get(e);s.has(i)||0===s.size?s.set(i,n):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(e,i)=>t.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i=""transitionend"",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s""#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),s=t=>{t.dispatchEvent(new Event(i))},o=t=>!(!t||""object""!=typeof t)&&(void + 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:""string""==typeof t&&t.length>0?document.querySelector(n(t)):null,a=t=>{if(!o(t)||0===t.getClientRects().length)return!1;const e=""visible""===getComputedStyle(t).getPropertyValue(""visibility""),i=t.closest(""details:not([open])"");if(!i)return e;if(i!==t){const e=t.closest(""summary"");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains(""disabled"")||(void 0!==t.disabled?t.disabled:t.hasAttribute(""disabled"")&&""false""!==t.getAttribute(""disabled"")) +,c=t=>{if(!document.documentElement.attachShadow)return null;if(""function""==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>window.jQuery&&!document.body.hasAttribute(""data-bs-no-jquery"")?window.jQuery:null,f=[],p=()=>""rtl""===document.documentElement.dir,m=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t +,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},""loading""===document.readyState?(f.length||document.addEventListener(""DOMContentLoaded"",(()=>{for(const t of f)t()})),f.push(e)):e()},g=(t,e=[],i=t)=>""function""==typeof t?t(...e):i,_=(t,e,n=!0)=>{if(!n)return void g(t);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split("","")[0],i=i.split("","")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5 +;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),g(t))};e.addEventListener(i,a),setTimeout((()=>{r||s(e)}),o)},b=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,A={};let E=1;const T={mouseenter:""mouseover"",mouseleave:""mouseout""},C=new Set([""click"",""dblclick"",""mouseup"",""mousedown"",""contextmenu"",""mousewheel"",""DOMMouseScroll"",""mouseover"",""mouseout"" +,""mousemove"",""selectstart"",""selectend"",""keydown"",""keypress"",""keyup"",""orientationchange"",""touchstart"",""touchmove"",""touchend"",""touchcancel"",""pointerdown"",""pointermove"",""pointerup"",""pointerleave"",""pointercancel"",""gesturestart"",""gesturechange"",""gestureend"",""focus"",""blur"",""change"",""reset"",""select"",""submit"",""focusin"",""focusout"",""load"",""unload"",""beforeunload"",""resize"",""move"",""DOMContentLoaded"",""readystatechange"",""error"",""abort"",""scroll""]);function O(t,e){return e&&`${e}::${E++}`||t.uidEvent||E++}function + x(t){const e=O(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function k(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function L(t,e,i){const n=""string""==typeof e,s=n?i:e||i;let o=I(t);return C.has(o)||(o=t),[n,s,o]}function S(t,e,i,n,s){if(""string""!=typeof e||!t)return;let[o,r,a]=L(e,i,n);if(e in T){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const + l=x(t),c=l[a]||(l[a]={}),h=k(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=O(r,e.replace(v,"""")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return P(s,{delegateTarget:r}),n.oneOff&&N.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return P(n,{delegateTarget:t}),i.oneOff&&N.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s +,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function D(t,e,i,n,s){const o=k(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function $(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&D(t,e,i,r.callable,r.delegationSelector)}function I(t){return t=t.replace(y,""""),T[t]||t}const N={on(t,e,i,n){S(t,e,i,n,!1)},one(t,e,i,n){S(t,e,i,n,!0)},off(t,e,i,n){if(""string""!=typeof e||!t)return;const[s,o,r]=L(e,i,n),a=r!==e,l=x(t),c=l[r]||{},h=e.startsWith(""."") +;if(void 0===o){if(h)for(const i of Object.keys(l))$(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(w,"""");a&&!e.includes(s)||D(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;D(t,l,r,o,s?i:null)}},trigger(t,e,i){if(""string""!=typeof e||!t)return null;const n=u();let s=null,o=!0,r=!0,a=!1;e!==I(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=P(new Event(e +,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function P(t,e={}){for(const[i,n]of Object.entries(e))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}function j(t){if(""true""===t)return!0;if(""false""===t)return!1;if(t===Number(t).toString())return Number(t);if(""""===t||""null""===t)return null;if(""string""!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function + M(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const F={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${M(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${M(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith(""bs"")&&!t.startsWith(""bsConfig"")));for(const n of i){let i=n.replace(/^bs/,"""");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=j(t.dataset[n])}return e},getDataAttribute:(t,e)=>j(t.getAttribute(`data-bs-${M(e)}`))} +;class H{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method ""NAME"", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=o(e)?F.getDataAttribute(e,""config""):{};return{...this.constructor.Default,...""object""==typeof i?i:{},...o(e)?F.getDataAttributes(e):{},...""object""==typeof t?t:{}}}_typeCheckConfig(t +,e=this.constructor.DefaultType){for(const[n,s]of Object.entries(e)){const e=t[n],r=o(e)?""element"":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(s).test(r))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option ""${n}"" provided type ""${r}"" but expected type ""${s}"".`)}var i}}class W extends H{constructor(t,i){super(),(t=r(t))&&(this._element=t,this._config=this._getConfig(i),e.set(this._element,this.constructor.DATA_KEY,this))}dispose(){e.remove(this._element +,this.constructor.DATA_KEY),N.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){_(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return e.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,""object""==typeof e?e:null)}static get VERSION(){return""5.3.3""}static get DATA_KEY(){return`bs.${this.NAME}`}static + get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const B=t=>{let e=t.getAttribute(""data-bs-target"");if(!e||""#""===e){let i=t.getAttribute(""href"");if(!i||!i.includes(""#"")&&!i.startsWith("".""))return null;i.includes(""#"")&&!i.startsWith(""#"")&&(i=`#${i.split(""#"")[1]}`),e=i&&""#""!==i?i.trim():null}return e?e.split("","").map((t=>n(t))).join("",""):null},z={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e +,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=[""a"",""button"",""input"",""textarea"",""select"",""details"",""[tabindex]"",'[contenteditable=""true""]'].map((t=>`${t}:not([tabindex^=""-""])`)) +.join("","");return this.find(e,t).filter((t=>!l(t)&&a(t)))},getSelectorFromElement(t){const e=B(t);return e&&z.findOne(e)?e:null},getElementFromSelector(t){const e=B(t);return e?z.findOne(e):null},getMultipleElementsFromSelector(t){const e=B(t);return e?z.find(e):[]}},R=(t,e=""hide"")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;N.on(document,i,`[data-bs-dismiss=""${n}""]`,(function(i){if([""A"",""AREA""].includes(this.tagName)&&i.preventDefault(),l(this))return;const s=z.getElementFromSelector(this)||this.closest(`.${n}`) +;t.getOrCreateInstance(s)[e]()}))},q="".bs.alert"",V=`close${q}`,K=`closed${q}`;class Q extends W{static get NAME(){return""alert""}close(){if(N.trigger(this._element,V).defaultPrevented)return;this._element.classList.remove(""show"");const t=this._element.classList.contains(""fade"");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),N.trigger(this._element,K),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=Q.getOrCreateInstance(this) +;if(""string""==typeof t){if(void 0===e[t]||t.startsWith(""_"")||""constructor""===t)throw new TypeError(`No method named ""${t}""`);e[t](this)}}))}}R(Q,""close""),m(Q);const X='[data-bs-toggle=""button""]';class Y extends W{static get NAME(){return""button""}toggle(){this._element.setAttribute(""aria-pressed"",this._element.classList.toggle(""active""))}static jQueryInterface(t){return this.each((function(){const e=Y.getOrCreateInstance(this);""toggle""===t&&e[t]()}))}}N.on(document,""click.bs.button.data-api"",X,(t=>{t.preventDefault() +;const e=t.target.closest(X);Y.getOrCreateInstance(e).toggle()})),m(Y);const U="".bs.swipe"",G=`touchstart${U}`,J=`touchmove${U}`,Z=`touchend${U}`,tt=`pointerdown${U}`,et=`pointerup${U}`,it={endCallback:null,leftCallback:null,rightCallback:null},nt={endCallback:""(function|null)"",leftCallback:""(function|null)"",rightCallback:""(function|null)""};class st extends H{constructor(t,e){super(),this._element=t,t&&st.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent) +,this._initEvents())}static get Default(){return it}static get DefaultType(){return nt}static get NAME(){return""swipe""}dispose(){N.off(this._element,U)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),g(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const + t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&g(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(N.on(this._element,tt,(t=>this._start(t))),N.on(this._element,et,(t=>this._end(t))),this._element.classList.add(""pointer-event"")):(N.on(this._element,G,(t=>this._start(t))),N.on(this._element,J,(t=>this._move(t))),N.on(this._element,Z,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&(""pen""===t.pointerType||""touch""===t.pointerType)}static + isSupported(){return""ontouchstart""in document.documentElement||navigator.maxTouchPoints>0}}const ot="".bs.carousel"",rt="".data-api"",at=""next"",lt=""prev"",ct=""left"",ht=""right"",dt=`slide${ot}`,ut=`slid${ot}`,ft=`keydown${ot}`,pt=`mouseenter${ot}`,mt=`mouseleave${ot}`,gt=`dragstart${ot}`,_t=`load${ot}${rt}`,bt=`click${ot}${rt}`,vt=""carousel"",yt=""active"",wt="".active"",At="".carousel-item"",Et=wt+At,Tt={ArrowLeft:ht,ArrowRight:ct},Ct={interval:5e3,keyboard:!0,pause:""hover"",ride:!1,touch:!0,wrap:!0},Ot={interval:""(number|boolean)"" +,keyboard:""boolean"",pause:""(string|boolean)"",ride:""(boolean|string)"",touch:""boolean"",wrap:""boolean""};class xt extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=z.findOne("".carousel-indicators"",this._element),this._addEventListeners(),this._config.ride===vt&&this.cycle()}static get Default(){return Ct}static get DefaultType(){return Ot}static get NAME(){return""carousel""}next(){this._slide(at)}nextWhenVisible(){!document.hidden&&a(this._element)&&this.next()}prev(){this._slide(lt)}pause(){this._isSliding&&s(this._element) +,this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?N.one(this._element,ut,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void N.one(this._element,ut,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?at:lt;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose() +,super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&N.on(this._element,ft,(t=>this._keydown(t))),""hover""===this._config.pause&&(N.on(this._element,pt,(()=>this.pause())),N.on(this._element,mt,(()=>this._maybeEnableCycle()))),this._config.touch&&st.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of z.find("".carousel-item img"",this._element))N.on(t,gt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(ct)) +,rightCallback:()=>this._slide(this._directionToOrder(ht)),endCallback:()=>{""hover""===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new st(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=Tt[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return +;const e=z.findOne(wt,this._indicatorsElement);e.classList.remove(yt),e.removeAttribute(""aria-current"");const i=z.findOne(`[data-bs-slide-to=""${t}""]`,this._indicatorsElement);i&&(i.classList.add(yt),i.setAttribute(""aria-current"",""true""))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute(""data-bs-interval""),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive() +,n=t===at,s=e||b(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>N.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(dt).defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?""carousel-item-start"":""carousel-item-end"",c=n?""carousel-item-next"":""carousel-item-prev"";s.classList.add(c) +,d(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,c),s.classList.add(yt),i.classList.remove(yt,c,l),this._isSliding=!1,r(ut)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains(""slide"")}_getActive(){return z.findOne(Et,this._element)}_getItems(){return z.find(At,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===ct?lt:at:t===ct?at:lt}_orderToDirection(t){return + p()?t===lt?ct:ht:t===lt?ht:ct}static jQueryInterface(t){return this.each((function(){const e=xt.getOrCreateInstance(this,t);if(""number""!=typeof t){if(""string""==typeof t){if(void 0===e[t]||t.startsWith(""_"")||""constructor""===t)throw new TypeError(`No method named ""${t}""`);e[t]()}}else e.to(t)}))}}N.on(document,bt,""[data-bs-slide], [data-bs-slide-to]"",(function(t){const e=z.getElementFromSelector(this);if(!e||!e.classList.contains(vt))return;t.preventDefault();const i=xt.getOrCreateInstance(e),n=this.getAttribute(""data-bs-slide-to"") +;return n?(i.to(n),void i._maybeEnableCycle()):""next""===F.getDataAttribute(this,""slide"")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),N.on(window,_t,(()=>{const t=z.find('[data-bs-ride=""carousel""]');for(const e of t)xt.getOrCreateInstance(e)})),m(xt);const kt="".bs.collapse"",Lt=`show${kt}`,St=`shown${kt}`,Dt=`hide${kt}`,$t=`hidden${kt}`,It=`click${kt}.data-api`,Nt=""show"",Pt=""collapse"",jt=""collapsing"",Mt=`:scope .${Pt} .${Pt}`,Ft='[data-bs-toggle=""collapse""]',Ht={parent:null +,toggle:!0},Wt={parent:""(null|element)"",toggle:""boolean""};class Bt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=z.find(Ft);for(const t of i){const e=z.getSelectorFromElement(t),i=z.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Ht}static + get DefaultType(){return Wt}static get NAME(){return""collapse""}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren("".collapse.show, .collapse.collapsing"").filter((t=>t!==this._element)).map((t=>Bt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(N.trigger(this._element,Lt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension() +;this._element.classList.remove(Pt),this._element.classList.add(jt),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(jt),this._element.classList.add(Pt,Nt),this._element.style[e]="""",N.trigger(this._element,St)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return +;if(N.trigger(this._element,Dt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,d(this._element),this._element.classList.add(jt),this._element.classList.remove(Pt,Nt);for(const t of this._triggerArray){const e=z.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="""",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(jt) +,this._element.classList.add(Pt),N.trigger(this._element,$t)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(Nt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=r(t.parent),t}_getDimension(){return this._element.classList.contains(""collapse-horizontal"")?""width"":""height""}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Ft);for(const e of t){const t=z.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const + e=z.find(Mt,this._config.parent);return z.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle(""collapsed"",!e),i.setAttribute(""aria-expanded"",e)}static jQueryInterface(t){const e={};return""string""==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Bt.getOrCreateInstance(this,e);if(""string""==typeof t){if(void 0===i[t])throw new TypeError(`No method named ""${t}""`);i[t]()}}))}}N.on(document,It +,Ft,(function(t){(""A""===t.target.tagName||t.delegateTarget&&""A""===t.delegateTarget.tagName)&&t.preventDefault();for(const t of z.getMultipleElementsFromSelector(this))Bt.getOrCreateInstance(t,{toggle:!1}).toggle()})),m(Bt);var zt=""top"",Rt=""bottom"",qt=""right"",Vt=""left"",Kt=""auto"",Qt=[zt,Rt,qt,Vt],Xt=""start"",Yt=""end"",Ut=""clippingParents"",Gt=""viewport"",Jt=""popper"",Zt=""reference"",te=Qt.reduce((function(t,e){return t.concat([e+""-""+Xt,e+""-""+Yt])}),[]),ee=[].concat(Qt,[Kt]).reduce((function(t,e){return t.concat([e +,e+""-""+Xt,e+""-""+Yt])}),[]),ie=""beforeRead"",ne=""read"",se=""afterRead"",oe=""beforeMain"",re=""main"",ae=""afterMain"",le=""beforeWrite"",ce=""write"",he=""afterWrite"",de=[ie,ne,se,oe,re,ae,le,ce,he];function ue(t){return t?(t.nodeName||"""").toLowerCase():null}function fe(t){if(null==t)return window;if(""[object Window]""!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function pe(t){return t instanceof fe(t).Element||t instanceof Element}function me(t){return t instanceof fe(t).HTMLElement||t + instanceof HTMLElement}function ge(t){return""undefined""!=typeof ShadowRoot&&(t instanceof fe(t).ShadowRoot||t instanceof ShadowRoot)}const _e={name:""applyStyles"",enabled:!0,phase:""write"",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];me(s)&&ue(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"""":e)})))}))},effect:function(t){var e=t.state +,i={popper:{position:e.options.strategy,left:""0"",top:""0"",margin:""0""},arrow:{position:""absolute""},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="""",t}),{});me(n)&&ue(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}} +,requires:[""computeStyles""]};function be(t){return t.split(""-"")[0]}var ve=Math.max,ye=Math.min,we=Math.round;function Ae(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map((function(t){return t.brand+""/""+t.version})).join("" ""):navigator.userAgent}function Ee(){return!/^((?!chrome|android).)*safari/i.test(Ae())}function Te(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&me(t)&&(s=t.offsetWidth>0&&we(n.width)/t.offsetWidth||1 +,o=t.offsetHeight>0&&we(n.height)/t.offsetHeight||1);var r=(pe(t)?fe(t):window).visualViewport,a=!Ee()&&i,l=(n.left+(a&&r?r.offsetLeft:0))/s,c=(n.top+(a&&r?r.offsetTop:0))/o,h=n.width/s,d=n.height/o;return{width:h,height:d,top:c,right:l+h,bottom:c+d,left:l,x:l,y:c}}function Ce(t){var e=Te(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Oe(t,e){var i=e.getRootNode&&e.getRootNode() +;if(t.contains(e))return!0;if(i&&ge(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function xe(t){return fe(t).getComputedStyle(t)}function ke(t){return[""table"",""td"",""th""].indexOf(ue(t))>=0}function Le(t){return((pe(t)?t.ownerDocument:t.document)||window.document).documentElement}function Se(t){return""html""===ue(t)?t:t.assignedSlot||t.parentNode||(ge(t)?t.host:null)||Le(t)}function De(t){return me(t)&&""fixed""!==xe(t).position?t.offsetParent:null}function $e(t){for(var + e=fe(t),i=De(t);i&&ke(i)&&""static""===xe(i).position;)i=De(i);return i&&(""html""===ue(i)||""body""===ue(i)&&""static""===xe(i).position)?e:i||function(t){var e=/firefox/i.test(Ae());if(/Trident/i.test(Ae())&&me(t)&&""fixed""===xe(t).position)return null;var i=Se(t);for(ge(i)&&(i=i.host);me(i)&&[""html"",""body""].indexOf(ue(i))<0;){var n=xe(i);if(""none""!==n.transform||""none""!==n.perspective||""paint""===n.contain||-1!==[""transform"",""perspective""].indexOf(n.willChange)||e&&""filter""===n.willChange||e&&n.filter&&""none""!==n.filter)return + i;i=i.parentNode}return null}(t)||e}function Ie(t){return[""top"",""bottom""].indexOf(t)>=0?""x"":""y""}function Ne(t,e,i){return ve(t,ye(e,i))}function Pe(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function je(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const Me={name:""arrow"",enabled:!0,phase:""main"",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=be(i.placement),l=Ie(a),c=[Vt,qt].indexOf(a)>=0?""height"":""width"";if(o&&r){var + h=function(t,e){return Pe(""number""!=typeof(t=""function""==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:je(t,Qt))}(s.padding,i),d=Ce(o),u=""y""===l?zt:Vt,f=""y""===l?Rt:qt,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=$e(o),_=g?""y""===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,A=Ne(v,w,y),E=l;i.modifiersData[n]=((e={})[E]=A,e.centerOffset=A-w,e)}},effect:function(t){var e=t.state,i=t.options.element +,n=void 0===i?""[data-popper-arrow]"":i;null!=n&&(""string""!=typeof n||(n=e.elements.popper.querySelector(n)))&&Oe(e.elements.popper,n)&&(e.elements.arrow=n)},requires:[""popperOffsets""],requiresIfExists:[""preventOverflow""]};function Fe(t){return t.split(""-"")[1]}var He={top:""auto"",right:""auto"",bottom:""auto"",left:""auto""};function We(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=t.isFixed,u=r.x,f=void 0===u?0:u +,p=r.y,m=void 0===p?0:p,g=""function""==typeof h?h({x:f,y:m}):{x:f,y:m};f=g.x,m=g.y;var _=r.hasOwnProperty(""x""),b=r.hasOwnProperty(""y""),v=Vt,y=zt,w=window;if(c){var A=$e(i),E=""clientHeight"",T=""clientWidth"";A===fe(i)&&""static""!==xe(A=Le(i)).position&&""absolute""===a&&(E=""scrollHeight"",T=""scrollWidth""),(s===zt||(s===Vt||s===qt)&&o===Yt)&&(y=Rt,m-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,m*=l?1:-1),s!==Vt&&(s!==zt&&s!==Rt||o!==Yt)||(v=qt,f-=(d&&A===w&&w.visualViewport?w.visualViewport.width:A[T])-n.width +,f*=l?1:-1)}var C,O=Object.assign({position:a},c&&He),x=!0===h?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:we(i*s)/s||0,y:we(n*s)/s||0}}({x:f,y:m},fe(i)):{x:f,y:m};return f=x.x,m=x.y,l?Object.assign({},O,((C={})[y]=b?""0"":"""",C[v]=_?""0"":"""",C.transform=(w.devicePixelRatio||1)<=1?""translate(""+f+""px, ""+m+""px)"":""translate3d(""+f+""px, ""+m+""px, 0)"",C)):Object.assign({},O,((e={})[y]=b?m+""px"":"""",e[v]=_?f+""px"":"""",e.transform="""",e))}const Be={name:""computeStyles"",enabled:!0,phase:""beforeWrite"" +,fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:be(e.placement),variation:Fe(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:""fixed""===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,We(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))) +,null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,We(Object.assign({},c,{offsets:e.modifiersData.arrow,position:""absolute"",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{""data-popper-placement"":e.placement})},data:{}};var ze={passive:!0};const Re={name:""eventListeners"",enabled:!0,phase:""write"",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=fe(e.elements.popper) +,c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener(""scroll"",i.update,ze)})),a&&l.addEventListener(""resize"",i.update,ze),function(){o&&c.forEach((function(t){t.removeEventListener(""scroll"",i.update,ze)})),a&&l.removeEventListener(""resize"",i.update,ze)}},data:{}};var qe={left:""right"",right:""left"",bottom:""top"",top:""bottom""};function Ve(t){return t.replace(/left|right|bottom|top/g,(function(t){return qe[t]}))}var Ke={start:""end"",end:""start""} +;function Qe(t){return t.replace(/start|end/g,(function(t){return Ke[t]}))}function Xe(t){var e=fe(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Ye(t){return Te(Le(t)).left+Xe(t).scrollLeft}function Ue(t){var e=xe(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ge(t){return[""html"",""body"",""#document""].indexOf(ue(t))>=0?t.ownerDocument.body:me(t)&&Ue(t)?t:Ge(Se(t))}function Je(t,e){var i;void 0===e&&(e=[]);var n=Ge(t),s=n===(null==(i=t.ownerDocument)?void + 0:i.body),o=fe(n),r=s?[o].concat(o.visualViewport||[],Ue(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Je(Se(r)))}function Ze(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function ti(t,e,i){return e===Gt?Ze(function(t,e){var i=fe(t),n=Le(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=Ee();(c||!c&&""fixed""===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+Ye(t),y:l}}(t,i)):pe(e)?function(t,e){var + i=Te(t,!1,""fixed""===e);return i.top=i.top+t.clientTop,i.left=i.left+t.clientLeft,i.bottom=i.top+t.clientHeight,i.right=i.left+t.clientWidth,i.width=t.clientWidth,i.height=t.clientHeight,i.x=i.left,i.y=i.top,i}(e,i):Ze(function(t){var e,i=Le(t),n=Xe(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ve(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ve(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Ye(t),l=-n.scrollTop;return""rtl""===xe(s||i).direction&&(a+=ve(i.clientWidth +,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Le(t)))}function ei(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?be(s):null,r=s?Fe(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case zt:e={x:a,y:i.y-n.height};break;case Rt:e={x:a,y:i.y+i.height};break;case qt:e={x:i.x+i.width,y:l};break;case Vt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Ie(o):null;if(null!=c){var h=""y""===c?""height"":""width"";switch(r){case Xt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case + Yt:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ii(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.strategy,r=void 0===o?t.strategy:o,a=i.boundary,l=void 0===a?Ut:a,c=i.rootBoundary,h=void 0===c?Gt:c,d=i.elementContext,u=void 0===d?Jt:d,f=i.altBoundary,p=void 0!==f&&f,m=i.padding,g=void 0===m?0:m,_=Pe(""number""!=typeof g?g:je(g,Qt)),b=u===Jt?Zt:Jt,v=t.rects.popper,y=t.elements[p?b:u],w=function(t,e,i,n){var s=""clippingParents""===e?function(t){var e=Je(Se(t)),i=[""absolute"" +,""fixed""].indexOf(xe(t).position)>=0&&me(t)?$e(t):t;return pe(i)?e.filter((function(t){return pe(t)&&Oe(t,i)&&""body""!==ue(t)})):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce((function(e,i){var s=ti(t,i,n);return e.top=ve(s.top,e.top),e.right=ye(s.right,e.right),e.bottom=ye(s.bottom,e.bottom),e.left=ve(s.left,e.left),e}),ti(t,r,n));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}(pe(y)?y:y.contextElement||Le(t.elements.popper),l,h,r),A=Te(t.elements.reference) +,E=ei({reference:A,element:v,strategy:""absolute"",placement:s}),T=Ze(Object.assign({},v,E)),C=u===Jt?T:A,O={top:w.top-C.top+_.top,bottom:C.bottom-w.bottom+_.bottom,left:w.left-C.left+_.left,right:C.right-w.right+_.right},x=t.modifiersData.offset;if(u===Jt&&x){var k=x[s];Object.keys(O).forEach((function(t){var e=[qt,Rt].indexOf(t)>=0?1:-1,i=[zt,Rt].indexOf(t)>=0?""y"":""x"";O[t]+=k[i]*e}))}return O}function ni(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations +,l=i.allowedAutoPlacements,c=void 0===l?ee:l,h=Fe(n),d=h?a?te:te.filter((function(t){return Fe(t)===h})):Qt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ii(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[be(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const si={name:""flip"",enabled:!0,phase:""main"",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void + 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=be(g),b=l||(_!==g&&p?function(t){if(be(t)===Kt)return[];var e=Ve(t);return[Qe(t),e,Qe(e)]}(g):[Ve(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(be(i)===Kt?ni(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper +,A=new Map,E=!0,T=v[0],C=0;C=0,S=L?""width"":""height"",D=ii(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),$=L?k?qt:Vt:k?Rt:zt;y[S]>w[S]&&($=Ve($));var I=Ve($),N=[];if(o&&N.push(D[x]<=0),a&&N.push(D[$]<=0,D[I]<=0),N.every((function(t){return t}))){T=O,E=!1;break}A.set(O,N)}if(E)for(var P=function(t){var e=v.find((function(e){var i=A.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e +,""break""},j=p?3:1;j>0&&""break""!==P(j);j--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:[""offset""],data:{_skip:!1}};function oi(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function ri(t){return[zt,qt,Rt,Vt].some((function(e){return t[e]>=0}))}const ai={name:""hide"",enabled:!0,phase:""main"",requiresIfExists:[""preventOverflow""],fn:function(t){var e=t.state +,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ii(e,{elementContext:""reference""}),a=ii(e,{altBoundary:!0}),l=oi(r,n),c=oi(a,s,o),h=ri(l),d=ri(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{""data-popper-reference-hidden"":h,""data-popper-escaped"":d})}},li={name:""offset"",enabled:!0,phase:""main"",requires:[""popperOffsets""],fn:function(t){var e=t.state +,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=ee.reduce((function(t,i){return t[i]=function(t,e,i){var n=be(t),s=[Vt,zt].indexOf(n)>=0?-1:1,o=""function""==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[Vt,qt].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},ci={name:""popperOffsets"" +,enabled:!0,phase:""read"",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=ei({reference:e.rects.reference,element:e.rects.popper,strategy:""absolute"",placement:e.placement})},data:{}},hi={name:""preventOverflow"",enabled:!0,phase:""main"",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ii(e,{boundary:l,rootBoundary:c +,padding:d,altBoundary:h}),_=be(e.placement),b=Fe(e.placement),v=!b,y=Ie(_),w=""x""===y?""y"":""x"",A=e.modifiersData.popperOffsets,E=e.rects.reference,T=e.rects.popper,C=""function""==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,O=""number""==typeof C?{mainAxis:C,altAxis:C}:Object.assign({mainAxis:0,altAxis:0},C),x=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,k={x:0,y:0};if(A){if(o){var L,S=""y""===y?zt:Vt,D=""y""===y?Rt:qt,$=""y""===y?""height"":""width"",I=A[y],N=I+g[S],P=I-g[D] +,j=f?-T[$]/2:0,M=b===Xt?E[$]:T[$],F=b===Xt?-T[$]:-E[$],H=e.elements.arrow,W=f&&H?Ce(H):{width:0,height:0},B=e.modifiersData[""arrow#persistent""]?e.modifiersData[""arrow#persistent""].padding:{top:0,right:0,bottom:0,left:0},z=B[S],R=B[D],q=Ne(0,E[$],W[$]),V=v?E[$]/2-j-q-z-O.mainAxis:M-q-z-O.mainAxis,K=v?-E[$]/2+j+q+R+O.mainAxis:F+q+R+O.mainAxis,Q=e.elements.arrow&&$e(e.elements.arrow),X=Q?""y""===y?Q.clientTop||0:Q.clientLeft||0:0,Y=null!=(L=null==x?void 0:x[y])?L:0,U=I+K-Y,G=Ne(f?ye(N,I+V-Y-X):N,I,f?ve(P +,U):P);A[y]=G,k[y]=G-I}if(a){var J,Z=""x""===y?zt:Vt,tt=""x""===y?Rt:qt,et=A[w],it=""y""===w?""height"":""width"",nt=et+g[Z],st=et-g[tt],ot=-1!==[zt,Vt].indexOf(_),rt=null!=(J=null==x?void 0:x[w])?J:0,at=ot?nt:et-E[it]-T[it]-rt+O.altAxis,lt=ot?et+E[it]+T[it]-rt-O.altAxis:st,ct=f&&ot?function(t,e,i){var n=Ne(t,e,i);return n>i?i:n}(at,et,lt):Ne(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:[""offset""]};function di(t,e,i){void 0===i&&(i=!1);var n,s,o=me(e),r=me(e)&&function(t){var + e=t.getBoundingClientRect(),i=we(e.width)/t.offsetWidth||1,n=we(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=Le(e),l=Te(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&((""body""!==ue(e)||Ue(a))&&(c=(n=e)!==fe(n)&&me(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Xe(n)),me(e)?((h=Te(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Ye(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function ui(t){var e=new Map,i=new Set,n=[] +;function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var fi={placement:""bottom"",modifiers:[],strategy:""absolute""};function pi(){for(var t=arguments.length,e=new Array(t),i=0;iNumber.parseInt(t,10))):""function""==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:""preventOverflow"",options:{boundary:this._config.boundary}},{name:""offset"",options:{offset:this._getOffset()}}]};return(this._inNavbar||""static""===this._config.display)&&(F.setDataAttribute(this._menu +,""popper"",""static""),t.modifiers=[{name:""applyStyles"",enabled:!1}]),{...t,...g(this._config.popperConfig,[t])}}_selectMenuItem({key:t,target:e}){const i=z.find("".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)"",this._menu).filter((t=>a(t)));i.length&&b(i,e,t===Ti,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=qi.getOrCreateInstance(this,t);if(""string""==typeof t){if(void 0===e[t])throw new TypeError(`No method named ""${t}""`);e[t]()}}))}static clearMenus(t){if(2===t.button||""keyup""===t.type&&""Tab""!==t.key)return +;const e=z.find(Ni);for(const i of e){const e=qi.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||""inside""===e._config.autoClose&&!s||""outside""===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&(""keyup""===t.type&&""Tab""===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};""click""===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const + e=/input|textarea/i.test(t.target.tagName),i=""Escape""===t.key,n=[Ei,Ti].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(Ii)?this:z.prev(this,Ii)[0]||z.next(this,Ii)[0]||z.findOne(Ii,t.delegateTarget.parentNode),o=qi.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}N.on(document,Si,Ii,qi.dataApiKeydownHandler),N.on(document,Si,Pi,qi.dataApiKeydownHandler),N.on(document +,Li,qi.clearMenus),N.on(document,Di,qi.clearMenus),N.on(document,Li,Ii,(function(t){t.preventDefault(),qi.getOrCreateInstance(this).toggle()})),m(qi);const Vi=""backdrop"",Ki=""show"",Qi=`mousedown.bs.${Vi}`,Xi={className:""modal-backdrop"",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:""body""},Yi={className:""string"",clickCallback:""(function|null)"",isAnimated:""boolean"",isVisible:""boolean"",rootElement:""(element|string)""};class Ui extends H{constructor(t){super(),this._config=this._getConfig(t) +,this._isAppended=!1,this._element=null}static get Default(){return Xi}static get DefaultType(){return Yi}static get NAME(){return Vi}show(t){if(!this._config.isVisible)return void g(t);this._append();const e=this._getElement();this._config.isAnimated&&d(e),e.classList.add(Ki),this._emulateAnimation((()=>{g(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(Ki),this._emulateAnimation((()=>{this.dispose(),g(t)}))):g(t)}dispose(){this._isAppended&&(N.off(this._element,Qi),this._element.remove() +,this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement(""div"");t.className=this._config.className,this._config.isAnimated&&t.classList.add(""fade""),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=r(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),N.on(t,Qi,(()=>{g(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){_(t,this._getElement(),this._config.isAnimated)}}const + Gi="".bs.focustrap"",Ji=`focusin${Gi}`,Zi=`keydown.tab${Gi}`,tn=""backward"",en={autofocus:!0,trapElement:null},nn={autofocus:""boolean"",trapElement:""element""};class sn extends H{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return en}static get DefaultType(){return nn}static get NAME(){return""focustrap""}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),N.off(document,Gi),N.on(document,Ji +,(t=>this._handleFocusin(t))),N.on(document,Zi,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,N.off(document,Gi))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=z.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===tn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){""Tab""===t.key&&(this._lastTabNavDirection=t.shiftKey?tn:""forward"")}}const +on="".fixed-top, .fixed-bottom, .is-fixed, .sticky-top"",rn="".sticky-top"",an=""padding-right"",ln=""margin-right"";class cn{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,an,(e=>e+t)),this._setElementAttributes(on,an,(e=>e+t)),this._setElementAttributes(rn,ln,(e=>e-t))}reset(){this._resetElementAttributes(this._element,""overflow""),this._resetElementAttributes(this._element +,an),this._resetElementAttributes(on,an),this._resetElementAttributes(rn,ln)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,""overflow""),this._element.style.overflow=""hidden""}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)}))}_saveInitialAttribute(t +,e){const i=t.style.getPropertyValue(e);i&&F.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=F.getDataAttribute(t,e);null!==i?(F.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(o(t))e(t);else for(const i of z.find(t,this._element))e(i)}}const hn="".bs.modal"",dn=`hide${hn}`,un=`hidePrevented${hn}`,fn=`hidden${hn}`,pn=`show${hn}`,mn=`shown${hn}`,gn=`resize${hn}`,_n=`click.dismiss${hn}` +,bn=`mousedown.dismiss${hn}`,vn=`keydown.dismiss${hn}`,yn=`click${hn}.data-api`,wn=""modal-open"",An=""show"",En=""modal-static"",Tn={backdrop:!0,focus:!0,keyboard:!0},Cn={backdrop:""(boolean|string)"",focus:""boolean"",keyboard:""boolean""};class On extends W{constructor(t,e){super(t,e),this._dialog=z.findOne("".modal-dialog"",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new cn,this._addEventListeners()}static + get Default(){return Tn}static get DefaultType(){return Cn}static get NAME(){return""modal""}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||N.trigger(this._element,pn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(wn),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(N.trigger(this._element,dn).defaultPrevented||(this._isShown=!1 +,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(An),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){N.off(window,hn),N.off(this._dialog,hn),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ui({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element) +,this._element.style.display=""block"",this._element.removeAttribute(""aria-hidden""),this._element.setAttribute(""aria-modal"",!0),this._element.setAttribute(""role"",""dialog""),this._element.scrollTop=0;const e=z.findOne("".modal-body"",this._dialog);e&&(e.scrollTop=0),d(this._element),this._element.classList.add(An),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,N.trigger(this._element,mn,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){N.on(this._element +,vn,(t=>{""Escape""===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),N.on(window,gn,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),N.on(this._element,bn,(t=>{N.one(this._element,_n,(e=>{this._element===t.target&&this._element===e.target&&(""static""!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display=""none"",this._element.setAttribute(""aria-hidden"",!0),this._element.removeAttribute(""aria-modal"") +,this._element.removeAttribute(""role""),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(wn),this._resetAdjustments(),this._scrollBar.reset(),N.trigger(this._element,fn)}))}_isAnimated(){return this._element.classList.contains(""fade"")}_triggerBackdropTransition(){if(N.trigger(this._element,un).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;""hidden""===e||this._element.classList.contains(En)||(t||(this._element.style.overflowY=""hidden"") +,this._element.classList.add(En),this._queueCallback((()=>{this._element.classList.remove(En),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?""paddingLeft"":""paddingRight"";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?""paddingRight"":""paddingLeft"";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="""" +,this._element.style.paddingRight=""""}static jQueryInterface(t,e){return this.each((function(){const i=On.getOrCreateInstance(this,t);if(""string""==typeof t){if(void 0===i[t])throw new TypeError(`No method named ""${t}""`);i[t](e)}}))}}N.on(document,yn,'[data-bs-toggle=""modal""]',(function(t){const e=z.getElementFromSelector(this);[""A"",""AREA""].includes(this.tagName)&&t.preventDefault(),N.one(e,pn,(t=>{t.defaultPrevented||N.one(e,fn,(()=>{a(this)&&this.focus()}))}));const i=z.findOne("".modal.show"");i&&On.getInstance(i).hide() +,On.getOrCreateInstance(e).toggle(this)})),R(On),m(On);const xn="".bs.offcanvas"",kn="".data-api"",Ln=`load${xn}${kn}`,Sn=""show"",Dn=""showing"",$n=""hiding"",In="".offcanvas.show"",Nn=`show${xn}`,Pn=`shown${xn}`,jn=`hide${xn}`,Mn=`hidePrevented${xn}`,Fn=`hidden${xn}`,Hn=`resize${xn}`,Wn=`click${xn}${kn}`,Bn=`keydown.dismiss${xn}`,zn={backdrop:!0,keyboard:!0,scroll:!1},Rn={backdrop:""(boolean|string)"",keyboard:""boolean"",scroll:""boolean""};class qn extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop() +,this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return zn}static get DefaultType(){return Rn}static get NAME(){return""offcanvas""}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||N.trigger(this._element,Nn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new cn).hide(),this._element.setAttribute(""aria-modal"",!0),this._element.setAttribute(""role"",""dialog""),this._element.classList.add(Dn) +,this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(Sn),this._element.classList.remove(Dn),N.trigger(this._element,Pn,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(N.trigger(this._element,jn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add($n),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(Sn,$n),this._element.removeAttribute(""aria-modal"") +,this._element.removeAttribute(""role""),this._config.scroll||(new cn).reset(),N.trigger(this._element,Fn)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Ui({className:""offcanvas-backdrop"",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{""static""!==this._config.backdrop?this.hide():N.trigger(this._element,Mn)}:null})}_initializeFocusTrap(){return + new sn({trapElement:this._element})}_addEventListeners(){N.on(this._element,Bn,(t=>{""Escape""===t.key&&(this._config.keyboard?this.hide():N.trigger(this._element,Mn))}))}static jQueryInterface(t){return this.each((function(){const e=qn.getOrCreateInstance(this,t);if(""string""==typeof t){if(void 0===e[t]||t.startsWith(""_"")||""constructor""===t)throw new TypeError(`No method named ""${t}""`);e[t](this)}}))}}N.on(document,Wn,'[data-bs-toggle=""offcanvas""]',(function(t){const e=z.getElementFromSelector(this) +;if([""A"",""AREA""].includes(this.tagName)&&t.preventDefault(),l(this))return;N.one(e,Fn,(()=>{a(this)&&this.focus()}));const i=z.findOne(In);i&&i!==e&&qn.getInstance(i).hide(),qn.getOrCreateInstance(e).toggle(this)})),N.on(window,Ln,(()=>{for(const t of z.find(In))qn.getOrCreateInstance(t).show()})),N.on(window,Hn,(()=>{for(const t of z.find(""[aria-modal][class*=show][class*=offcanvas-]""))""fixed""!==getComputedStyle(t).position&&qn.getOrCreateInstance(t).hide()})),R(qn),m(qn);const Vn={""*"":[""class"" +,""dir"",""id"",""lang"",""role"",/^aria-[\w-]*$/i],a:[""target"",""href"",""title"",""rel""],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:[""src"",""srcset"",""alt"",""title"",""width"",""height""],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Kn=new Set([""background"",""cite"",""href"",""itemtype"",""longdesc"",""poster"",""src"",""xlink:href""]),Qn=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Xn=(t,e)=>{const i=t.nodeName.toLowerCase() +;return e.includes(i)?!Kn.has(i)||Boolean(Qn.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Yn={allowList:Vn,content:{},extraClass:"""",html:!1,sanitize:!0,sanitizeFn:null,template:""
""},Un={allowList:""object"",content:""object"",extraClass:""(string|function)"",html:""boolean"",sanitize:""boolean"",sanitizeFn:""(null|function)"",template:""string""},Gn={entry:""(string|element|function|null)"",selector:""(string|element)""};class Jn extends H{constructor(t){super(),this._config=this._getConfig(t)}static + get Default(){return Yn}static get DefaultType(){return Un}static get NAME(){return""TemplateFactory""}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement(""div"");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t +,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split("" "")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},Gn)}_setContent(t,e,i){const n=z.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?o(e)?this._putElementInTemplate(r(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return + this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&""function""==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,""text/html""),s=[].concat(...n.body.querySelectorAll(""*""));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e[""*""]||[],e[i]||[]);for(const e of n)Xn(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return + g(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="""",void e.append(t);e.textContent=t.textContent}}const Zn=new Set([""sanitize"",""allowList"",""sanitizeFn""]),ts=""fade"",es=""show"",is="".modal"",ns=""hide.bs.modal"",ss=""hover"",os=""focus"",rs={AUTO:""auto"",TOP:""top"",RIGHT:p()?""left"":""right"",BOTTOM:""bottom"",LEFT:p()?""right"":""left""},as={allowList:Vn,animation:!0,boundary:""clippingParents"",container:!1,customClass:"""",delay:0,fallbackPlacements:[""top"",""right"",""bottom"",""left""],html:!1 +,offset:[0,6],placement:""top"",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'
',title:"""",trigger:""hover focus""},ls={allowList:""object"",animation:""boolean"",boundary:""(string|element)"",container:""(string|element|boolean)"",customClass:""(string|function)"",delay:""(number|object)"",fallbackPlacements:""array"",html:""boolean"",offset:""(array|string|function)"",placement:""(string|function)"" +,popperConfig:""(null|object|function)"",sanitize:""boolean"",sanitizeFn:""(null|function)"",selector:""(string|boolean)"",template:""string"",title:""(string|element|function)"",trigger:""string""};class cs extends W{constructor(t,e){if(void 0===vi)throw new TypeError(""Bootstrap's tooltips require Popper (https://popper.js.org)"");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners() +,this._config.selector||this._fixTitle()}static get Default(){return as}static get DefaultType(){return ls}static get NAME(){return""tooltip""}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),N.off(this._element.closest(is),ns,this._hideModalHandler),this._element.getAttribute(""data-bs-original-title"")&&this._element.setAttribute(""title"" +,this._element.getAttribute(""data-bs-original-title"")),this._disposePopper(),super.dispose()}show(){if(""none""===this._element.style.display)throw new Error(""Please use show on visible elements"");if(!this._isWithContent()||!this._isEnabled)return;const t=N.trigger(this._element,this.constructor.eventName(""show"")),e=(c(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute(""aria-describedby"" +,i.getAttribute(""id""));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),N.trigger(this._element,this.constructor.eventName(""inserted""))),this._popper=this._createPopper(i),i.classList.add(es),""ontouchstart""in document.documentElement)for(const t of[].concat(...document.body.children))N.on(t,""mouseover"",h);this._queueCallback((()=>{N.trigger(this._element,this.constructor.eventName(""shown"")),!1===this._isHovered&&this._leave(),this._isHovered=!1}) +,this.tip,this._isAnimated())}hide(){if(this._isShown()&&!N.trigger(this._element,this.constructor.eventName(""hide"")).defaultPrevented){if(this._getTipElement().classList.remove(es),""ontouchstart""in document.documentElement)for(const t of[].concat(...document.body.children))N.off(t,""mouseover"",h);this._activeTrigger.click=!1,this._activeTrigger[os]=!1,this._activeTrigger[ss]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute(""aria-describedby"") +,N.trigger(this._element,this.constructor.eventName(""hidden"")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(ts,es),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t)) +;return t})(this.constructor.NAME).toString();return e.setAttribute(""id"",i),this._isAnimated()&&e.classList.add(ts),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Jn({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{"".tooltip-inner"":this._getTitle()}}_getTitle(){return + this._resolvePossibleFunction(this._config.title)||this._element.getAttribute(""data-bs-original-title"")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(ts)}_isShown(){return this.tip&&this.tip.classList.contains(es)}_createPopper(t){const e=g(this._config.placement,[this,t,this._element]),i=rs[e.toUpperCase()];return bi(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config +;return""string""==typeof t?t.split("","").map((t=>Number.parseInt(t,10))):""function""==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return g(t,[this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:""flip"",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:""offset"",options:{offset:this._getOffset()}},{name:""preventOverflow"",options:{boundary:this._config.boundary}},{name:""arrow"",options:{element:`.${this.constructor.NAME}-arrow`}},{name:""preSetPlacement"" +,enabled:!0,phase:""beforeMain"",fn:t=>{this._getTipElement().setAttribute(""data-popper-placement"",t.state.placement)}}]};return{...e,...g(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split("" "");for(const e of t)if(""click""===e)N.on(this._element,this.constructor.eventName(""click""),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if(""manual""!==e){const t=e===ss?this.constructor.eventName(""mouseenter""):this.constructor.eventName(""focusin"") +,i=e===ss?this.constructor.eventName(""mouseleave""):this.constructor.eventName(""focusout"");N.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger[""focusin""===t.type?os:ss]=!0,e._enter()})),N.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger[""focusout""===t.type?os:ss]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},N.on(this._element.closest(is) +,ns,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute(""title"");t&&(this._element.getAttribute(""aria-label"")||this._element.textContent.trim()||this._element.setAttribute(""aria-label"",t),this._element.setAttribute(""data-bs-original-title"",t),this._element.removeAttribute(""title""))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1 +,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=F.getDataAttributes(this._element);for(const t of Object.keys(e))Zn.has(t)&&delete e[t];return t={...e,...""object""==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:r(t.container) +,""number""==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),""number""==typeof t.title&&(t.title=t.title.toString()),""number""==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger=""manual"",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const + e=cs.getOrCreateInstance(this,t);if(""string""==typeof t){if(void 0===e[t])throw new TypeError(`No method named ""${t}""`);e[t]()}}))}}m(cs);const hs={...cs.Default,content:"""",offset:[0,8],placement:""right"",template:'

',trigger:""click""},ds={...cs.DefaultType,content:""(null|string|element|function)""};class us extends cs{static get Default(){return hs}static get DefaultType(){return + ds}static get NAME(){return""popover""}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{"".popover-header"":this._getTitle(),"".popover-body"":this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=us.getOrCreateInstance(this,t);if(""string""==typeof t){if(void 0===e[t])throw new TypeError(`No method named ""${t}""`);e[t]()}}))}}m(us);const fs="".bs.scrollspy"",ps=`activate${fs}` +,ms=`click${fs}`,gs=`load${fs}.data-api`,_s=""active"",bs=""[href]"",vs="".nav-link"",ys=`${vs}, .nav-item > ${vs}, .list-group-item`,ws={offset:null,rootMargin:""0px 0px -25%"",smoothScroll:!1,target:null,threshold:[.1,.5,1]},As={offset:""(number|null)"",rootMargin:""string"",smoothScroll:""boolean"",target:""element"",threshold:""array""};class Es extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement=""visible""===getComputedStyle(this._element).overflowY?null:this._element +,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return ws}static get DefaultType(){return As}static get NAME(){return""scrollspy""}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect() +,super.dispose()}_configAfterMerge(t){return t.target=r(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,""string""==typeof t.threshold&&(t.threshold=t.threshold.split("","").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(N.off(this._config.target,ms),N.on(this._config.target,ms,bs,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop +;if(i.scrollTo)return void i.scrollTo({top:n,behavior:""smooth""});i.scrollTop=n}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop +;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=z.find(bs,this._config.target);for(const e of t){if(!e.hash||l(e))continue;const t=z.findOne(decodeURI(e.hash),this._element);a(t)&&(this._targetLinks.set(decodeURI(e.hash) +,e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(_s),this._activateParents(t),N.trigger(this._element,ps,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains(""dropdown-item""))z.findOne("".dropdown-toggle"",t.closest("".dropdown"")).classList.add(_s);else for(const e of z.parents(t,"".nav, .list-group""))for(const t of z.prev(e,ys))t.classList.add(_s)}_clearActiveClass(t){t.classList.remove(_s) +;const e=z.find(`${bs}.${_s}`,t);for(const t of e)t.classList.remove(_s)}static jQueryInterface(t){return this.each((function(){const e=Es.getOrCreateInstance(this,t);if(""string""==typeof t){if(void 0===e[t]||t.startsWith(""_"")||""constructor""===t)throw new TypeError(`No method named ""${t}""`);e[t]()}}))}}N.on(window,gs,(()=>{for(const t of z.find('[data-bs-spy=""scroll""]'))Es.getOrCreateInstance(t)})),m(Es);const Ts="".bs.tab"",Cs=`hide${Ts}`,Os=`hidden${Ts}`,xs=`show${Ts}`,ks=`shown${Ts}`,Ls=`click${Ts}` +,Ss=`keydown${Ts}`,Ds=`load${Ts}`,$s=""ArrowLeft"",Is=""ArrowRight"",Ns=""ArrowUp"",Ps=""ArrowDown"",js=""Home"",Ms=""End"",Fs=""active"",Hs=""fade"",Ws=""show"",Bs="".dropdown-toggle"",zs=`:not(${Bs})`,Rs='[data-bs-toggle=""tab""], [data-bs-toggle=""pill""], [data-bs-toggle=""list""]',qs=`.nav-link${zs}, .list-group-item${zs}, [role=""tab""]${zs}, ${Rs}`,Vs=`.${Fs}[data-bs-toggle=""tab""], .${Fs}[data-bs-toggle=""pill""], .${Fs}[data-bs-toggle=""list""]`;class Ks extends W{constructor(t){super(t),this._parent= +this._element.closest('.list-group, .nav, [role=""tablist""]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),N.on(this._element,Ss,(t=>this._keydown(t))))}static get NAME(){return""tab""}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?N.trigger(e,Cs,{relatedTarget:t}):null;N.trigger(t,xs,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(Fs),this._activate(z.getElementFromSelector(t)) +,this._queueCallback((()=>{""tab""===t.getAttribute(""role"")?(t.removeAttribute(""tabindex""),t.setAttribute(""aria-selected"",!0),this._toggleDropDown(t,!0),N.trigger(t,ks,{relatedTarget:e})):t.classList.add(Ws)}),t,t.classList.contains(Hs)))}_deactivate(t,e){t&&(t.classList.remove(Fs),t.blur(),this._deactivate(z.getElementFromSelector(t)),this._queueCallback((()=>{""tab""===t.getAttribute(""role"")?(t.setAttribute(""aria-selected"",!1),t.setAttribute(""tabindex"",""-1""),this._toggleDropDown(t,!1),N.trigger(t,Os +,{relatedTarget:e})):t.classList.remove(Ws)}),t,t.classList.contains(Hs)))}_keydown(t){if(![$s,Is,Ns,Ps,js,Ms].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!l(t)));let i;if([js,Ms].includes(t.key))i=e[t.key===js?0:e.length-1];else{const n=[Is,Ps].includes(t.key);i=b(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Ks.getOrCreateInstance(i).show())}_getChildren(){return z.find(qs,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t +,e){this._setAttributeIfNotExists(t,""role"",""tablist"");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute(""aria-selected"",e),i!==t&&this._setAttributeIfNotExists(i,""role"",""presentation""),e||t.setAttribute(""tabindex"",""-1""),this._setAttributeIfNotExists(t,""role"",""tab""),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=z.getElementFromSelector(t) +;e&&(this._setAttributeIfNotExists(e,""role"",""tabpanel""),t.id&&this._setAttributeIfNotExists(e,""aria-labelledby"",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains(""dropdown""))return;const n=(t,n)=>{const s=z.findOne(t,i);s&&s.classList.toggle(n,e)};n(Bs,Fs),n("".dropdown-menu"",Ws),i.setAttribute(""aria-expanded"",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(Fs)}_getInnerElement(t){return + t.matches(qs)?t:z.findOne(qs,t)}_getOuterElement(t){return t.closest("".nav-item, .list-group-item"")||t}static jQueryInterface(t){return this.each((function(){const e=Ks.getOrCreateInstance(this);if(""string""==typeof t){if(void 0===e[t]||t.startsWith(""_"")||""constructor""===t)throw new TypeError(`No method named ""${t}""`);e[t]()}}))}}N.on(document,Ls,Rs,(function(t){[""A"",""AREA""].includes(this.tagName)&&t.preventDefault(),l(this)||Ks.getOrCreateInstance(this).show()})),N.on(window,Ds,(()=>{for(const t + of z.find(Vs))Ks.getOrCreateInstance(t)})),m(Ks);const Qs="".bs.toast"",Xs=`mouseover${Qs}`,Ys=`mouseout${Qs}`,Us=`focusin${Qs}`,Gs=`focusout${Qs}`,Js=`hide${Qs}`,Zs=`hidden${Qs}`,to=`show${Qs}`,eo=`shown${Qs}`,io=""hide"",no=""show"",so=""showing"",oo={animation:""boolean"",autohide:""boolean"",delay:""number""},ro={animation:!0,autohide:!0,delay:5e3};class ao extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get + Default(){return ro}static get DefaultType(){return oo}static get NAME(){return""toast""}show(){N.trigger(this._element,to).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add(""fade""),this._element.classList.remove(io),d(this._element),this._element.classList.add(no,so),this._queueCallback((()=>{this._element.classList.remove(so),N.trigger(this._element,eo),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(N.trigger(this._element +,Js).defaultPrevented||(this._element.classList.add(so),this._queueCallback((()=>{this._element.classList.add(io),this._element.classList.remove(so,no),N.trigger(this._element,Zs)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(no),super.dispose()}isShown(){return this._element.classList.contains(no)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}) +,this._config.delay)))}_onInteraction(t,e){switch(t.type){case""mouseover"":case""mouseout"":this._hasMouseInteraction=e;break;case""focusin"":case""focusout"":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){N.on(this._element,Xs,(t=>this._onInteraction(t,!0))),N.on(this._element,Ys,(t=>this._onInteraction(t,!1))),N.on(this._element,Us,(t=>this._onInteraction(t,!0))),N.on(this._element +,Gs,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=ao.getOrCreateInstance(this,t);if(""string""==typeof t){if(void 0===e[t])throw new TypeError(`No method named ""${t}""`);e[t](this)}}))}}return R(ao),m(ao),{Alert:Q,Button:Y,Carousel:xt,Collapse:Bt,Dropdown:qi,Modal:On,Offcanvas:qn,Popover:us,ScrollSpy:Es,Tab:Ks,Toast:ao,Tooltip:cs}})); //# sourceMappingURL=bootstrap.bundle.min.js.map"; } } diff --git a/src/AngleSharp.Js.Tests/EcmaTests.cs b/src/AngleSharp.Js.Tests/EcmaTests.cs new file mode 100644 index 0000000..244d7bb --- /dev/null +++ b/src/AngleSharp.Js.Tests/EcmaTests.cs @@ -0,0 +1,21 @@ +namespace AngleSharp.Js.Tests +{ + using NUnit.Framework; + using System; + using System.Threading.Tasks; + + [TestFixture] + public class EcmaTests + { + private static String SetResult(String eval) => + $"document.querySelector('#result').textContent = {eval};"; + + [Test] + public async Task BootstrapVersionFive() + { + var result = await (new[] { Constants.Bootstrap_5_3_3, SetResult("bootstrap.toString()") }).EvalScriptsAsync() + .ConfigureAwait(false); + Assert.AreNotEqual("", result); + } + } +} diff --git a/src/AngleSharp.Js.Tests/FireEventTests.cs b/src/AngleSharp.Js.Tests/FireEventTests.cs index eac505c..cddaf59 100644 --- a/src/AngleSharp.Js.Tests/FireEventTests.cs +++ b/src/AngleSharp.Js.Tests/FireEventTests.cs @@ -3,6 +3,7 @@ namespace AngleSharp.Js.Tests using AngleSharp.Dom; using AngleSharp.Dom.Events; using AngleSharp.Scripting; + using Jint; using NUnit.Framework; using System; @@ -60,11 +61,11 @@ public async Task InvokeLoadEventFromJsAndCustomEventFromJsAndCs() document.AddEventListener("hello", (s, ev) => { - log.Put(log.Get("length").AsNumber().ToString(), "d", false); + log.Set(log.Get("length").AsNumber(), "d", false); }); document.Dispatch(new Event("hello")); - + Assert.AreEqual(4.0, log.Get("length").AsNumber()); Assert.AreEqual("a", log.Get("0").AsString()); Assert.AreEqual("b", log.Get("1").AsString()); diff --git a/src/AngleSharp.Js.Tests/InteractionTests.cs b/src/AngleSharp.Js.Tests/InteractionTests.cs index 8afcdf7..eff1a33 100644 --- a/src/AngleSharp.Js.Tests/InteractionTests.cs +++ b/src/AngleSharp.Js.Tests/InteractionTests.cs @@ -3,6 +3,7 @@ namespace AngleSharp.Js.Tests using AngleSharp.Dom; using AngleSharp.Html.Dom; using AngleSharp.Scripting; + using Jint; using Jint.Runtime; using NUnit.Framework; using System; @@ -30,8 +31,9 @@ public async Task RunJavaScriptFunctionFromCSharp() var cfg = Configuration.Default.With(service); var html = ""; var document = await BrowsingContext.New(cfg).OpenAsync(m => m.Content(html)); - var square = service.GetOrCreateJint(document).GetValue("square"); - var result = square.Invoke(4); + var engine = service.GetOrCreateJint(document); + var square = engine.GetValue("square"); + var result = engine.Invoke(square, 4); Assert.AreEqual(Types.Number, result.Type); Assert.AreEqual(16.0, result.AsNumber()); } diff --git a/src/AngleSharp.Js.Tests/JqueryTests.cs b/src/AngleSharp.Js.Tests/JqueryTests.cs index 3110025..6627c7c 100644 --- a/src/AngleSharp.Js.Tests/JqueryTests.cs +++ b/src/AngleSharp.Js.Tests/JqueryTests.cs @@ -66,7 +66,7 @@ public async Task JqueryWithAjaxToDelayedResponse() var message = "Hi!"; var req = new DelayedRequester(10, message); var cfg = Configuration.Default.WithJs().WithEventLoop().With(req).WithDefaultLoader(); - var sources = new [] { Constants.Jquery2_1_4, @" + var sources = new[] { Constants.Jquery2_1_4, @" $.ajax('http://example.com/', { success: function (data, status, xhr) { var res = document.querySelector('#result'); @@ -87,7 +87,7 @@ public async Task JqueryWithAjaxToDelayedResponse() [Test] public async Task JqueryVersionOne() { - var result = await (new [] { Constants.Jquery1_11_2, SetResult("$.toString()") }).EvalScriptsAsync() + var result = await (new[] { Constants.Jquery1_11_2, SetResult("$.toString()") }).EvalScriptsAsync() .ConfigureAwait(false); Assert.AreNotEqual("", result); } diff --git a/src/AngleSharp.Js.Tests/Mocks/DataRequester.cs b/src/AngleSharp.Js.Tests/Mocks/DataRequester.cs index 75d64c7..19e26c9 100644 --- a/src/AngleSharp.Js.Tests/Mocks/DataRequester.cs +++ b/src/AngleSharp.Js.Tests/Mocks/DataRequester.cs @@ -11,12 +11,12 @@ sealed class DataRequester : BaseRequester { private static readonly String Base64Section = ";base64"; - + public override Boolean SupportsProtocol(String protocol) { return protocol.Is(ProtocolNames.Data); } - + protected override Task PerformRequestAsync(Request request, CancellationToken cancel) { var content = new MemoryStream(); diff --git a/src/AngleSharp.Js/AngleSharp.Js.csproj b/src/AngleSharp.Js/AngleSharp.Js.csproj index 85e35c1..e63eda6 100644 --- a/src/AngleSharp.Js/AngleSharp.Js.csproj +++ b/src/AngleSharp.Js/AngleSharp.Js.csproj @@ -1,9 +1,9 @@ - + AngleSharp.Js AngleSharp.Js netstandard2.0 - netstandard2.0;net46;net461;net472 + netstandard2.0;net462 true Key.snk true @@ -17,12 +17,12 @@ - + - - + + diff --git a/src/AngleSharp.Js/Cache/PrototypeCache.cs b/src/AngleSharp.Js/Cache/PrototypeCache.cs index 52d2136..ffcc2fd 100644 --- a/src/AngleSharp.Js/Cache/PrototypeCache.cs +++ b/src/AngleSharp.Js/Cache/PrototypeCache.cs @@ -14,7 +14,7 @@ public PrototypeCache(Engine engine) { _prototypes = new ConcurrentDictionary { - [typeof(Object)] = engine.Object.PrototypeObject, + [typeof(Object)] = engine.Intrinsics.Object.PrototypeObject, }; _engine = engine; } diff --git a/src/AngleSharp.Js/Converters/DomTypeConverter.cs b/src/AngleSharp.Js/Converters/DomTypeConverter.cs deleted file mode 100644 index 29889fa..0000000 --- a/src/AngleSharp.Js/Converters/DomTypeConverter.cs +++ /dev/null @@ -1,169 +0,0 @@ -namespace AngleSharp.Js -{ - using AngleSharp.Dom; - using AngleSharp.Dom.Events; - using AngleSharp.Html.Dom; - using AngleSharp.Html.Dom.Events; - using AngleSharp.Media.Dom; - using Jint.Native; - using System; - - static class DomTypeConverter - { - public static DomEventHandler ToEventHandler(JsValue arg) - { - return null; - } - - public static MutationCallback ToMutationCallback(JsValue arg) - { - return null; - } - - public static NodeFilter ToNodeFilter(JsValue arg) - { - return null; - } - - public static IAttr ToAttr(JsValue arg) - { - return null; - } - - public static IElement ToElement(JsValue arg) - { - return null; - } - - public static IHtmlElement ToHtmlElement(JsValue arg) - { - return null; - } - - public static IHtmlOptionElement ToOptionElement(JsValue arg) - { - return null; - } - - public static IHtmlTableCaptionElement ToTableCaptionElement(JsValue arg) - { - return null; - } - - public static IHtmlTableSectionElement ToTableSectionElement(JsValue arg) - { - return null; - } - - public static IHtmlMenuElement ToMenuElement(JsValue arg) - { - return null; - } - - public static IHtmlOptionsGroupElement ToOptionsGroupElement(JsValue arg) - { - return null; - } - - public static IEventTarget ToEventTarget(JsValue arg) - { - return null; - } - - public static INode ToNode(JsValue arg) - { - return null; - } - - public static Action ToTimer(JsValue arg) - { - return null; - } - - public static IRenderingContext ToRenderingContext(JsValue arg) - { - return null; - } - - public static IWindow ToWindow(JsValue arg) - { - return null; - } - - public static IDocumentType ToDoctype(JsValue arg) - { - return null; - } - - public static IMessagePort ToMessagePort(JsValue arg) - { - return null; - } - - public static DomException ToDomException(JsValue arg) - { - return null; - } - - public static ITouchList ToTouchList(JsValue arg) - { - return null; - } - - public static ITextTrackCue ToTextTrackCue(JsValue arg) - { - return null; - } - - public static Event ToEvent(JsValue arg) - { - return null; - } - - public static IRange ToRange(JsValue arg) - { - return null; - } - - public static AdjacentPosition ToAdjacentPosition(JsValue arg) - { - return ToEnum(arg); - } - - public static RangeType ToRangeType(JsValue arg) - { - return ToEnum(arg); - } - - public static WheelMode ToWheelMode(JsValue arg) - { - return ToEnum(arg); - } - - public static MouseButton ToMouseButton(JsValue arg) - { - return ToEnum(arg); - } - - public static KeyboardLocation ToKeyboardLocation(JsValue arg) - { - return ToEnum(arg); - } - - public static TextTrackMode ToTextTrackMode(JsValue arg) - { - return ToEnum(arg); - } - - public static FilterSettings ToFilterSettings(JsValue arg) - { - return ToEnum(arg); - } - - public static T ToEnum(JsValue arg) - where T : struct, IComparable - { - return default(T); - } - } -} diff --git a/src/AngleSharp.Js/Converters/SystemTypeConverter.cs b/src/AngleSharp.Js/Converters/SystemTypeConverter.cs deleted file mode 100644 index 76fb70d..0000000 --- a/src/AngleSharp.Js/Converters/SystemTypeConverter.cs +++ /dev/null @@ -1,56 +0,0 @@ -namespace AngleSharp.Js -{ - using Jint.Native; - using Jint.Runtime; - using System; - using System.Collections.Generic; - using System.IO; - - static class SystemTypeConverter - { - public static IDictionary ToObjBag(JsValue arg) - { - var obj = arg.AsObject(); - var dict = new Dictionary(); - var properties = obj.GetOwnProperties(); - - foreach (var property in properties) - { - var value = property.Value.Value.Clr(); - dict.Add(property.Key,value); - } - - return dict; - } - - public static Action ToStreamTask(JsValue arg) - { - return null; - } - - public static Nullable ToOptionalInt32(JsValue arg) - { - if (arg.IsNumber()) - { - return TypeConverter.ToInt32(arg); - } - - return null; - } - - public static Nullable ToOptionalDateTime(JsValue arg) - { - return null; - } - - public static Object ToObject(JsValue arg) - { - return arg.ToObject(); - } - - static Object Clr(this JsValue arg) - { - return arg?.ToObject(); - } - } -} diff --git a/src/AngleSharp.Js/Converters/UnresolvedConverter.cs b/src/AngleSharp.Js/Converters/UnresolvedConverter.cs deleted file mode 100644 index ff3b49f..0000000 --- a/src/AngleSharp.Js/Converters/UnresolvedConverter.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace AngleSharp.Js -{ - using Jint.Native; - - static class UnresolvedConverter - { - public static T To(JsValue arg) - { - return default(T); - } - } -} diff --git a/src/AngleSharp.Js/Dom/Console.cs b/src/AngleSharp.Js/Dom/Console.cs new file mode 100644 index 0000000..5dc3321 --- /dev/null +++ b/src/AngleSharp.Js/Dom/Console.cs @@ -0,0 +1,35 @@ +using AngleSharp.Attributes; +using AngleSharp.Dom; + +namespace AngleSharp.Js.Dom +{ + /// + /// Defines the console. + /// + [DomName("Console")] + public sealed class Console + { + private readonly IConsoleLogger _logger; + + /// + /// Creates a new console. + /// + /// + [DomConstructor] + public Console(IWindow window) + { + var context = window.Document.Context; + _logger = context.GetService(); + } + + /// + /// Outputs a message to the console. + /// + /// + [DomName("log")] + public void Log(params object[] objs) + { + _logger?.Log(objs); + } + } +} diff --git a/src/AngleSharp.Js/Dom/DomParser.cs b/src/AngleSharp.Js/Dom/DomParser.cs index ff7800b..882ed45 100644 --- a/src/AngleSharp.Js/Dom/DomParser.cs +++ b/src/AngleSharp.Js/Dom/DomParser.cs @@ -40,7 +40,7 @@ public IDocument Parse(String str, String type) { var ctx = _window?.Document.Context; var factory = ctx?.GetService() ?? throw new DomException(DomError.NotSupported); - + using (var content = new MemoryStream(TextEncoding.Utf8.GetBytes(str))) { var response = new DefaultResponse diff --git a/src/AngleSharp.Js/Dom/EventAttributeObserver.cs b/src/AngleSharp.Js/Dom/EventAttributeObserver.cs index 3c299e9..55928c4 100644 --- a/src/AngleSharp.Js/Dom/EventAttributeObserver.cs +++ b/src/AngleSharp.Js/Dom/EventAttributeObserver.cs @@ -98,11 +98,9 @@ private void RegisterEventCallback(String eventName) var document = element.Owner; var engine = _service.GetOrCreateInstance(document); var jint = engine.Jint; - jint.EnterExecutionContext(engine.Lexicals, engine.Variables, engine.Window); - var instance = jint.Function.Construct(new JsValue[] { "event", value }); - jint.LeaveExecutionContext(); + var instance = jint.Intrinsics.Function.Construct(new JsValue[] { "event", value }, JsValue.Undefined); - if (instance is FunctionInstance functor) + if (instance is Function functor) { element.AddEventListener(eventName, functor.ToListener(engine)); } diff --git a/src/AngleSharp.Js/Dom/WindowExtensions.cs b/src/AngleSharp.Js/Dom/WindowExtensions.cs index e0c7977..5fec386 100644 --- a/src/AngleSharp.Js/Dom/WindowExtensions.cs +++ b/src/AngleSharp.Js/Dom/WindowExtensions.cs @@ -30,5 +30,17 @@ public static void PostMessage(this IWindow window, String message, String targe [DomName("top")] [DomAccessor(Accessors.Getter)] public static IWindow Top(this IWindow window) => window.Document.Context?.Creator?.DefaultView; + + /// + /// Gets the console instance. + /// + /// + /// + [DomName("console")] + [DomAccessor(Accessors.Getter)] + public static Console Console(this IWindow window) + { + return new Console(window); + } } } diff --git a/src/AngleSharp.Js/EngineInstance.cs b/src/AngleSharp.Js/EngineInstance.cs index 7d111ab..2767e3d 100644 --- a/src/AngleSharp.Js/EngineInstance.cs +++ b/src/AngleSharp.Js/EngineInstance.cs @@ -4,7 +4,6 @@ namespace AngleSharp.Js using Jint; using Jint.Native; using Jint.Native.Object; - using Jint.Runtime.Environments; using System; using System.Collections.Generic; using System.Reflection; @@ -17,8 +16,6 @@ sealed class EngineInstance private readonly PrototypeCache _prototypes; private readonly ReferenceCache _references; private readonly IEnumerable _libs; - private readonly LexicalEnvironment _lexicals; - private readonly LexicalEnvironment _variables; private readonly DomNodeInstance _window; #endregion @@ -27,13 +24,10 @@ sealed class EngineInstance public EngineInstance(IWindow window, IDictionary assignments, IEnumerable libs) { - var context = window.Document.Context; - var logger = context.GetService(); _engine = new Engine(); _prototypes = new PrototypeCache(_engine); _references = new ReferenceCache(); _libs = libs; - _engine.SetValue("console", new ConsoleInstance(_engine, logger)); foreach (var assignment in assignments) { @@ -41,15 +35,24 @@ public EngineInstance(IWindow window, IDictionary assignments, I } _window = GetDomNode(window); - _lexicals = LexicalEnvironment.NewObjectEnvironment(_engine, _window, _engine.ExecutionContext.LexicalEnvironment, true); - _variables = LexicalEnvironment.NewObjectEnvironment(_engine, _engine.Global, null, false); foreach (var lib in libs) { - this.AddConstructors(_window, lib); this.AddConstructors(_window, lib); this.AddInstances(_window, lib); } + + foreach (var property in _window.GetOwnProperties()) + { + _engine.Global.FastSetProperty(property.Key.ToString(), property.Value); + } + + foreach (var prototypeProperty in Window.Prototype.GetOwnProperties()) + { + _engine.Global.FastSetProperty(prototypeProperty.Key.ToString(), prototypeProperty.Value); + } + + _engine.Global.Prototype = _window.Prototype; } #endregion @@ -60,10 +63,6 @@ public EngineInstance(IWindow window, IDictionary assignments, I public DomNodeInstance Window => _window; - public LexicalEnvironment Lexicals => _lexicals; - - public LexicalEnvironment Variables => _variables; - public Engine Jint => _engine; #endregion @@ -78,10 +77,7 @@ public JsValue RunScript(String source, JsValue context) { lock (_engine) { - _engine.EnterExecutionContext(Lexicals, Variables, context); - _engine.Execute(source); - _engine.LeaveExecutionContext(); - return _engine.GetCompletionValue(); + return _engine.Evaluate(source); } } diff --git a/src/AngleSharp.Js/Extensions/DomDelegates.cs b/src/AngleSharp.Js/Extensions/DomDelegates.cs index 9294476..5c95086 100644 --- a/src/AngleSharp.Js/Extensions/DomDelegates.cs +++ b/src/AngleSharp.Js/Extensions/DomDelegates.cs @@ -2,6 +2,7 @@ namespace AngleSharp.Js { using AngleSharp.Dom; using AngleSharp.Dom.Events; + using Jint; using Jint.Native; using Jint.Native.Function; using Jint.Runtime; @@ -12,10 +13,10 @@ namespace AngleSharp.Js static class DomDelegates { - private static readonly Type[] ToCallbackSignature = new[] { typeof(FunctionInstance), typeof(EngineInstance) }; + private static readonly Type[] ToCallbackSignature = new[] { typeof(Function), typeof(EngineInstance) }; private static readonly Type[] ToJsValueSignature = new[] { typeof(Object), typeof(EngineInstance) }; - public static Delegate ToDelegate(this Type type, FunctionInstance function, EngineInstance engine) + public static Delegate ToDelegate(this Type type, Function function, EngineInstance engine) { if (type != typeof(DomEventHandler)) { @@ -26,7 +27,7 @@ public static Delegate ToDelegate(this Type type, FunctionInstance function, Eng return function.ToListener(engine); } - public static DomEventHandler ToListener(this FunctionInstance function, EngineInstance engine) => (obj, ev) => + public static DomEventHandler ToListener(this Function function, EngineInstance engine) => (obj, ev) => { var objAsJs = obj.ToJsValue(engine); var evAsJs = ev.ToJsValue(engine); @@ -38,11 +39,11 @@ public static DomEventHandler ToListener(this FunctionInstance function, EngineI catch (JavaScriptException jsException) { var window = (IWindow)engine.Window.Value; - window.Fire(e => e.Init(null, jsException.LineNumber, jsException.Column, jsException)); + window.Fire(e => e.Init(null, jsException.Location.Start.Line, jsException.Location.Start.Column, jsException)); } }; - public static T ToCallback(this FunctionInstance function, EngineInstance engine) + public static T ToCallback(this Function function, EngineInstance engine) { var methodInfo = typeof(T).GetRuntimeMethods().First(m => m.Name == "Invoke"); var convert = typeof(EngineExtensions).GetRuntimeMethod("ToJsValue", ToJsValueSignature); diff --git a/src/AngleSharp.Js/Extensions/EngineExtensions.cs b/src/AngleSharp.Js/Extensions/EngineExtensions.cs index 180236a..599d4f8 100644 --- a/src/AngleSharp.Js/Extensions/EngineExtensions.cs +++ b/src/AngleSharp.Js/Extensions/EngineExtensions.cs @@ -21,27 +21,27 @@ public static JsValue ToJsValue(this Object obj, EngineInstance engine) { if (obj is String) { - return new JsValue((String)obj); + return JsValue.FromObjectWithType(engine.Jint, obj, typeof(String)); } else if (obj is Int32) { - return new JsValue((Int32)obj); + return JsValue.FromObjectWithType(engine.Jint, obj, typeof(Int32)); } else if (obj is UInt32) { - return new JsValue((UInt32)obj); + return JsValue.FromObjectWithType(engine.Jint, obj, typeof(UInt32)); } else if (obj is Double) { - return new JsValue((Double)obj); + return JsValue.FromObjectWithType(engine.Jint, obj, typeof(Double)); } else if (obj is Single) { - return new JsValue((Single)obj); + return JsValue.FromObjectWithType(engine.Jint, obj, typeof(Single)); } else if (obj is Boolean) { - return new JsValue((Boolean)obj); + return JsValue.FromObjectWithType(engine.Jint, obj, typeof(Boolean)); } else if (obj is Enum) { @@ -51,11 +51,11 @@ public static JsValue ToJsValue(this Object obj, EngineInstance engine) var name = ((Enum)obj).GetOfficialName(); if (name != null) { - return new JsValue(name); + return JsValue.FromObjectWithType(engine.Jint, name, typeof(String)); } break; } - return new JsValue(Convert.ToInt32(obj)); + return JsValue.FromObjectWithType(engine.Jint, obj, typeof(Enum)); } return engine.GetDomNode(obj); @@ -64,17 +64,11 @@ public static JsValue ToJsValue(this Object obj, EngineInstance engine) return JsValue.Null; } - public static ClrFunctionInstance AsValue(this Engine engine, Func func) => - new ClrFunctionInstance(engine, func); + public static ClrFunction AsValue(this Engine engine, string name, Func func) => + new ClrFunction(engine, name, func); - public static PropertyDescriptor AsProperty(this Engine engine, Func getter, Action setter) => - new PropertyDescriptor(new GetterFunctionInstance(engine, getter), new SetterFunctionInstance(engine, setter), true, true); - - public static PropertyDescriptor AsProperty(this Engine engine, Func getter) => - new PropertyDescriptor(new GetterFunctionInstance(engine, getter), null, true, false); - - public static PropertyDescriptor AsProperty(this Engine engine, Action setter) => - new PropertyDescriptor(null, new SetterFunctionInstance(engine, setter), true, false); + public static PropertyDescriptor AsProperty(this Engine engine, JsValue getter = null, JsValue setter = null) => + new GetSetPropertyDescriptor(getter, setter, true, getter != null && setter != null); public static Object[] BuildArgs(this EngineInstance context, MethodBase method, JsValue[] arguments) { @@ -212,15 +206,26 @@ public static JsValue RunScript(this EngineInstance engine, String source, INode public static JsValue Call(this EngineInstance instance, MethodInfo method, JsValue thisObject, JsValue[] arguments) { - if (method != null && thisObject.Type == Types.Object && thisObject.AsObject() is DomNodeInstance node) + if (method != null) { + DomNodeInstance nodeInstance; + + if (thisObject.Type == Types.Object && thisObject.AsObject() is DomNodeInstance node) + { + nodeInstance = node; + } + else + { + nodeInstance = instance.Window; + } + try { if (method.IsStatic) { var newArgs = new List { - thisObject, + nodeInstance, }; newArgs.AddRange(arguments); var parameters = instance.BuildArgs(method, newArgs.ToArray()); @@ -229,12 +234,12 @@ public static JsValue Call(this EngineInstance instance, MethodInfo method, JsVa else { var parameters = instance.BuildArgs(method, arguments); - return method.Invoke(node.Value, parameters).ToJsValue(instance); + return method.Invoke(nodeInstance.Value, parameters).ToJsValue(instance); } } catch (TargetInvocationException) { - throw new JavaScriptException(instance.Jint.Error); + throw new JavaScriptException(instance.Jint.Intrinsics.Error); } } diff --git a/src/AngleSharp.Js/Extensions/JsValueExtensions.cs b/src/AngleSharp.Js/Extensions/JsValueExtensions.cs index b786214..70e4c04 100644 --- a/src/AngleSharp.Js/Extensions/JsValueExtensions.cs +++ b/src/AngleSharp.Js/Extensions/JsValueExtensions.cs @@ -1,5 +1,6 @@ namespace AngleSharp.Js { + using Jint; using Jint.Native; using Jint.Native.Function; using Jint.Runtime; @@ -20,13 +21,13 @@ private static Object AsComplex(this JsValue value, Type targetType, EngineInsta } else if (targetType.GetTypeInfo().IsSubclassOf(typeof(Delegate))) { - var f = obj as FunctionInstance; + var f = obj as Function; if (f == null && obj is String b) { var e = engine.Jint; - var p = new[] { new JsValue(b) }; - f = new ClrFunctionInstance(e, (_this, args) => e.Eval.Call(_this, p)); + var p = new[] { JsValue.FromObjectWithType(e, b, typeof(String)) }; + f = new ClrFunction(e, "AsComplex", (_this, args) => e.Intrinsics.Eval.Call(_this, p)); } if (f != null) @@ -56,7 +57,7 @@ public static Object FromJsValue(this JsValue val) var node = obj as DomNodeInstance; return node != null ? node.Value : obj; case Types.Undefined: - return Undefined.Text; + return JsValue.Undefined.ToString(); case Types.Null: return null; } diff --git a/src/AngleSharp.Js/JsApiExtensions.cs b/src/AngleSharp.Js/JsApiExtensions.cs index 53ee910..d5e8cbf 100644 --- a/src/AngleSharp.Js/JsApiExtensions.cs +++ b/src/AngleSharp.Js/JsApiExtensions.cs @@ -19,7 +19,7 @@ public static Object ExecuteScript(this IDocument document, String scriptCode) { if (document == null) throw new ArgumentNullException(nameof(document)); - + var service = document?.Context.GetService(); return service?.EvaluateScript(document, scriptCode); } diff --git a/src/AngleSharp.Js/Proxies/ConsoleInstance.cs b/src/AngleSharp.Js/Proxies/ConsoleInstance.cs deleted file mode 100644 index a75086e..0000000 --- a/src/AngleSharp.Js/Proxies/ConsoleInstance.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace AngleSharp.Js -{ - using Jint; - using Jint.Native; - using Jint.Native.Object; - using Jint.Runtime.Interop; - using System; - - sealed class ConsoleInstance : ObjectInstance - { - private readonly IConsoleLogger _logger; - - public ConsoleInstance(Engine engine, IConsoleLogger logger) - : base(engine) - { - _logger = logger; - FastAddProperty("log", new ClrFunctionInstance(engine, Log), false, false, false); - } - - private JsValue Log(JsValue ctx, JsValue[] args) - { - if (_logger != null) - { - var objs = new Object[args.Length]; - - for (var i = 0; i < args.Length; i++) - { - objs[i] = args[i].FromJsValue(); - } - - _logger.Log(objs); - } - - return JsValue.Undefined; - } - } -} diff --git a/src/AngleSharp.Js/Proxies/DomConstructorInstance.cs b/src/AngleSharp.Js/Proxies/DomConstructorInstance.cs index 9534e0f..64bd0d3 100644 --- a/src/AngleSharp.Js/Proxies/DomConstructorInstance.cs +++ b/src/AngleSharp.Js/Proxies/DomConstructorInstance.cs @@ -1,28 +1,28 @@ namespace AngleSharp.Js { using Jint.Native; - using Jint.Native.Function; using Jint.Native.Object; using Jint.Runtime; + using Jint.Runtime.Descriptors; using Jint.Runtime.Interop; using System; using System.Reflection; - sealed class DomConstructorInstance : FunctionInstance, IConstructor + sealed class DomConstructorInstance : Constructor { private readonly ConstructorInfo _constructor; private readonly EngineInstance _instance; private readonly ObjectInstance _objectPrototype; public DomConstructorInstance(EngineInstance engine, Type type) - : base(engine.Jint, null, null, false) + : base(engine.Jint, type.GetOfficialName()) { - var toString = new ClrFunctionInstance(Engine, ToString); + var toString = new ClrFunction(Engine, "toString", ToString); _objectPrototype = engine.GetDomPrototype(type); _instance = engine; - FastAddProperty("toString", toString, true, false, true); - FastAddProperty("prototype", _objectPrototype, false, false, false); - _objectPrototype.FastAddProperty("constructor", this, true, false, true); + FastSetProperty("toString", new PropertyDescriptor(toString, true, false, true)); + SetOwnProperty("prototype", new PropertyDescriptor(_objectPrototype, false, false, false)); + _objectPrototype.FastSetProperty("constructor", new PropertyDescriptor(this, true, false, true)); } public DomConstructorInstance(EngineInstance engine, ConstructorInfo constructor) @@ -31,17 +31,7 @@ public DomConstructorInstance(EngineInstance engine, ConstructorInfo constructor _constructor = constructor; } - public override JsValue Call(JsValue thisObject, JsValue[] arguments) - { - if (_constructor != null) - { - throw new JavaScriptException("Only call the constructor with the new keyword."); - } - - return ((IConstructor)this).Construct(arguments); - } - - ObjectInstance IConstructor.Construct(JsValue[] arguments) + public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget) { if (_constructor == null) { @@ -56,11 +46,20 @@ ObjectInstance IConstructor.Construct(JsValue[] arguments) } catch { - throw new JavaScriptException(_instance.Jint.Error); + throw new JavaScriptException(_instance.Jint.Intrinsics.Error); } } - private JsValue ToString(JsValue thisObj, JsValue[] arguments) => - $"function {_objectPrototype.Class}() {{ [native code] }}"; + protected override JsValue Call(JsValue thisObject, JsValue[] arguments) + { + if (_constructor != null) + { + throw new JavaScriptException("Only call the constructor with the new keyword."); + } + + return Construct(arguments, null); + } + + private JsValue ToString(JsValue thisObj, JsValue[] arguments) => ToString(); } } diff --git a/src/AngleSharp.Js/Proxies/DomConstructors.cs b/src/AngleSharp.Js/Proxies/DomConstructors.cs deleted file mode 100644 index cf55349..0000000 --- a/src/AngleSharp.Js/Proxies/DomConstructors.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace AngleSharp.Js -{ - using Jint.Native.Function; - using Jint.Native.Object; - using System.Reflection; - - partial class DomConstructors - { - private readonly EngineInstance _engine; - - public DomConstructors(EngineInstance engine) - { - Object = engine.Jint.Object; - _engine = engine; - } - - public ObjectConstructor Object - { - get; - private set; - } - - public void Configure() => Setup(_engine); - - public void AttachConstructors(ObjectInstance obj) - { - var properties = GetType().GetTypeInfo().DeclaredProperties; - - foreach (var property in properties) - { - var func = property.GetValue(this) as FunctionInstance; - obj.FastAddProperty(property.Name, func, true, false, true); - } - } - - partial void Setup(EngineInstance engine); - } -} diff --git a/src/AngleSharp.Js/Proxies/DomDelegateInstance.cs b/src/AngleSharp.Js/Proxies/DomDelegateInstance.cs deleted file mode 100644 index 741df11..0000000 --- a/src/AngleSharp.Js/Proxies/DomDelegateInstance.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace AngleSharp.Js -{ - using Jint.Native; - using Jint.Native.Function; - using Jint.Runtime; - using Jint.Runtime.Interop; - using System; - - sealed class DomDelegateInstance : FunctionInstance - { - private readonly EngineInstance _instance; - private readonly Func _func; - private readonly String _officialName; - - public DomDelegateInstance(EngineInstance engine, String officialName, Func func) - : base(engine.Jint, Array.Empty(), null, false) - { - var toString = new ClrFunctionInstance(Engine, ToString); - _instance = engine; - _func = func; - _officialName = officialName; - FastAddProperty("toString", toString, true, false, true); - } - - public override JsValue Call(JsValue thisObject, JsValue[] arguments) => - _func.Invoke(thisObject, arguments); - - private JsValue ToString(JsValue thisObj, JsValue[] arguments) - { - var func = thisObj.TryCast() ?? - throw new JavaScriptException(Engine.TypeError, "Function object expected."); - - return $"function {_officialName}() {{ [native code] }}"; - } - } -} diff --git a/src/AngleSharp.Js/Proxies/DomEventInstance.cs b/src/AngleSharp.Js/Proxies/DomEventInstance.cs index 41d7e57..3eb9d23 100644 --- a/src/AngleSharp.Js/Proxies/DomEventInstance.cs +++ b/src/AngleSharp.Js/Proxies/DomEventInstance.cs @@ -1,6 +1,7 @@ namespace AngleSharp.Js { using AngleSharp.Dom; + using Jint; using Jint.Native; using Jint.Native.Function; using Jint.Runtime.Interop; @@ -13,20 +14,20 @@ sealed class DomEventInstance private readonly MethodInfo _addHandler; private readonly MethodInfo _removeHandler; private DomEventHandler _handler; - private FunctionInstance _function; + private Function _function; public DomEventInstance(EngineInstance engine, MethodInfo addHandler, MethodInfo removeHandler) { _engine = engine; _addHandler = addHandler; _removeHandler = removeHandler; - Getter = new ClrFunctionInstance(engine.Jint, GetEventHandler); - Setter = new ClrFunctionInstance(engine.Jint, SetEventHandler); + Getter = new ClrFunction(engine.Jint, "get", GetEventHandler); + Setter = new ClrFunction(engine.Jint, "set", SetEventHandler); } - public ClrFunctionInstance Getter { get; } + public ClrFunction Getter { get; } - public ClrFunctionInstance Setter { get; } + public ClrFunction Setter { get; } private JsValue GetEventHandler(JsValue thisObject, JsValue[] arguments) => _function ?? JsValue.Null; @@ -44,9 +45,9 @@ private JsValue SetEventHandler(JsValue thisObject, JsValue[] arguments) _function = null; } - if (arguments[0].Is()) + if (arguments[0] is Function) { - _function = arguments[0].As(); + _function = arguments[0].As(); _handler = (s, ev) => { var sender = s.ToJsValue(_engine); diff --git a/src/AngleSharp.Js/Proxies/DomFunctionInstance.cs b/src/AngleSharp.Js/Proxies/DomFunctionInstance.cs deleted file mode 100644 index 263060b..0000000 --- a/src/AngleSharp.Js/Proxies/DomFunctionInstance.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace AngleSharp.Js -{ - using Jint.Native; - using Jint.Native.Function; - using Jint.Runtime; - using Jint.Runtime.Interop; - using System.Reflection; - - sealed class DomFunctionInstance : FunctionInstance - { - private readonly EngineInstance _instance; - private readonly MethodInfo _method; - - public DomFunctionInstance(EngineInstance engine, MethodInfo method) - : base(engine.Jint, method.GetParameterNames(), null, false) - { - var toString = new ClrFunctionInstance(Engine, ToString); - _instance = engine; - _method = method; - FastAddProperty("toString", toString, true, false, true); - } - - public override JsValue Call(JsValue thisObject, JsValue[] arguments) => - _instance.Call(_method, thisObject, arguments); - - private JsValue ToString(JsValue thisObj, JsValue[] arguments) - { - var func = thisObj.TryCast() ?? - throw new JavaScriptException(Engine.TypeError, "Function object expected."); - - var officialName = _method.GetOfficialName(); - return $"function {officialName}() {{ [native code] }}"; - } - } -} diff --git a/src/AngleSharp.Js/Proxies/DomNodeInstance.cs b/src/AngleSharp.Js/Proxies/DomNodeInstance.cs index 8ade45d..3705b46 100644 --- a/src/AngleSharp.Js/Proxies/DomNodeInstance.cs +++ b/src/AngleSharp.Js/Proxies/DomNodeInstance.cs @@ -1,5 +1,7 @@ namespace AngleSharp.Js { + using AngleSharp.Dom; + using Jint.Native; using Jint.Native.Object; using Jint.Runtime.Descriptors; using System; @@ -14,23 +16,69 @@ public DomNodeInstance(EngineInstance engine, Object value) { _instance = engine; _value = value; - - Extensible = true; + Prototype = engine.GetDomPrototype(value.GetType()); } public Object Value => _value; - public override String Class => Prototype.Class; + public override object ToObject() => _value; - public override PropertyDescriptor GetOwnProperty(String propertyName) + public override PropertyDescriptor GetOwnProperty(JsValue property) { - if (Prototype is DomPrototypeInstance prototype && prototype.TryGetFromIndex(_value, propertyName, out var descriptor)) + if (Prototype is DomPrototypeInstance prototype) { - return descriptor; + if (prototype.TryGetFromIndex(_value, property.ToString(), out var descriptor)) + { + return descriptor; + } + else if (prototype.HasProperty(property)) + { + return prototype.GetProperty(property); + } } - return base.GetOwnProperty(propertyName); + return base.GetOwnProperty(property); + } + + protected override void SetOwnProperty(JsValue property, PropertyDescriptor desc) + { + base.SetOwnProperty(property, desc); + + if (_value is IWindow) + { + _instance.Jint.Global.FastSetProperty(property, desc); + } + } + + public new void FastSetProperty(string name, PropertyDescriptor value) + { + base.FastSetProperty(name, value); + + if (_value is IWindow) + { + _instance.Jint.Global.FastSetProperty(name, value); + } + } + + public new void FastSetProperty(JsValue property, PropertyDescriptor value) + { + base.FastSetProperty(property, value); + + if (_value is IWindow) + { + _instance.Jint.Global.FastSetProperty(property, value); + } + } + + public new void FastSetDataProperty(string name, JsValue value) + { + base.FastSetDataProperty(name, value); + + if (_value is IWindow) + { + _instance.Jint.Global.FastSetProperty(name, new PropertyDescriptor(value, true, true, true)); + } } } } diff --git a/src/AngleSharp.Js/Proxies/DomPrototypeInstance.cs b/src/AngleSharp.Js/Proxies/DomPrototypeInstance.cs index ec64833..183439e 100644 --- a/src/AngleSharp.Js/Proxies/DomPrototypeInstance.cs +++ b/src/AngleSharp.Js/Proxies/DomPrototypeInstance.cs @@ -5,7 +5,9 @@ namespace AngleSharp.Js using AngleSharp.Text; using Jint.Native; using Jint.Native.Object; + using Jint.Native.Symbol; using Jint.Runtime.Descriptors; + using Jint.Runtime.Interop; using System; using System.Collections.Generic; using System.Linq; @@ -26,16 +28,15 @@ public DomPrototypeInstance(EngineInstance engine, Type type) _name = type.GetOfficialName(baseType); _instance = engine; + Set(GlobalSymbolRegistry.ToStringTag, _name); + SetAllMembers(type); SetExtensionMembers(); // DOM objects can have properties added dynamically - Extensible = true; Prototype = engine.GetDomPrototype(baseType); } - public override String Class => _name; - public Boolean TryGetFromIndex(Object value, String index, out PropertyDescriptor result) { // If we have a numeric indexer and the property is numeric @@ -68,7 +69,7 @@ public Boolean TryGetFromIndex(Object value, String index, out PropertyDescripto // Eg. object.callMethod1() vs object['callMethod1'] is not necessarily the same if the object has a string indexer?? (I'm not an ECMA expert!) // node.attributes is one such object - has both a string and numeric indexer // This GetOwnProperty override might need an additional parameter to let us know this was called via an indexer - if (_stringIndexer != null && !Properties.ContainsKey(index)) + if (_stringIndexer != null && !HasProperty(index)) { var args = new Object[] { index }; var prop = _stringIndexer.GetMethod.Invoke(value, args).ToJsValue(_instance); @@ -120,7 +121,7 @@ private void SetExtensionMethods(IEnumerable methods) var name = entry.Key; var value = entry.Value; - if (Properties.ContainsKey(name)) + if (HasProperty(name)) { } else if (value.Adder != null && value.Remover != null) @@ -178,20 +179,20 @@ private void SetNormalMethods(IEnumerable methods) private void SetEvent(String name, MethodInfo adder, MethodInfo remover) { var eventInstance = new DomEventInstance(_instance, adder, remover); - FastSetProperty(name, new PropertyDescriptor(eventInstance.Getter, eventInstance.Setter, false, false)); + FastSetProperty(name, new GetSetPropertyDescriptor(eventInstance.Getter, eventInstance.Setter, false, false)); } private void SetProperty(String name, MethodInfo getter, MethodInfo setter, DomPutForwardsAttribute putsForward) { - FastSetProperty(name, new PropertyDescriptor( - new DomDelegateInstance(_instance, name, (obj, values) => + FastSetProperty(name, new GetSetPropertyDescriptor( + new ClrFunction(_instance.Jint, name, (obj, values) => _instance.Call(getter, obj, values)), - new DomDelegateInstance(_instance, name, (obj, values) => + new ClrFunction(_instance.Jint, name, (obj, values) => { if (putsForward != null) { var ep = Array.Empty(); - var that = obj.AsObject() as DomNodeInstance; + var that = obj as DomNodeInstance; var target = getter.Invoke(that.Value, ep); var propName = putsForward.PropertyName; var prop = getter.ReturnType @@ -227,10 +228,12 @@ private void SetMethod(String name, MethodInfo method) // If it already has a property with the given name (usually another method), // then convert that method to a two-layer method, which decides which one // to pick depending on the number (and probably types) of arguments. - if (!Properties.ContainsKey(name)) + if (!HasProperty(name)) { - var func = new DomFunctionInstance(_instance, method); - FastAddProperty(name, func, false, false, false); + FastSetProperty(name, new PropertyDescriptor( + new ClrFunction(_instance.Jint, name, (obj, values) => + _instance.Call(method, obj, values) + ), false, false, false)); } } }