diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 1f114d6..b74e64f 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,4 +1,4 @@ # These are supported funding model platforms github: FlorianRappl -custom: https://salt.bountysource.com/teams/anglesharp +custom: ['https://www.paypal.me/FlorianRappl', 'https://buymeacoffee.com/florianrappl'] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e224ca8..5fdad75 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,12 +26,12 @@ jobs: if: needs.can_document.outputs.value == 'true' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v5 - name: Use Node.js - uses: actions/setup-node@v1 + uses: actions/setup-node@v5 with: - node-version: "14.x" + node-version: "20.x" registry-url: 'https://registry.npmjs.org' - name: Install Dependencies @@ -48,23 +48,33 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v5 + + - uses: actions/setup-dotnet@v5 + with: + dotnet-version: | + 10.0.x - name: Build - run: ./build.sh + run: ./build.sh -AngleSharpVersion 1.5.0 windows: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v5 + + - uses: actions/setup-dotnet@v5 + with: + dotnet-version: | + 10.0.x - name: Build run: | if ($env:GITHUB_REF -eq "refs/heads/main") { - .\build.ps1 -Target Publish + .\build.ps1 -Target Publish -AngleSharpVersion 1.5.0 } elseif ($env:GITHUB_REF -eq "refs/heads/devel") { - .\build.ps1 -Target PrePublish + .\build.ps1 -Target PrePublish -AngleSharpVersion 1.5.0 } else { - .\build.ps1 + .\build.ps1 -AngleSharpVersion 1.5.0 } 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..83a628f --- /dev/null +++ b/.nuke/build.schema.json @@ -0,0 +1,139 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "definitions": { + "Host": { + "type": "string", + "enum": [ + "AppVeyor", + "AzurePipelines", + "Bamboo", + "Bitbucket", + "Bitrise", + "GitHubActions", + "GitLab", + "Jenkins", + "Rider", + "SpaceAutomation", + "TeamCity", + "Terminal", + "TravisCI", + "VisualStudio", + "VSCode" + ] + }, + "ExecutableTarget": { + "type": "string", + "enum": [ + "Clean", + "Compile", + "CopyFiles", + "CreatePackage", + "Default", + "Package", + "PrePublish", + "Publish", + "PublishPackage", + "PublishPreRelease", + "PublishRelease", + "Restore", + "RunUnitTests" + ] + }, + "Verbosity": { + "type": "string", + "description": "", + "enum": [ + "Verbose", + "Normal", + "Minimal", + "Quiet" + ] + }, + "NukeBuild": { + "properties": { + "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": { + "description": "Host for execution. Default is 'automatic'", + "$ref": "#/definitions/Host" + }, + "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" + } + }, + "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": { + "$ref": "#/definitions/ExecutableTarget" + } + }, + "Target": { + "type": "array", + "description": "List of targets to be invoked. Default is '{default_target}'", + "items": { + "$ref": "#/definitions/ExecutableTarget" + } + }, + "Verbosity": { + "description": "Logging verbosity during build execution. Default is 'Normal'", + "$ref": "#/definitions/Verbosity" + } + } + } + }, + "allOf": [ + { + "properties": { + "AngleSharpVersion": { + "type": "string", + "description": "AngleSharp package version override (e.g. 1.0.0 for compatibility checks)" + }, + "Configuration": { + "type": "string", + "description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)", + "enum": [ + "Debug", + "Release" + ] + }, + "ReleaseNotesFilePath": { + "type": "string", + "description": "ReleaseNotesFilePath - To determine the SemanticVersion" + }, + "Solution": { + "type": "string", + "description": "Path to a solution file that is automatically loaded" + } + } + }, + { + "$ref": "#/definitions/NukeBuild" + } + ] +} 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/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..f78f1f2 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,212 @@ +# AGENTS.md + +Guidance for AI coding agents working in this repository. `CLAUDE.md` imports this file, so +keep it the single source of truth and every agent reads the same instructions. + +AngleSharp.Js is an AngleSharp plugin that exposes the AngleSharp DOM to the +[Jint](https://github.com/sebastienros/jint) JavaScript engine. There is no code generation +and no hand-written binding layer: the whole JS surface is derived at runtime by reflecting +over AngleSharp's `[DomName]`-style attributes. + +## Commands + +The orchestrator is NUKE (`nuke/Build.cs`), bootstrapped by `build.ps1` / `build.sh` +(`build.cmd` forwards to either). Default target is `RunUnitTests`. + +```powershell +.\build.ps1 # restore, compile, run the full test suite +.\build.ps1 -Target Compile # other targets: Clean Restore Compile RunUnitTests +.\build.ps1 -Target Package # CopyFiles CreatePackage Package PrePublish Publish +``` + +For the normal edit/test loop use the SDK directly — much faster than the NUKE bootstrap: + +```powershell +dotnet build src/AngleSharp.Js.sln +dotnet test src/AngleSharp.Js.Tests/AngleSharp.Js.Tests.csproj -f net8.0 +dotnet test src/AngleSharp.Js.Tests/AngleSharp.Js.Tests.csproj -f net8.0 --filter "FullyQualifiedName~InstanceOfTests" +dotnet test src/AngleSharp.Js.Tests/AngleSharp.Js.Tests.csproj -f net8.0 --filter "Name=WindowIsAnInstanceOfWindow" +``` + +- Always pass `-f net8.0` when iterating. On Windows both projects also target `net462` and + `net472`, so omitting it runs everything three times. +- `TreatWarningsAsErrors` is on (`src/Directory.Build.props`) — a warning breaks the build. + There is no separate lint step; the compiler is it. +- The package version is parsed from the top entry of `CHANGELOG.md` (`ReleaseNotesParser`), + not from a csproj property. Release-worthy changes get a `CHANGELOG.md` line. +- `RunUnitTests` runs the suite twice, differing only in a `prefetched` environment variable + that nothing in this repo currently reads — a single run is equivalent locally. +- There is no `global.json`; the bootstrap scripts use the STS channel, CI installs 10.0.x. + +## Architecture + +### Wiring into AngleSharp + +`WithJs()` (`JsConfigurationExtensions`) registers four things: `JsScriptingService`, an +`EventAttributeObserver` (inline `onclick="…"` attributes), a `JsNavigationHandler` +(`javascript:` URLs), and a default `INavigator`. `WithEventLoop()` adds `JsEventLoop`, a +dedicated background thread that serializes script tasks — most DOM-mutating tests need it. + +`JsScriptingService` is AngleSharp's `IScriptingService`. It keeps one `EngineInstance` per +`IWindow` in a `ConditionalWeakTable`, and accepts `text/javascript`, `module` and +`importmap`. **The set of assemblies whose types get exposed is derived from the services +registered in the browsing context** (every `AngleSharp*` assembly behind a registered +service), so adding `WithCss()` or `WithIo()` widens the JS DOM surface. + +`EngineInstance` owns the Jint `Engine` and the per-engine caches. On construction it wraps +the window, walks each library's exported types to publish constructors, constructor +functions and instances, then copies the window's own properties onto the Jint global and +points the global's prototype at the window prototype. `RunScript` locks on the engine. + +### The proxy objects (`src/AngleSharp.Js/Proxies`) + +- **`DomNodeInstance`** — the JS object standing for one CLR DOM object. Identity is + preserved by `ReferenceCache` (a `ConditionalWeakTable`), so the same node always maps to + the same JS object. Only indexers become own properties; interface members live on the + prototype. Writes to the window instance are mirrored onto the Jint global. +- **`DomPrototypeInstance`** — one per DOM type. Members are registered lazily in + `Initialize()`: reflecting the full type tree is the expensive part and most prototypes + are never touched. Also owns the numeric/string indexers and extension members pulled from + `[DomExposed]` types. +- **`DomConstructorInstance`** — the exposed constructor (`HTMLDivElement`, …). The + prototype holds it, so the object script reads off the window and the one an instance + reports as its `constructor` are the same. It answers `Symbol.hasInstance` itself, because + the prototype chain cannot cover mixins (`ParentNode`) or generic collections + (`IHtmlCollection`). +- **`DomConstructorDescriptor`** — the property a constructor is published under. Every + exported type gets one, so the constructor object behind it is built only on first read. + +### Type → prototype canonicalization + +This is the subtlety most changes trip over. Instances are created from internal concrete +classes (`HtmlDivElement`), constructors are built from exported interfaces +(`IHtmlDivElement`), and many element classes carry no `[DomName]` of their own (a `b` +element is just an `HTMLElement`). `PrototypeTypeCache` folds all of these onto the topmost +class that defines a given DOM name, which is what makes `instanceof` and +`Object.getPrototypeOf(div) === HTMLDivElement.prototype` hold. Enums and generic types are +deliberately excluded from folding. + +### Caching rules (`src/AngleSharp.Js/Cache`) + +Split by what the cached value depends on: + +- Process-wide statics — `CreatorCache`, `PrototypeTypeCache`, `MethodCache`, `ScriptCache` + (capped at 32 prepared scripts) — hold values determined by a type, method or source alone. +- Per-engine — `PrototypeCache`, `ReferenceCache` — hold anything that is a `JsValue` or + otherwise bound to one engine, plus anything depending on the engine's library set. + +Anything shared across engines must be thread-safe; the existing caches all use +`Concurrent*` collections. + +### Marshalling + +`EngineExtensions.ToJsValue` and `JsValueExtensions.FromJsValue` / `.As(type, …)` convert +values. `EngineExtensions.BuildArgs` maps JS arguments onto a CLR signature and handles the +DOM-specific cases: an implicit leading `IWindow` parameter, optional parameters, `params` +arrays, and `[DomInitDict]` option objects expanded into positional arguments. + +## Performance + +**Performance is a primary concern in this repository, not an afterthought.** Jint is an +interpreter and every DOM access from script crosses this binding layer, so the binding must +never be the bottleneck. Reflection is the whole mechanism here, and reflection is slow — the +work of the last release cycle was largely making it happen once instead of once per call +(`perf/cache-interop-reflection`, `perf/cache-parsed-scripts`, `perf/lazy-dom-prototypes`, +`perf/lazy-dom-constructors`). Hold new code to that standard. + +The two techniques that carry most of the win: + +- **Cache anything derived from a type, method or source string.** It cannot change for the + lifetime of the process. `MethodDescription.Of` resolves a signature once; + `CreatorCache.GetConstructorDefinition` caches even the *null* answer, because most + exported types are not constructors; `ScriptCache` keeps Jint's `Prepared")); +``` + +JavaScript can call delegates and access the public members of objects exposed this way. For +advanced integration, `GetOrCreateJint(document)` returns the document's Jint `Engine`, which +lets host code inspect JavaScript values or invoke JavaScript functions directly. + +Registering a `JsScriptingService` directly does not add the auxiliary integration that +`WithJs()` supplies: inline event-handler attributes and `javascript:` URL navigation. + +### Capture `console.log` + +`console.log` forwards its arguments to an `IConsoleLogger` registered for the browsing +context. Provide one with `WithConsoleLogger`: + +```cs +var configuration = Configuration.Default .WithJs() - .WithConsoleLogger(ctx => new MyConsoleLogger(ctx)); + .WithConsoleLogger(_ => new ApplicationConsoleLogger()); +``` + +Implement `IConsoleLogger.Log(Object[] values)` to send the values to your application's +logging system. Without a logger, calls to `console.log` do not produce output. + +For example, a minimal logger can forward values to `System.Diagnostics`: + +```cs +sealed class ApplicationConsoleLogger : IConsoleLogger +{ + public void Log(Object[] values) + { + Debug.WriteLine(String.Join(" ", values)); + } +} ``` -in the previous example `MyConsoleLogger` refers to a class implementing the `IConsoleLogger` interface. Examples of classes implementing this interface are available in our [samples repository](https://github.com/AngleSharp/AngleSharp.Samples). +## DOM APIs and integration points + +AngleSharp.Js exposes AngleSharp DOM interfaces to JavaScript dynamically. The available +surface therefore follows the AngleSharp services registered in the browsing context. For +example, adding CSS support also makes its AngleSharp DOM types available to scripts. + +In addition to the DOM provided by AngleSharp, the package supplies: + +- `console.log`, `atob`, `btoa`, `DOMParser`, `Image`, `screen`, and `XMLHttpRequest`. +- `javascript:` URL navigation. +- Inline event-handler attributes and DOM event callbacks. +- ES modules and import maps through Jint's module loader. + +### Built-in browser facades + +The additional browser-like APIs are deliberately small. Use this table when deciding whether +they meet a script's needs: + +| API | Available behavior | +| --- | --- | +| `DOMParser` | `parseFromString` creates a document through the configured `IDocumentFactory`. The requested MIME type must be supported by that configuration. | +| `Image` | Creates an AngleSharp `` element; optional width and height become its display dimensions. | +| `window.postMessage` | Queues a `message` event on the current window. It requires an event loop; it does not transfer objects, deliver to another browsing context, or enforce `targetOrigin`. | +| `XMLHttpRequest` | Supports `open`, `send`, request headers, status, text responses, and lifecycle events through the configured document loader. | +| `console` | Supports `console.log` only. | +| `screen` | Exposes fixed 1920-by-1080 dimensions and 24-bit color depth for compatibility. | + +To replace the supplied behavior, register your own compatible AngleSharp service before +calling `WithJs()`. In particular, `WithJs()` preserves an existing `INavigator`, and the +`WithEventLoop` overloads accept either an existing `IEventLoop` or a factory for one. + +## Supported behavior and limitations + +AngleSharp.Js is a DOM and scripting integration, not a browser runtime. Script behavior +depends on the installed Jint and AngleSharp versions, plus the services that your +configuration supplies. Test the browser APIs your application relies on instead of assuming +complete browser parity. + +Notable limitations include: + +- The package does not calculate layout. Its `scroll*`, `client*`, and `offset*` element + properties return `0`. +- The default `navigator` is intentionally minimal. Its platform is empty, registration + methods are no-ops, and its user-agent value is a fixed compatibility string. +- Network-backed features such as external scripts and `XMLHttpRequest` require suitable + AngleSharp requesters and resource loading configuration. +- `XMLHttpRequest` currently provides text responses only. Its `response`, `responseXML`, and + `upload` properties are unavailable, `responseType` always has its empty value, and its + `timeout` and `withCredentials` settings do not affect requests. +- The JavaScript engine executes application-provided or page-provided code in your process. + Treat untrusted scripts as untrusted code and apply the constraints appropriate to your + application. 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..45b59dd --- /dev/null +++ b/nuke/Build.cs @@ -0,0 +1,317 @@ +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 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"; + + [Nuke.Common.Parameter("AngleSharp package version override (e.g. 1.0.0 for compatibility checks)")] + readonly string AngleSharpVersion; + + [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(TargetLibName); + 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(x => x.DeleteDirectory()); + }); + + Target Restore => _ => _ + .Executes(() => + { + DotNetRestore(s => + { + var settings = s.SetProjectFile(Solution); + + if (!String.IsNullOrEmpty(AngleSharpVersion)) + { + settings = settings.SetProperty("AngleSharpVersion", AngleSharpVersion); + } + + return settings; + }); + }); + + Target Compile => _ => _ + .DependsOn(Restore) + .Executes(() => + { + DotNetBuild(s => + { + var settings = s + .SetProjectFile(Solution) + .SetConfiguration(Configuration) + .EnableNoRestore(); + + if (!String.IsNullOrEmpty(AngleSharpVersion)) + { + settings = settings.SetProperty("AngleSharpVersion", AngleSharpVersion); + } + + return settings; + }); + }); + + Target RunUnitTests => _ => _ + .DependsOn(Compile) + .Executes(() => + { + DotNetTest(s => + { + var settings = s + .SetProjectFile(Solution) + .SetConfiguration(Configuration) + .EnableNoRestore() + .EnableNoBuild(); + + if (!String.IsNullOrEmpty(AngleSharpVersion)) + { + settings = settings.SetProperty("AngleSharpVersion", AngleSharpVersion); + } + + return settings; + }); + }); + + Target CopyFiles => _ => _ + .DependsOn(Compile) + .Executes(() => + { + foreach (var item in TargetFrameworks) + { + var targetDir = NugetDirectory / "lib" / item; + var srcDir = BuildDirectory / item; + + (srcDir / $"{TargetProjectName}.dll").Copy(targetDir / $"{TargetProjectName}.dll", ExistsPolicy.FileOverwriteIfNewer); + (srcDir / $"{TargetProjectName}.pdb").Copy(targetDir / $"{TargetProjectName}.pdb", ExistsPolicy.FileOverwriteIfNewer); + (srcDir / $"{TargetProjectName}.xml").Copy(targetDir / $"{TargetProjectName}.xml", ExistsPolicy.FileOverwriteIfNewer); + } + + (SourceDirectory / $"{TargetProjectName}.nuspec").Copy(NugetDirectory / $"{TargetProjectName}.nuspec", ExistsPolicy.FileOverwriteIfNewer); + (RootDirectory / "logo.png").Copy(NugetDirectory / "logo.png", ExistsPolicy.FileOverwriteIfNewer); + (RootDirectory / "README.md").Copy(NugetDirectory / "README.md", ExistsPolicy.FileOverwriteIfNewer); + }); + + 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 NugetDirectory.GlobFiles("*.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..5a0000d --- /dev/null +++ b/nuke/_build.csproj @@ -0,0 +1,23 @@ + + + + Exe + net10.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 167bca3..dcf1f90 100644 --- a/src/AngleSharp.Js.Tests/AngleSharp.Js.Tests.csproj +++ b/src/AngleSharp.Js.Tests/AngleSharp.Js.Tests.csproj @@ -1,12 +1,8 @@ - AngleSharp.Js.Tests - netcoreapp2.1 - true - Key.snk + net8.0 + $(TargetFrameworks);net462;net472 false - 7.1 - AngleSharp.Js.Tests true @@ -17,12 +13,20 @@ - - - - - - - + - \ No newline at end of file + + + + + 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..81fa93d 100644 --- a/src/AngleSharp.Js.Tests/Constants.cs +++ b/src/AngleSharp.Js.Tests/Constants.cs @@ -265,5 +265,320 @@ 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"; + + public static readonly string Jquery4_0_0_ESM = @"/*! jQuery v4.0.0-beta | (c) OpenJS Foundation and other contributors | jquery.org/license */function e(e,t){if(void 0===e||!e.document)throw Error(""jQuery requires a window with a document"");var n=[],r=Object.getPrototypeOf,i=n.slice,o=n.flat?function(e){return n.flat.call(e)}:function(e){return n.concat.apply([],e)},a=n.push,s=n.indexOf,u={},l=u.toString,c=u.hasOwnProperty,f=c.toString,p=f.call(Object),d={};function h(e){return null==e?e+"""":""object""==typeof e?u[l.call(e)]||""object"":typeof e} +function g(e){return null!=e&&e===e.window}function v(e){var t=!!e&&e.length,n=h(e);return!(""function""==typeof e||g(e))&&(""array""===n||0===t||""number""==typeof t&&t>0&&t-1 in e)}var y=e.document,m={type:!0,src:!0,nonce:!0,noModule:!0};function x(e,t,n){var r,i=(n=n||y).createElement(""script"");for(r in i.text=e,m)t&&t[r]&&(i[r]=t[r]);n.head.appendChild(i).parentNode&&i.parentNode.removeChild(i)}var b=""4.0.0-beta"",w=/HTML$/i,T=function(e,t){return new T.fn.init(e,t)};function C(e,t){return + e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}T.fn=T.prototype={jquery:b,constructor:T,length:0,toArray:function(){return i.call(this)},get:function(e){return null==e?i.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=T.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return T.each(this,e)},map:function(e){return this.pushStack(T.map(this,(function(t,n){return e.call(t,n,t)})))},slice:function(){return this.pushStack(i.apply(this, + arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(T.grep(this,(function(e,t){return(t+1)%2})))},odd:function(){return this.pushStack(T.grep(this,(function(e,t){return t%2})))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n+~]|""+E+"")""+E+""*""),N=RegExp(E+""|>""),O=/[+~]/,H=y.documentElement,L=H.matches||H.msMatchesSelector;function P(){var e=[];function t(n,r){return e.push(n+"" "")>T.expr.cacheLength&&delete t[e.shift()],t[n+"" ""]=r}return t}function R(e){return e&&void 0!==e.getElementsByTagName&&e}var M=""\\[""+E+""*(""+A+"")(?:""+E+""*([*^$|!~]?=)""+E+""*(?:'((?:\\\\.|[^\\\\'])*)'|\""((?:\\\\.|[^\\\\\""])*)\""|(""+A+""))|)""+E+ + ""*\\]"",W="":(""+A+"")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\""((?:\\\\.|[^\\\\\""])*)\"")|((?:\\\\.|[^\\\\()[\\]]|""+M+"")*)|.*)\\)|)"",I={ID:RegExp(""^#(""+A+"")""),CLASS:RegExp(""^\\.(""+A+"")""),TAG:RegExp(""^(""+A+""|[*])""),ATTR:RegExp(""^""+M),PSEUDO:RegExp(""^""+W),CHILD:RegExp(""^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(""+E+""*(even|odd|(([+-]|)(\\d*)n|)""+E+""*(?:([+-]|)""+E+""*(\\d+)|))""+E+""*\\)|)"",""i"")},$=new RegExp(W),F=RegExp(""\\\\[\\da-fA-F]{1,6}""+E+""?|\\\\([^\\r\\n\\f])"",""g""),B=function(e,t){var n=""0x""+ + e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))};function _(e){return e.replace(F,B)}function U(e){T.error(""Syntax error, unrecognized expression: ""+e)}var X=RegExp(""^""+E+""*,""+E+""*""),z=P();function V(e,t){var n,r,i,o,a,s,u,l=z[e+"" ""];if(l)return t?0:l.slice(0);a=e,s=[],u=T.expr.preFilter;while(a){for(o in(!n||(r=X.exec(a)))&&(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=q.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace( + D,"" "")}),a=a.slice(n.length)),I)(r=T.expr.match[o].exec(a))&&(!u[o]||(r=u[o](r)))&&(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?U(e):z(e,s).slice(0)}function Y(e){for(var t=0,n=e.length,r="""";t1)},removeAttr:function(e){return this.each((function(){T.removeAttr(this,e)}))}}),T.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o){if(void 0===e.getAttribute)return T.prop(e,t,n);if(1===o&&T.isXMLDoc(e)||(i=T.attrHooks[t.toLowerCase()]),void 0!==n){if( + null===n){T.removeAttr(e,t);return}return i&&""set""in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n),n)}return i&&""get""in i&&null!==(r=i.get(e,t))?r:null==(r=e.getAttribute(t))?void 0:r}},attrHooks:{},removeAttr:function(e,t){var n,r=0,i=t&&t.match(Q);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),k&&(T.attrHooks.type={set:function(e,t){if(""radio""===t&&C(e,""input"")){var n=e.value;return e.setAttribute(""type"",t),n&&(e.value=n),t}}}),T.each(""checked selected async autofocus autoplay controls defer disabled hidden ismap loop multiple open readonly required scoped"".split("" ""),(function(e,t){T.attrHooks[t]={get:function(e){return null!=e.getAttribute(t)?t.toLowerCase():null},set:function(e,t,n){return!1===t?T.removeAttr(e,n):e.setAttribute(n,n),n}}}));var J=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;function K(e,t){return t?""\0""===e?"" "":e.slice(0,-1)+""\\""+e.charCodeAt(e.length-1).toString(16)+"" "":""\\""+e}T.escapeSelector=function(e){return(e+"""").replace(J,K)};var + Z=n.sort,ee=n.splice;function te(e,t){if(e===t)return ne=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)?e==y||e.ownerDocument==y&&T.contains(y,e)?-1:t==y||t.ownerDocument==y&&T.contains(y,t)?1:0:4&n?-1:1)}T.uniqueSort=function(e){var t,n=[],r=0,i=0;if(ne=!1,Z.call(e,te),ne){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)ee.call(e,n[r],1)}return e},T.fn.uniqueSort=function(){return + this.pushStack(T.uniqueSort(i.apply(this)))};var ne,re,ie,oe,ae,se,ue=0,le=0,ce=P(),fe=P(),pe=P(),de=RegExp(E+""+"",""g""),he=RegExp(""^""+A+""$""),ge=T.extend({needsContext:RegExp(""^""+E+""*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(""+E+""*((?:-\\d)?\\d*)""+E+""*\\)|)(?=[^-]|$)"",""i"")},I),ve=/^(?:input|select|textarea|button)$/i,ye=/^h\d$/i,me=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,xe=function(){Ee()},be=Se((function(e){return!0===e.disabled&&C(e,""fieldset"")}),{dir:""parentNode"",next:""legend""});function we(e, + t,n,r){var i,o,s,u,l,c,f,p=t&&t.ownerDocument,d=t?t.nodeType:9;if(n=n||[],""string""!=typeof e||!e||1!==d&&9!==d&&11!==d)return n;if(!r&&(Ee(t),t=t||oe,se)){if(11!==d&&(l=me.exec(e))){if(i=l[1]){if(9===d)return(s=t.getElementById(i))&&a.call(n,s),n;if(p&&(s=p.getElementById(i))&&T.contains(t,s))return a.call(n,s),n}else if(l[2])return a.apply(n,t.getElementsByTagName(e)),n;else if((i=l[3])&&t.getElementsByClassName)return a.apply(n,t.getElementsByClassName(i)),n}if(!pe[e+"" ""]&&(!S||!S.test(e))){ + if(f=e,p=t,1===d&&(N.test(e)||q.test(e))){((p=O.test(e)&&R(t.parentNode)||t)!=t||k)&&((u=t.getAttribute(""id""))?u=T.escapeSelector(u):t.setAttribute(""id"",u=T.expando)),o=(c=V(e)).length;while(o--)c[o]=(u?""#""+u:"":scope"")+"" ""+Y(c[o]);f=c.join("","")}try{return a.apply(n,p.querySelectorAll(f)),n}catch(t){pe(e,!0)}finally{u===T.expando&&t.removeAttribute(""id"")}}}return Ne(e.replace(D,""$1""),t,n,r)}function Te(e){return e[T.expando]=!0,e}function Ce(e){return function(t){if(""form""in t)return + t.parentNode&&!1===t.disabled?""label""in t?""label""in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||!e!==t.isDisabled&&be(t)===e:t.disabled===e;return""label""in t&&t.disabled===e}}function je(e){return Te((function(t){return t=+t,Te((function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))}))}))}function Ee(e){var t,n=e?e.ownerDocument||e:y;n!=oe&&9===n.nodeType&&(ae=(oe=n).documentElement,se=!T.isXMLDoc(oe),k&&y!=oe&&(t=oe.defaultView) + &&t.top!==t&&t.addEventListener(""unload"",xe))}for(re in we.matches=function(e,t){return we(e,null,null,t)},we.matchesSelector=function(e,t){if(Ee(e),se&&!pe[t+"" ""]&&(!S||!S.test(t)))try{return L.call(e,t)}catch(e){pe(t,!0)}return we(t,oe,null,[e]).length>0},T.expr={cacheLength:50,createPseudo:Te,match:ge,find:{ID:function(e,t){if(void 0!==t.getElementById&&se){var n=t.getElementById(e);return n?[n]:[]}},TAG:function(e,t){return void 0!==t.getElementsByTagName?t.getElementsByTagName(e): + t.querySelectorAll(e)},CLASS:function(e,t){if(void 0!==t.getElementsByClassName&&se)return t.getElementsByClassName(e)}},relative:{"">"":{dir:""parentNode"",first:!0},"" "":{dir:""parentNode""},""+"":{dir:""previousSibling"",first:!0},""~"":{dir:""previousSibling""}},preFilter:{ATTR:function(e){return e[1]=_(e[1]),e[3]=_(e[3]||e[4]||e[5]||""""),""~=""===e[2]&&(e[3]="" ""+e[3]+"" ""),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),""nth""===e[1].slice(0,3)?(e[3]||U(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*( + ""even""===e[3]||""odd""===e[3])),e[5]=+(e[7]+e[8]||""odd""===e[3])):e[3]&&U(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return I.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"""":n&&$.test(n)&&(t=V(n,!0))&&(t=n.indexOf("")"",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{ID:function(e){var t=_(e);return function(e){return e.getAttribute(""id"")===t}},TAG:function(e){var t=_(e).toLowerCase();return""*""===e?function(){return!0}:function(e){return C(e,t)}},CLASS: + function(e){var t=ce[e+"" ""];return t||(t=RegExp(""(^|""+E+"")""+e+""(""+E+""|$)""),ce(e,(function(e){return t.test(""string""==typeof e.className&&e.className||void 0!==e.getAttribute&&e.getAttribute(""class"")||"""")})))},ATTR:function(e,t,n){return function(r){var i=T.attr(r,e);return null==i?""!=""===t:!t||((i+="""",""=""===t)?i===n:""!=""===t?i!==n:""^=""===t?n&&0===i.indexOf(n):""*=""===t?n&&i.indexOf(n)>-1:""$=""===t?n&&i.slice(-n.length)===n:""~=""===t?("" ""+i.replace(de,"" "")+"" "").indexOf(n)>-1:""|=""===t&&(i===n|| + i.slice(0,n.length+1)===n+""-""))}},CHILD:function(e,t,n,r,i){var o=""nth""!==e.slice(0,3),a=""last""!==e.slice(-4),s=""of-type""===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h=o!==a?""nextSibling"":""previousSibling"",g=t.parentNode,v=s&&t.nodeName.toLowerCase(),y=!u&&!s,m=!1;if(g){if(o){while(h){f=t;while(f=f[h])if(s?C(f,v):1===f.nodeType)return!1;d=h=""only""===e&&!d&&""nextSibling""}return!0}if(d=[a?g.firstChild:g.lastChild],a&&y){m=(p=(l=(c=g[T.expando]||(g[ + T.expando]={}))[e]||[])[0]===ue&&l[1])&&l[2],f=p&&g.childNodes[p];while(f=++p&&f&&f[h]||(m=p=0)||d.pop())if(1===f.nodeType&&++m&&f===t){c[e]=[ue,p,m];break}}else if(y&&(m=p=(l=(c=t[T.expando]||(t[T.expando]={}))[e]||[])[0]===ue&&l[1]),!1===m){while(f=++p&&f&&f[h]||(m=p=0)||d.pop())if((s?C(f,v):1===f.nodeType)&&++m&&(y&&((c=f[T.expando]||(f[T.expando]={}))[e]=[ue,m]),f===t))break}return(m-=i)===r||m%r==0&&m/r>=0}}},PSEUDO:function(e,t){var n=T.expr.pseudos[e]||T.expr.setFilters[e.toLowerCase()]|| + U(""unsupported pseudo: ""+e);return n[T.expando]?n(t):n}},pseudos:{not:Te((function(e){var t=[],n=[],r=qe(e.replace(D,""$1""));return r[T.expando]?Te((function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))})):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}})),has:Te((function(e){return function(t){return we(e,t).length>0}})),contains:Te((function(e){return e=_(e),function(t){return(t.textContent||T.text(t)).indexOf(e)>-1}})),lang:Te((function(e){ + return he.test(e||"""")||U(""unsupported lang: ""+e),e=_(e).toLowerCase(),function(t){var n;do{if(n=se?t.lang:t.getAttribute(""xml:lang"")||t.getAttribute(""lang""))return(n=n.toLowerCase())===e||0===n.indexOf(e+""-"")}while((t=t.parentNode)&&1===t.nodeType);return!1}})),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===ae},focus:function(e){return e===oe.activeElement&&oe.hasFocus()&&!!(e.type||e.href||~e.tabIndex)},enabled:Ce(!1),disabled:Ce( + !0),checked:function(e){return C(e,""input"")&&!!e.checked||C(e,""option"")&&!!e.selected},selected:function(e){return k&&e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!T.expr.pseudos.empty(e)},header:function(e){return ye.test(e.nodeName)},input:function(e){return ve.test(e.nodeName)},button:function(e){return C(e,""input"")&&""button""===e.type||C(e,""button"")},text:function( + e){return C(e,""input"")&&""text""===e.type},first:je((function(){return[0]})),last:je((function(e,t){return[t-1]})),eq:je((function(e,t,n){return[n<0?n+t:n]})),even:je((function(e,t){for(var n=0;nt?t:n;--r>=0;)e.push(r);return e})),gt:je((function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function Ae(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s-1}),l,!0),d=[function(e,t,r){var i=!u&&(r||t!=ie)||((n=t).nodeType?f(e,t,r):p(e,t,r));return n=null,i}];c-1&&(e[f]=!(u[f]=d))}}else h=Ae(h===u?h.splice(y,h.length):h),o?o(null,u,h,c):a.apply(u,h)}))}(c>1&&De(d),c>1&&Y(t.slice(0,c-1).concat({value:"" ""===t[c-2].type?""*"":""""})).replace(D,""$1""),r,c0,r=l.length>0,i=function(e,t,i,o,s){var c,f,p,d=0,h=""0"",g=e&&[],v=[],y=ie,m=e|| + r&&T.expr.find.TAG(""*"",s),x=ue+=null==y?1:Math.random()||.1;for(s&&(ie=t==oe||t||s);null!=(c=m[h]);h++){if(r&&c){f=0,t||c.ownerDocument==oe||(Ee(c),i=!se);while(p=l[f++])if(p(c,t||oe,i)){a.call(o,c);break}s&&(ue=x)}n&&((c=!p&&c)&&d--,e&&g.push(c))}if(d+=h,n&&h!==d){f=0;while(p=u[f++])p(g,v,t,i);if(e){if(d>0)while(h--)g[h]||v[h]||(v[h]=j.call(o));v=Ae(v)}a.apply(o,v),s&&!e&&v.length>0&&d+u.length>1&&T.uniqueSort(o)}return s&&(ue=x,ie=y),g},n?Te(i):i))).selector=e}return c}function Ne(e,t,n,r){ + var i,o,s,u,l,c=""function""==typeof e&&e,f=!r&&V(e=c.selector||e);if(n=n||[],1===f.length){if((o=f[0]=f[0].slice(0)).length>2&&""ID""===(s=o[0]).type&&9===t.nodeType&&se&&T.expr.relative[o[1].type]){if(!(t=(T.expr.find.ID(_(s.matches[0]),t)||[])[0]))return n;c&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=ge.needsContext.test(e)?0:o.length;while(i--){if(s=o[i],T.expr.relative[u=s.type])break;if((l=T.expr.find[u])&&(r=l(_(s.matches[0]),O.test(o[0].type)&&R(t.parentNode)||t))){if(o.splice(i, + 1),!(e=r.length&&Y(o)))return a.apply(n,r),n;break}}}return(c||qe(e,f))(r,t,!se,n,!t||O.test(e)&&R(t.parentNode)||t),n}function Oe(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&T(e).is(n))break;r.push(e)}return r}function He(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}ke.prototype=T.expr.filters=T.expr.pseudos,T.expr.setFilters=new ke,Ee(),T.find=we,we.compile=qe,we.select=Ne,we.setDocument=Ee,we.tokenize=V;var + Le=T.expr.match.needsContext,Pe=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function Re(e){return""<""===e[0]&&"">""===e[e.length-1]&&e.length>=3}function Me(e,t,n){return""function""==typeof t?T.grep(e,(function(e,r){return!!t.call(e,r,e)!==n})):t.nodeType?T.grep(e,(function(e){return e===t!==n})):""string""!=typeof t?T.grep(e,(function(e){return s.call(t,e)>-1!==n})):T.filter(t,e,n)}T.filter=function(e,t,n){var r=t[0];return(n&&(e="":not(""+e+"")""),1===t.length&&1===r.nodeType) + ?T.find.matchesSelector(r,e)?[r]:[]:T.find.matches(e,T.grep(t,(function(e){return 1===e.nodeType})))},T.fn.extend({find:function(e){var t,n,r=this.length,i=this;if(""string""!=typeof e)return this.pushStack(T(e).filter((function(){for(t=0;t1?T.uniqueSort(n):n},filter:function(e){return this.pushStack(Me(this,e||[],!1))},not:function(e){return this.pushStack(Me(this,e||[],!0))},is:function( + e){return!!Me(this,""string""==typeof e&&Le.test(e)?T(e):e||[],!1).length}});var We,Ie=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(T.fn.init=function(e,t){var n,r;if(!e)return this;if(e.nodeType)return this[0]=e,this.length=1,this;if(""function""==typeof e)return void 0!==We.ready?We.ready(e):e(T);if(Re(n=e+""""))n=[null,e,null];else{if(""string""!=typeof e)return T.makeArray(e,this);n=Ie.exec(e)}if(n&&(n[1]||!t)){if(!n[1])return(r=y.getElementById(n[2]))&&(this[0]=r,this.length=1),this;if(t=t instanceof + T?t[0]:t,T.merge(this,T.parseHTML(n[1],t&&t.nodeType?t.ownerDocument||t:y,!0)),Pe.test(n[1])&&T.isPlainObject(t))for(n in t)""function""==typeof this[n]?this[n](t[n]):this.attr(n,t[n]);return this}return!t||t.jquery?(t||We).find(e):this.constructor(t).find(e)}).prototype=T.fn,We=T(y);var $e=/^(?:parents|prev(?:Until|All))/,Fe={children:!0,contents:!0,next:!0,prev:!0};function Be(e,t){while((e=e[t])&&1!==e.nodeType);return e}function _e(e){return e}function Ue(e){throw e}function Xe(e,t,n,r){var i; + try{e&&""function""==typeof(i=e.promise)?i.call(e).done(t).fail(n):e&&""function""==typeof(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n(e)}}T.fn.extend({has:function(e){var t=T(e,this),n=t.length;return this.filter((function(){for(var e=0;e-1: + 1===n.nodeType&&T.find.matchesSelector(n,e))){o.push(n);break}}return this.pushStack(o.length>1?T.uniqueSort(o):o)},index:function(e){return e?""string""==typeof e?s.call(T(e),this[0]):s.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(T.uniqueSort(T.merge(this.get(),T(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),T.each({parent:function(e){var t=e.parentNode;return + t&&11!==t.nodeType?t:null},parents:function(e){return Oe(e,""parentNode"")},parentsUntil:function(e,t,n){return Oe(e,""parentNode"",n)},next:function(e){return Be(e,""nextSibling"")},prev:function(e){return Be(e,""previousSibling"")},nextAll:function(e){return Oe(e,""nextSibling"")},prevAll:function(e){return Oe(e,""previousSibling"")},nextUntil:function(e,t,n){return Oe(e,""nextSibling"",n)},prevUntil:function(e,t,n){return Oe(e,""previousSibling"",n)},siblings:function(e){return He((e.parentNode||{}) + .firstChild,e)},children:function(e){return He(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(C(e,""template"")&&(e=e.content||e),T.merge([],e.childNodes))}},(function(e,t){T.fn[e]=function(n,r){var i=T.map(this,t,n);return""Until""!==e.slice(-5)&&(r=n),r&&""string""==typeof r&&(i=T.filter(r,i)),this.length>1&&(Fe[e]||T.uniqueSort(i),$e.test(e)&&i.reverse()),this.pushStack(i)}})),T.Callbacks=function(e){e=""string""==typeof e?(t=e,n={},T.each( + t.match(Q)||[],(function(e,t){n[t]=!0})),n):T.extend({},e);var t,n,r,i,o,a,s=[],u=[],l=-1,c=function(){for(a=a||e.once,o=r=!0;u.length;l=-1){i=u.shift();while(++l-1)s.splice(n,1),n<=l&&l--})),this},has:function(e){return e?T.inArray(e,s)>-1:s.length>0},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=i="""",this},disabled:function(){return!s},lock:function(){return a=u=[],i||r||(s=i=""""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),r||c()),this},fire:function(){return f.fireWith( + this,arguments),this},fired:function(){return!!o}};return f},T.extend({Deferred:function(t){var n=[[""notify"",""progress"",T.Callbacks(""memory""),T.Callbacks(""memory""),2],[""resolve"",""done"",T.Callbacks(""once memory""),T.Callbacks(""once memory""),0,""resolved""],[""reject"",""fail"",T.Callbacks(""once memory""),T.Callbacks(""once memory""),1,""rejected""]],r=""pending"",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},catch:function(e){return i.then(null,e)},pipe: + function(){var e=arguments;return T.Deferred((function(t){T.each(n,(function(n,r){var i=""function""==typeof e[r[4]]&&e[r[4]];o[r[1]]((function(){var e=i&&i.apply(this,arguments);e&&""function""==typeof e.promise?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+""With""](this,i?[e]:arguments)}))})),e=null})).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t=o&&(r!==Ue&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(T.Deferred.getErrorHook&&(c.error=T.Deferred.getErrorHook()),e.setTimeout( + c))}}return T.Deferred((function(e){n[0][3].add(a(0,e,""function""==typeof i?i:_e,e.notifyWith)),n[1][3].add(a(0,e,""function""==typeof t?t:_e)),n[2][3].add(a(0,e,""function""==typeof r?r:Ue))})).promise()},promise:function(e){return null!=e?T.extend(e,i):i}},o={};return T.each(n,(function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add((function(){r=s}),n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+""With""](this===o?void 0:this, + arguments),this},o[t[0]+""With""]=a.fireWith})),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),o=i.call(arguments),a=T.Deferred(),s=function(e){return function(n){r[e]=this,o[e]=arguments.length>1?i.call(arguments):n,--t||a.resolveWith(r,o)}};if(t<=1&&(Xe(e,a.done(s(n)).resolve,a.reject,!t),""pending""===a.state()||""function""==typeof(o[n]&&o[n].then)))return a.then();while(n--)Xe(o[n],s(n),a.reject);return a.promise()}});var ze= + /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;T.Deferred.exceptionHook=function(t,n){t&&ze.test(t.name)&&e.console.warn(""jQuery.Deferred exception"",t,n)},T.readyException=function(t){e.setTimeout((function(){throw t}))};var Ve=T.Deferred();function Ye(){y.removeEventListener(""DOMContentLoaded"",Ye),e.removeEventListener(""load"",Ye),T.ready()}T.fn.ready=function(e){return Ve.then(e).catch((function(e){T.readyException(e)})),this},T.extend({isReady:!1,readyWait:1,ready:function(e){!(!0===e?--T.readyWait:T.isReady)&&( + T.isReady=!0,!0!==e&&--T.readyWait>0||Ve.resolveWith(y,[T]))}}),T.ready.then=Ve.then,""loading""!==y.readyState?e.setTimeout(T.ready):(y.addEventListener(""DOMContentLoaded"",Ye),e.addEventListener(""load"",Ye));var Ge=/-([a-z])/g;function Qe(e,t){return t.toUpperCase()}function Je(e){return e.replace(Ge,Qe)}function Ke(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType}function Ze(){this.expando=T.expando+Ze.uid++}Ze.uid=1,Ze.prototype={cache:function(e){var t=e[this.expando];return!t&&( + t=Object.create(null),Ke(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if(""string""==typeof t)i[Je(t)]=n;else for(r in t)i[Je(r)]=t[r];return n},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][Je(t)]},access:function(e,t,n){return void 0===t||t&&""string""==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[ + this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(Je):(t=Je(t))in r?[t]:t.match(Q)||[]).length;while(n--)delete r[t[n]]}(void 0===t||T.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!T.isEmptyObject(t)}};var et=new Ze,tt=new Ze,nt=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,rt=/[A-Z]/g;function it(e,t,n){var r,i;if(void 0===n&&1===e.nodeType){if(r=""data-""+t.replace(rt,""-$&"").toLowerCase(), + ""string""==typeof(n=e.getAttribute(r))){try{i=n,n=""true""===i||""false""!==i&&(""null""===i?null:i===+i+""""?+i:nt.test(i)?JSON.parse(i):i)}catch(e){}tt.set(e,t,n)}else n=void 0}return n}T.extend({hasData:function(e){return tt.hasData(e)||et.hasData(e)},data:function(e,t,n){return tt.access(e,t,n)},removeData:function(e,t){tt.remove(e,t)},_data:function(e,t,n){return et.access(e,t,n)},_removeData:function(e,t){et.remove(e,t)}}),T.fn.extend({data:function(e,t){var n,r,i,o=this[0],a=o&&o.attributes;if( + void 0===e){if(this.length&&(i=tt.get(o),1===o.nodeType&&!et.get(o,""hasDataAttrs""))){n=a.length;while(n--)a[n]&&0===(r=a[n].name).indexOf(""data-"")&&it(o,r=Je(r.slice(5)),i[r]);et.set(o,""hasDataAttrs"",!0)}return i}return""object""==typeof e?this.each((function(){tt.set(this,e)})):G(this,(function(t){var n;if(o&&void 0===t)return void 0!==(n=tt.get(o,e))||void 0!==(n=it(o,e))?n:void 0;this.each((function(){tt.set(this,e,t)}))}),null,t,arguments.length>1,null,!0)},removeData:function(e){return + this.each((function(){tt.remove(this,e)}))}}),T.extend({queue:function(e,t,n){var r;if(e)return t=(t||""fx"")+""queue"",r=et.get(e,t),n&&(!r||Array.isArray(n)?r=et.set(e,t,T.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||""fx"";var n=T.queue(e,t),r=n.length,i=n.shift(),o=T._queueHooks(e,t);""inprogress""===i&&(i=n.shift(),r--),i&&(""fx""===t&&n.unshift(""inprogress""),delete o.stop,i.call(e,(function(){T.dequeue(e,t)}),o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+""queueHooks""; + return et.get(e,n)||et.set(e,n,{empty:T.Callbacks(""once memory"").add((function(){et.remove(e,[t+""queue"",n])}))})}}),T.fn.extend({queue:function(e,t){var n=2;return(""string""!=typeof e&&(t=e,e=""fx"",n--),arguments.length\x20\t\r\n\f]*)/i,bt={thead:[""table""],col:[""colgroup"",""table""],tr:[""tbody"",""table""],td:[""tr"",""tbody"",""table""]};function wt(e,t){var n;return(n=void 0!==e.getElementsByTagName?e.getElementsByTagName(t||""*""):void 0!==e.querySelectorAll?e.querySelectorAll(t||""*""):[],void 0===t||t&&C(e,t))?T.merge([e],n):n} + bt.tbody=bt.tfoot=bt.colgroup=bt.caption=bt.thead,bt.th=bt.td;var Tt=/^$|^module$|\/(?:java|ecma)script/i;function Ct(e,t){for(var n=0,r=e.length;n-1)s=s.appendChild(t.createElement(u[c]));s.innerHTML=T.htmlPrefilter(a),T.merge(p,s.childNodes),(s=f.firstChild).textContent=""""}else p.push(t.createTextNode(a))}f.textContent="""",d=0;while(a=p[d++]){if(i&&T.inArray(a,i)>-1){o&&o.push(a);continue}if(l=yt(a),s=wt(f.appendChild(a),""script""),l&&Ct(s),r){c=0;while(a=s[c++])Tt.test(a.type||"""")&&r.push(a)}}return f}function kt(e){return e.type=(null!==e.getAttribute(""type""))+""/""+e.type,e}function St(e){ + return""true/""===(e.type||"""").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute(""type""),e}function Dt(e,t,n,r){t=o(t);var i,a,s,u,l,c,f=0,p=e.length,d=p-1,h=t[0];if(""function""==typeof h)return e.each((function(i){var o=e.eq(i);t[0]=h.call(this,i,o.html()),Dt(o,t,n,r)}));if(p&&(a=(i=Et(t,e[0].ownerDocument,!1,e,r)).firstChild,1===i.childNodes.length&&(i=a),a||r)){for(u=(s=T.map(wt(i,""script""),kt)).length;f=1)){for(;l!==this; + l=l.parentNode||this)if(1===l.nodeType&&!(""click""===e.type&&!0===l.disabled)){for(n=0,o=[],a={};n-1:T.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}}return l=this,u0&&Ct(a,!u&&wt(e,""script"")),s},cleanData:function(e){for(var t,n,r,i=T.event.special,o=0;void 0!==(n=e[o]);o++)if(Ke(n)){if(t=n[et.expando]){ + if(t.events)for(r in t.events)i[r]?T.event.remove(n,r):T.removeEvent(n,r,t.handle);n[et.expando]=void 0}n[tt.expando]&&(n[tt.expando]=void 0)}}}),T.fn.extend({detach:function(e){return Wt(this,e,!0)},remove:function(e){return Wt(this,e)},text:function(e){return G(this,(function(e){return void 0===e?T.text(this):this.empty().each((function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=e)}))}),null,e,arguments.length)},append:function(){return Dt(this,arguments,( + function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&Rt(this,e).appendChild(e)}))},prepend:function(){return Dt(this,arguments,(function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Rt(this,e);t.insertBefore(e,t.firstChild)}}))},before:function(){return Dt(this,arguments,(function(e){this.parentNode&&this.parentNode.insertBefore(e,this)}))},after:function(){return Dt(this,arguments,(function(e){this.parentNode&&this.parentNode.insertBefore(e, + this.nextSibling)}))},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(T.cleanData(wt(e,!1)),e.textContent="""");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map((function(){return T.clone(this,e,t)}))},html:function(e){return G(this,(function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if(""string""==typeof e&&!Pt.test(e)&&!bt[(xt.exec(e)||["""",""""])[1].toLowerCase()]){e=T.htmlPrefilter(e);try{for(;nT.inArray(this,e)&&(T.cleanData(wt(this)),n&&n.replaceChild(t,this))}),e)}}),T.each({appendTo:""append"",prependTo:""prepend"",insertBefore:""before"",insertAfter:""after"",replaceAll:""replaceWith""},(function(e,t){T.fn[e]=function(e){for(var n,r=[],i=T(e),o=i.length-1,s=0;s<=o; + s++)n=s===o?this:this.clone(!0),T(i[s])[t](n),a.apply(r,n);return this.pushStack(r)}}));var It=RegExp(""^(""+ot+"")(?!px)[a-z%]+$"",""i""),$t=/^--/;function Ft(t){var n=t.ownerDocument.defaultView;return n||(n=e),n.getComputedStyle(t)}function Bt(e,t,n){var r,i=$t.test(t);return(n=n||Ft(e))&&(r=n.getPropertyValue(t)||n[t],i&&r&&(r=r.replace(D,""$1"")||void 0),""""!==r||yt(e)||(r=T.style(e,t))),void 0!==r?r+"""":r}var _t=[""Webkit"",""Moz"",""ms""],Ut=y.createElement(""div"").style,Xt={};function zt(e){return Xt[ + e]||(e in Ut?e:Xt[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=_t.length;while(n--)if((e=_t[n]+t)in Ut)return e}(e)||e)}(tn=y.createElement(""div"")).style&&(d.reliableTrDimensions=function(){var t,n,r;if(null==en){if(t=y.createElement(""table""),n=y.createElement(""tr""),t.style.cssText=""position:absolute;left:-11111px;border-collapse:separate"",n.style.cssText=""box-sizing:content-box;border:1px solid"",n.style.height=""1px"",tn.style.height=""9px"",tn.style.display=""block"",H.appendChild(t) + .appendChild(n).appendChild(tn),0===t.offsetWidth){H.removeChild(t);return}en=parseInt((r=e.getComputedStyle(n)).height,10)+parseInt(r.borderTopWidth,10)+parseInt(r.borderBottomWidth,10)===n.offsetHeight,H.removeChild(t)}return en});var Vt=/^(none|table(?!-c[ea]).+)/,Yt={position:""absolute"",visibility:""hidden"",display:""block""},Gt={letterSpacing:""0"",fontWeight:""400""};function Qt(e,t,n){var r=at.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||""px""):t}function Jt(e,t,n,r,i,o){var a=""width""===t?1:0, + s=0,u=0,l=0;if(n===(r?""border"":""content""))return 0;for(;a<4;a+=2)""margin""===n&&(l+=T.css(e,n+st[a],!0,i)),r?(""content""===n&&(u-=T.css(e,""padding""+st[a],!0,i)),""margin""!==n&&(u-=T.css(e,""border""+st[a]+""Width"",!0,i))):(u+=T.css(e,""padding""+st[a],!0,i),""padding""!==n?u+=T.css(e,""border""+st[a]+""Width"",!0,i):s+=T.css(e,""border""+st[a]+""Width"",!0,i));return!r&&o>=0&&(u+=Math.max(0,Math.ceil(e[""offset""+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u+l}function Kt(e,t,n){var r=Ft(e),i=(k||n)&&""border-box""=== + T.css(e,""boxSizing"",!1,r),o=i,a=Bt(e,t,r),s=""offset""+t[0].toUpperCase()+t.slice(1);if(It.test(a)){if(!n)return a;a=""auto""}return(""auto""===a||k&&i||!d.reliableTrDimensions()&&C(e,""tr""))&&e.getClientRects().length&&(i=""border-box""===T.css(e,""boxSizing"",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+Jt(e,t,n||(i?""border"":""content""),o,r,a)+""px""}function Zt(e,t,n,r,i){return new Zt.prototype.init(e,t,n,r,i)}T.extend({cssHooks:{},style:function(e,t,n,r){if( + e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=ht(t),u=$t.test(t),l=e.style;if(u||(t=zt(s)),a=T.cssHooks[t]||T.cssHooks[s],void 0===n)return a&&""get""in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];""string""==(o=typeof n)&&(i=at.exec(n))&&i[1]&&(n=pt(e,t,i),o=""number""),null!=n&&n==n&&(""number""===o&&(n+=i&&i[3]||(ft(s)?""px"":"""")),k&&""""===n&&0===t.indexOf(""background"")&&(l[t]=""inherit""),a&&""set""in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=ht(t); + return($t.test(t)||(t=zt(s)),(a=T.cssHooks[t]||T.cssHooks[s])&&""get""in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Bt(e,t,r)),""normal""===i&&t in Gt&&(i=Gt[t]),""""===n||n)?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),T.each([""height"",""width""],(function(e,t){T.cssHooks[t]={get:function(e,n,r){if(n)return!Vt.test(T.css(e,""display""))||e.getClientRects().length&&e.getBoundingClientRect().width?Kt(e,t,r):function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t) + e.style[i]=o[i];return r}(e,Yt,(function(){return Kt(e,t,r)}))},set:function(e,n,r){var i,o=Ft(e),a=r&&""border-box""===T.css(e,""boxSizing"",!1,o),s=r?Jt(e,t,r,a,o):0;return s&&(i=at.exec(n))&&""px""!==(i[3]||""px"")&&(e.style[t]=n,n=T.css(e,t)),Qt(e,n,s)}}})),T.each({margin:"""",padding:"""",border:""Width""},(function(e,t){T.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o=""string""==typeof n?n.split("" ""):[n];r<4;r++)i[e+st[r]+t]=o[r]||o[r-2]||o[0];return i}},""margin""!==e&&(T.cssHooks[e+t].set=Qt)})), + T.fn.extend({css:function(e,t){return G(this,(function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Ft(e),i=t.length;a1)}}),T.Tween=Zt,Zt.prototype={constructor:Zt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||T.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(ft(n)?""px"":"""")},cur:function(){var e=Zt.propHooks[this.prop]; + return e&&e.get?e.get(this):Zt.propHooks._default.get(this)},run:function(e){var t,n=Zt.propHooks[this.prop];return this.options.duration?this.pos=t=T.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Zt.propHooks._default.set(this),this}},Zt.prototype.init.prototype=Zt.prototype,Zt.propHooks={_default:{get:function(e){var t; + return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=T.css(e.elem,e.prop,""""))&&""auto""!==t?t:0},set:function(e){T.fx.step[e.prop]?T.fx.step[e.prop](e):1===e.elem.nodeType&&(T.cssHooks[e.prop]||null!=e.elem.style[zt(e.prop)])?T.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},T.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:""swing""},T.fx=Zt.prototype.init,T.fx.step={};var en,tn,nn,rn,on= + /^(?:toggle|show|hide)$/,an=/queueHooks$/;function sn(){return e.setTimeout((function(){nn=void 0})),nn=Date.now()}function un(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i[""margin""+(n=st[r])]=i[""padding""+n]=e;return t&&(i.opacity=i.width=e),i}function ln(e,t,n){for(var r,i=(cn.tweeners[t]||[]).concat(cn.tweeners[""*""]),o=0,a=i.length;o1)},removeProp:function(e){return this.each((function(){delete this[T.propFix[e]||e]}))}}),T.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return(1===o&&T.isXMLDoc(e)||(t=T.propFix[t]||t,i=T.propHooks[t]),void 0!==n)?i&&""set""in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&""get""in + i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=e.getAttribute(""tabindex"");return t?parseInt(t,10):fn.test(e.nodeName)||pn.test(e.nodeName)&&e.href?0:-1}}},propFix:{for:""htmlFor"",class:""className""}}),k&&(T.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),T.each([""tabIndex"",""readOnly"",""maxLength"", + ""cellSpacing"",""cellPadding"",""rowSpan"",""colSpan"",""useMap"",""frameBorder"",""contentEditable""],(function(){T.propFix[this.toLowerCase()]=this})),T.fn.extend({addClass:function(e){var t,n,r,i,o,a;return""function""==typeof e?this.each((function(t){T(this).addClass(e.call(this,t,hn(this)))})):(t=gn(e)).length?this.each((function(){if(r=hn(this),n=1===this.nodeType&&"" ""+dn(r)+"" ""){for(o=0;on.indexOf("" ""+i+"" "")&&(n+=i+"" "");r!==(a=dn(n))&&this.setAttribute(""class"",a)}})):this}, + removeClass:function(e){var t,n,r,i,o,a;return""function""==typeof e?this.each((function(t){T(this).removeClass(e.call(this,t,hn(this)))})):arguments.length?(t=gn(e)).length?this.each((function(){if(r=hn(this),n=1===this.nodeType&&"" ""+dn(r)+"" ""){for(o=0;o-1)n=n.replace("" ""+i+"" "","" "")}r!==(a=dn(n))&&this.setAttribute(""class"",a)}})):this:this.attr(""class"","""")},toggleClass:function(e,t){var n,r,i,o;return""function""==typeof e?this.each((function(n){T( + this).toggleClass(e.call(this,n,hn(this),t),t)})):""boolean""==typeof t?t?this.addClass(e):this.removeClass(e):(n=gn(e)).length?this.each((function(){for(i=0,o=T(this);i-1)return!0;return!1}}),T.fn.extend({val:function(e){var t,n,r,i=this[0];return arguments.length?(r=""function""==typeof e,this.each((function(n){ + var i;1===this.nodeType&&(null==(i=r?e.call(this,n,T(this).val()):e)?i="""":""number""==typeof i?i+="""":Array.isArray(i)&&(i=T.map(i,(function(e){return null==e?"""":e+""""}))),(t=T.valHooks[this.type]||T.valHooks[this.nodeName.toLowerCase()])&&""set""in t&&void 0!==t.set(this,i,""value"")||(this.value=i))}))):i?(t=T.valHooks[i.type]||T.valHooks[i.nodeName.toLowerCase()])&&""get""in t&&void 0!==(n=t.get(i,""value""))?n:null==(n=i.value)?"""":n:void 0}}),T.extend({valHooks:{select:{get:function(e){var t,n,r, + i=e.options,o=e.selectedIndex,a=""select-one""===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),k&&(T.valHooks.option={get:function(e){var t=e.getAttribute(""value"");return + null!=t?t:dn(T.text(e))}}),T.each([""radio"",""checkbox""],(function(){T.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=T.inArray(T(e).val(),t)>-1}}}));var vn=/^(?:focusinfocus|focusoutblur)$/,yn=function(e){e.stopPropagation()};T.extend(T.event,{trigger:function(t,n,r,i){var o,a,s,u,l,f,p,d,h=[r||y],v=c.call(t,""type"")?t.type:t,m=c.call(t,""namespace"")?t.namespace.split("".""):[];if(a=d=s=r=r||y,!(3===r.nodeType||8===r.nodeType||vn.test(v+T.event.triggered))&&(v.indexOf(""."")>- + 1&&(v=(m=v.split(""."")).shift(),m.sort()),l=0>v.indexOf("":"")&&""on""+v,(t=t[T.expando]?t:new T.Event(v,""object""==typeof t&&t)).isTrigger=i?2:3,t.namespace=m.join("".""),t.rnamespace=t.namespace?RegExp(""(^|\\.)""+m.join(""\\.(?:.*\\.|)"")+""(\\.|$)""):null,t.result=void 0,t.target||(t.target=r),n=null==n?[t]:T.makeArray(n,[t]),p=T.event.special[v]||{},i||!p.trigger||!1!==p.trigger.apply(r,n))){if(!i&&!p.noBubble&&!g(r)){for(u=p.delegateType||v,vn.test(u+v)||(a=a.parentNode);a;a=a.parentNode)h.push(a),s=a; + s===(r.ownerDocument||y)&&h.push(s.defaultView||s.parentWindow||e)}o=0;while((a=h[o++])&&!t.isPropagationStopped())d=a,t.type=o>1?u:p.bindType||v,(f=(et.get(a,""events"")||Object.create(null))[t.type]&&et.get(a,""handle""))&&f.apply(a,n),(f=l&&a[l])&&f.apply&&Ke(a)&&(t.result=f.apply(a,n),!1===t.result&&t.preventDefault());return t.type=v,!i&&!t.isDefaultPrevented()&&(!p._default||!1===p._default.apply(h.pop(),n))&&Ke(r)&&l&&""function""==typeof r[v]&&!g(r)&&((s=r[l])&&(r[l]=null),T.event.triggered=v, + t.isPropagationStopped()&&d.addEventListener(v,yn),r[v](),t.isPropagationStopped()&&d.removeEventListener(v,yn),T.event.triggered=void 0,s&&(r[l]=s)),t.result}},simulate:function(e,t,n){var r=T.extend(new T.Event,n,{type:e,isSimulated:!0});T.event.trigger(r,null,t)}}),T.fn.extend({trigger:function(e,t){return this.each((function(){T.event.trigger(e,t,this)}))},triggerHandler:function(e,t){var n=this[0];if(n)return T.event.trigger(e,t,n,!0)}});var mn=e.location,xn={guid:Date.now()},bn=/\?/; + T.parseXML=function(t){var n,r;if(!t||""string""!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,""text/xml"")}catch(e){}return r=n&&n.getElementsByTagName(""parsererror"")[0],(!n||r)&&T.error(""Invalid XML: ""+(r?T.map(r.childNodes,(function(e){return e.textContent})).join(""\n""):t)),n};var wn=/\[\]$/,Tn=/\r?\n/g,Cn=/^(?:submit|button|image|reset|file)$/i,jn=/^(?:input|select|textarea|keygen)/i;T.param=function(e,t){var n,r=[],i=function(e,t){var n=""function""==typeof t?t():t;r[r.length] + =encodeURIComponent(e)+""=""+encodeURIComponent(null==n?"""":n)};if(null==e)return"""";if(Array.isArray(e)||e.jquery&&!T.isPlainObject(e))T.each(e,(function(){i(this.name,this.value)}));else for(n in e)!function e(t,n,r,i){var o;if(Array.isArray(n))T.each(n,(function(n,o){r||wn.test(t)?i(t,o):e(t+""[""+(""object""==typeof o&&null!=o?n:"""")+""]"",o,r,i)}));else if(r||""object""!==h(n))i(t,n);else for(o in n)e(t+""[""+o+""]"",n[o],r,i)}(n,e[n],t,i);return r.join(""&"")},T.fn.extend({serialize:function(){return + T.param(this.serializeArray())},serializeArray:function(){return this.map((function(){var e=T.prop(this,""elements"");return e?T.makeArray(e):this})).filter((function(){var e=this.type;return this.name&&!T(this).is("":disabled"")&&jn.test(this.nodeName)&&!Cn.test(e)&&(this.checked||!At.test(e))})).map((function(e,t){var n=T(this).val();return null==n?null:Array.isArray(n)?T.map(n,(function(e){return{name:t.name,value:e.replace(Tn,""\r\n"")}})):{name:t.name,value:n.replace(Tn,""\r\n"")}})).get()}});var + En=/%20/g,kn=/#.*$/,Sn=/([?&])_=[^&]*/,Dn=/^(.*?):[ \t]*([^\r\n]*)$/gm,An=/^(?:GET|HEAD)$/,qn=/^\/\//,Nn={},On={},Hn=""*/"".concat(""*""),Ln=y.createElement(""a"");function Pn(e){return function(t,n){""string""!=typeof t&&(n=t,t=""*"");var r,i=0,o=t.toLowerCase().match(Q)||[];if(""function""==typeof n)while(r=o[i++])""+""===r[0]?(e[r=r.slice(1)||""*""]=e[r]||[]).unshift(n):(e[r]=e[r]||[]).push(n)}}function Rn(e,t,n,r){var i={},o=e===On;function a(s){var u;return i[s]=!0,T.each(e[s]||[],(function(e,s){var l=s(t, + n,r);return""string""!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)})),u}return a(t.dataTypes[0])||!i[""*""]&&a(""*"")}function Mn(e,t){var n,r,i=T.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&T.extend(!0,e,r),e}Ln.href=mn.href,T.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:mn.href,type:""GET"",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(mn.protocol),global:!0,processData:!0,async:!0, + contentType:""application/x-www-form-urlencoded; charset=UTF-8"",accepts:{""*"":Hn,text:""text/plain"",html:""text/html"",xml:""application/xml, text/xml"",json:""application/json, text/javascript""},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:""responseXML"",text:""responseText"",json:""responseJSON""},converters:{""* text"":String,""text html"":!0,""text json"":JSON.parse,""text xml"":T.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Mn(Mn(e,T.ajaxSettings),t): + Mn(T.ajaxSettings,e)},ajaxPrefilter:Pn(Nn),ajaxTransport:Pn(On),ajax:function(t,n){""object""==typeof t&&(n=t,t=void 0),n=n||{};var r,i,o,a,s,u,l,c,f,p,d=T.ajaxSetup({},n),h=d.context||d,g=d.context&&(h.nodeType||h.jquery)?T(h):T.event,v=T.Deferred(),m=T.Callbacks(""once memory""),x=d.statusCode||{},b={},w={},C=""canceled"",j={readyState:0,getResponseHeader:function(e){var t;if(l){if(!a){a={};while(t=Dn.exec(o))a[t[1].toLowerCase()+"" ""]=(a[t[1].toLowerCase()+"" ""]||[]).concat(t[2])}t=a[e.toLowerCase()+ + "" ""]}return null==t?null:t.join("", "")},getAllResponseHeaders:function(){return l?o:null},setRequestHeader:function(e,t){return null==l&&(b[e=w[e.toLowerCase()]=w[e.toLowerCase()]||e]=t),this},overrideMimeType:function(e){return null==l&&(d.mimeType=e),this},statusCode:function(e){var t;if(e){if(l)j.always(e[j.status]);else for(t in e)x[t]=[x[t],e[t]]}return this},abort:function(e){var t=e||C;return r&&r.abort(t),E(0,t),this}};if(v.promise(j),d.url=((t||d.url||mn.href)+"""").replace(qn,mn.protocol+ + ""//""),d.type=n.method||n.type||d.method||d.type,d.dataTypes=(d.dataType||""*"").toLowerCase().match(Q)||[""""],null==d.crossDomain){u=y.createElement(""a"");try{u.href=d.url,u.href=u.href,d.crossDomain=Ln.protocol+""//""+Ln.host!=u.protocol+""//""+u.host}catch(e){d.crossDomain=!0}}if(Rn(Nn,d,n,j),d.data&&d.processData&&""string""!=typeof d.data&&(d.data=T.param(d.data,d.traditional)),l)return j;for(f in(c=T.event&&d.global)&&0==T.active++&&T.event.trigger(""ajaxStart""),d.type=d.type.toUpperCase(), + d.hasContent=!An.test(d.type),i=d.url.replace(kn,""""),d.hasContent?d.data&&d.processData&&0===(d.contentType||"""").indexOf(""application/x-www-form-urlencoded"")&&(d.data=d.data.replace(En,""+"")):(p=d.url.slice(i.length),d.data&&(d.processData||""string""==typeof d.data)&&(i+=(bn.test(i)?""&"":""?"")+d.data,delete d.data),!1===d.cache&&(i=i.replace(Sn,""$1""),p=(bn.test(i)?""&"":""?"")+""_=""+xn.guid+++p),d.url=i+p),d.ifModified&&(T.lastModified[i]&&j.setRequestHeader(""If-Modified-Since"",T.lastModified[i]),T.etag[ + i]&&j.setRequestHeader(""If-None-Match"",T.etag[i])),(d.data&&d.hasContent&&!1!==d.contentType||n.contentType)&&j.setRequestHeader(""Content-Type"",d.contentType),j.setRequestHeader(""Accept"",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(""*""!==d.dataTypes[0]?"", ""+Hn+""; q=0.01"":""""):d.accepts[""*""]),d.headers)j.setRequestHeader(f,d.headers[f]);if(d.beforeSend&&(!1===d.beforeSend.call(h,j,d)||l))return j.abort();if(C=""abort"",m.add(d.complete),j.done(d.success),j.fail(d.error),r=Rn( + On,d,n,j)){if(j.readyState=1,c&&g.trigger(""ajaxSend"",[j,d]),l)return j;d.async&&d.timeout>0&&(s=e.setTimeout((function(){j.abort(""timeout"")}),d.timeout));try{l=!1,r.send(b,E)}catch(e){if(l)throw e;E(-1,e)}}else E(-1,""No Transport"");function E(t,n,a,u){var f,p,y,b,w,C=n;!l&&(l=!0,s&&e.clearTimeout(s),r=void 0,o=u||"""",j.readyState=t>0?4:0,f=t>=200&&t<300||304===t,a&&(b=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while(""*""===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader( + ""Content-Type""));if(r){for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+"" ""+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(d,j,a)),!f&&T.inArray(""script"",d.dataTypes)>-1&&0>T.inArray(""json"",d.dataTypes)&&(d.converters[""text script""]=function(){}),b=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if( + e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift()){if(""*""===o)o=u;else if(""*""!==u&&u!==o){if(!(a=l[u+"" ""+o]||l[""* ""+o])){for(i in l)if((s=i.split("" ""))[1]===o&&(a=l[u+"" ""+s[0]]||l[""* ""+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}}if(!0!==a){if(a&&e.throws)t=a(t);else try{t=a(t)}catch(e){return{state:""parsererror"",error:a?e:""No conversion from ""+u+"" to ""+o}}}}}return{state:""success"",data:t}}(d,b,j,f),f?( + d.ifModified&&((w=j.getResponseHeader(""Last-Modified""))&&(T.lastModified[i]=w),(w=j.getResponseHeader(""etag""))&&(T.etag[i]=w)),204===t||""HEAD""===d.type?C=""nocontent"":304===t?C=""notmodified"":(C=b.state,p=b.data,f=!(y=b.error))):(y=C,(t||!C)&&(C=""error"",t<0&&(t=0))),j.status=t,j.statusText=(n||C)+"""",f?v.resolveWith(h,[p,C,j]):v.rejectWith(h,[j,C,y]),j.statusCode(x),x=void 0,c&&g.trigger(f?""ajaxSuccess"":""ajaxError"",[j,d,f?p:y]),m.fireWith(h,[j,C]),!c||(g.trigger(""ajaxComplete"",[j,d]),--T.active|| + T.event.trigger(""ajaxStop"")))}return j},getJSON:function(e,t,n){return T.get(e,t,n,""json"")},getScript:function(e,t){return T.get(e,void 0,t,""script"")}}),T.each([""get"",""post""],(function(e,t){T[t]=function(e,n,r,i){return(""function""==typeof n||null===n)&&(i=i||r,r=n,n=void 0),T.ajax(T.extend({url:e,type:t,dataType:i,data:n,success:r},T.isPlainObject(e)&&e))}})),T.ajaxPrefilter((function(e){var t;for(t in e.headers)""content-type""===t.toLowerCase()&&(e.contentType=e.headers[t]||"""")})), + T._evalUrl=function(e,t,n){return T.ajax({url:e,type:""GET"",dataType:""script"",cache:!0,async:!1,global:!1,scriptAttrs:t.crossOrigin?{crossOrigin:t.crossOrigin}:void 0,converters:{""text script"":function(){}},dataFilter:function(e){T.globalEval(e,t,n)}})},T.fn.extend({wrapAll:function(e){var t;return this[0]&&(""function""==typeof e&&(e=e.call(this[0])),t=T(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map((function(){var e=this;while(e.firstElementChild) + e=e.firstElementChild;return e})).append(this)),this},wrapInner:function(e){return""function""==typeof e?this.each((function(t){T(this).wrapInner(e.call(this,t))})):this.each((function(){var t=T(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)}))},wrap:function(e){var t=""function""==typeof e;return this.each((function(n){T(this).wrapAll(t?e.call(this,n):e)}))},unwrap:function(e){return this.parent(e).not(""body"").each((function(){T(this).replaceWith(this.childNodes)})),this}}), + T.expr.pseudos.hidden=function(e){return!T.expr.pseudos.visible(e)},T.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},T.ajaxSettings.xhr=function(){return new e.XMLHttpRequest};var Wn={0:200};function In(e){return e.scriptAttrs||!e.headers&&(e.crossDomain||e.async&&0>T.inArray(""json"",e.dataTypes))}T.ajaxTransport((function(e){var t;return{send:function(n,r){var i,o=e.xhr();if(o.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for( + i in e.xhrFields)o[i]=e.xhrFields[i];for(i in e.mimeType&&o.overrideMimeType&&o.overrideMimeType(e.mimeType),e.crossDomain||n[""X-Requested-With""]||(n[""X-Requested-With""]=""XMLHttpRequest""),n)o.setRequestHeader(i,n[i]);t=function(e){return function(){t&&(t=o.onload=o.onerror=o.onabort=o.ontimeout=null,""abort""===e?o.abort():""error""===e?r(o.status,o.statusText):r(Wn[o.status]||o.status,o.statusText,""text""===(o.responseType||""text"")?{text:o.responseText}:{binary:o.response}, + o.getAllResponseHeaders()))}},o.onload=t(),o.onabort=o.onerror=o.ontimeout=t(""error""),t=t(""abort"");try{o.send(e.hasContent&&e.data||null)}catch(e){if(t)throw e}},abort:function(){t&&t()}}})),T.ajaxSetup({accepts:{script:""text/javascript, application/javascript, application/ecmascript, application/x-ecmascript""},converters:{""text script"":function(e){return T.globalEval(e),e}}}),T.ajaxPrefilter(""script"",(function(e){void 0===e.cache&&(e.cache=!1),In(e)&&(e.type=""GET"")})),T.ajaxTransport(""script"",( + function(e){if(In(e)){var t,n;return{send:function(r,i){t=T("""; + Parallel.Invoke(() => Assert(ctx1), () => Assert(ctx2)); + return; + + void Assert(IBrowsingContext context) => Task + .Run(async () => + { + var document = await context.OpenAsync(m => m.Content(html)); + var result = document.QuerySelector("#result").TextContent; + NUnit.Framework.Assert.AreEqual("foo", result); + }) + .Wait(); + } } } diff --git a/src/AngleSharp.Js.Tests/DeferredConstructorTests.cs b/src/AngleSharp.Js.Tests/DeferredConstructorTests.cs new file mode 100644 index 0000000..4cb9155 --- /dev/null +++ b/src/AngleSharp.Js.Tests/DeferredConstructorTests.cs @@ -0,0 +1,141 @@ +namespace AngleSharp.Js.Tests +{ + using NUnit.Framework; + using System.Threading.Tasks; + + /// + /// The constructor of an exposed type is only built once script reads the property it + /// is published under, so these cover what a reader is entitled to see either way. + /// + [TestFixture] + public class DeferredConstructorTests + { + [Test] + public async Task ConstructorIsSameObjectOnWindowAndGlobal() + { + var result = await "String(window.HTMLDivElement === HTMLDivElement)".EvalScriptAsync(); + Assert.AreEqual("true", result); + } + + [Test] + public async Task ConstructorIsSameObjectOnEveryRead() + { + var result = await "String((function () { var a = HTMLDivElement; var b = window.HTMLDivElement; return a === b && a === HTMLDivElement; })())".EvalScriptAsync(); + Assert.AreEqual("true", result); + } + + [Test] + public async Task ConstructorIsFunction() + { + var result = await "typeof HTMLDivElement".EvalScriptAsync(); + Assert.AreEqual("function", result); + } + + [Test] + public async Task UnreadConstructorIsStillOwnPropertyOfWindow() + { + var result = await "String(window.hasOwnProperty('HTMLTableColElement'))".EvalScriptAsync(); + Assert.AreEqual("true", result); + } + + [Test] + public async Task UnreadConstructorIsStillEnumerable() + { + var result = await "String(Object.keys(window).indexOf('HTMLTableColElement') !== -1)".EvalScriptAsync(); + Assert.AreEqual("true", result); + } + + [Test] + public async Task UnreadConstructorIsStillFoundByForIn() + { + var result = await "String((function () { for (var k in window) { if (k === 'HTMLTableColElement') { return true; } } return false; })())".EvalScriptAsync(); + Assert.AreEqual("true", result); + } + + [Test] + public async Task ConstructorKeepsItsAttributes() + { + var result = await "(function () { var d = Object.getOwnPropertyDescriptor(window, 'HTMLDivElement'); return d.writable + ',' + d.enumerable + ',' + d.configurable; })()".EvalScriptAsync(); + Assert.AreEqual("false,true,false", result); + } + + [Test] + public async Task DescriptorValueIsTheConstructor() + { + var result = await "String(Object.getOwnPropertyDescriptor(window, 'HTMLDivElement').value === HTMLDivElement)".EvalScriptAsync(); + Assert.AreEqual("true", result); + } + + [Test] + public async Task ReadingAConstructorDoesNotChangeTheKeysOfWindow() + { + var result = await "String((function () { var before = Object.keys(window).length; var c = HTMLDivElement; return before === Object.keys(window).length; })())".EvalScriptAsync(); + Assert.AreEqual("true", result); + } + + [Test] + public async Task ConstructedInstanceIsInstanceOfItsConstructor() + { + var result = await "String(new CustomEvent('foo') instanceof CustomEvent)".EvalScriptAsync(); + Assert.AreEqual("true", result); + } + + [Test] + public async Task ConstructorBuildsInstances() + { + var result = await "new CustomEvent('foo').type".EvalScriptAsync(); + Assert.AreEqual("foo", result); + } + + [Test] + public async Task PrototypePointsBackAtItsConstructor() + { + var result = await "String(HTMLDivElement.prototype.constructor === HTMLDivElement)".EvalScriptAsync(); + Assert.AreEqual("true", result); + } + + // Reaching a prototype through an instance is the one path that never names the + // type, so it is the one that has to pull the constructor in by itself. + [Test] + public async Task InstanceReportsItsConstructorWhenTheNameWasNeverRead() + { + var result = await "screen.constructor.name".EvalScriptAsync(); + Assert.AreEqual("Screen", result); + } + + [Test] + public async Task InstanceReportsTheSameConstructorTheWindowPublishes() + { + var result = await "String(screen.constructor === Screen)".EvalScriptAsync(); + Assert.AreEqual("true", result); + } + + [Test] + public async Task ConstructorIsNotWritable() + { + var result = await "String((function () { var before = HTMLDivElement; window.HTMLDivElement = 5; return window.HTMLDivElement === before; })())".EvalScriptAsync(); + Assert.AreEqual("true", result); + } + + [Test] + public async Task ConstructorIsNotConfigurable() + { + var result = await "String((delete window.HTMLDivElement) === false && typeof HTMLDivElement === 'function')".EvalScriptAsync(); + Assert.AreEqual("true", result); + } + + [Test] + public async Task ConstructorStringifiesAsNativeCode() + { + var result = await "String(HTMLDivElement)".EvalScriptAsync(); + Assert.AreEqual("function HTMLDivElement() { [native code] }", result); + } + + [Test] + public async Task NonConstructableTypeStillRejectsNew() + { + var result = await "(function () { try { new Node(); return 'no throw'; } catch (e) { return 'threw'; } })()".EvalScriptAsync(); + Assert.AreEqual("threw", result); + } + } +} diff --git a/src/AngleSharp.Js.Tests/DomTests.cs b/src/AngleSharp.Js.Tests/DomTests.cs new file mode 100644 index 0000000..c4baa29 --- /dev/null +++ b/src/AngleSharp.Js.Tests/DomTests.cs @@ -0,0 +1,296 @@ +namespace AngleSharp.Js.Tests +{ + using NUnit.Framework; + using System.Threading.Tasks; + + [TestFixture] + public class DomTests + { + [Test] + public async Task NodeHasChildNodesIsAFunction() + { + var result = await "document.createElement('div').hasChildNodes".EvalScriptAsync(); + Assert.AreEqual("function hasChildNodes() { [native code] }", result); + } + + [Test] + public async Task NodeHasChildNodesWithoutChildren() + { + var result = await "document.createElement('div').hasChildNodes()".EvalScriptAsync(); + Assert.AreEqual("False", result); + } + + [Test] + public async Task NodeHasChildNodesWithChildren() + { + var result = await "new DOMParser().parseFromString(`
`, 'text/html').body.firstChild.hasChildNodes()".EvalScriptAsync(); + Assert.AreEqual("True", result); + } + + [Test] + public async Task PrototypeChainOfElementIsBuiltCompletely() + { + var result = await "(function () { var p = Object.getPrototypeOf(document.createElement('div')), t = []; while (p) { t.push(p[Symbol.toStringTag]); p = Object.getPrototypeOf(p); } return t.join(); })()".EvalScriptAsync(); + Assert.AreEqual("HTMLDivElement,HTMLElement,Element,Node,EventTarget,", result); + } + + [Test] + public async Task ConstructorPropertyOfPrototypeRefersBackToTheConstructor() + { + var result = await "HTMLDivElement.prototype.constructor === HTMLDivElement".EvalScriptAsync(); + Assert.AreEqual("True", result); + } + + [Test] + public async Task NumericIndexerOfHtmlCollectionYieldsTheElement() + { + var result = await "document.getElementsByTagName('script')[0].nodeName".EvalScriptAsync(); + Assert.AreEqual("SCRIPT", result); + } + + [Test] + public async Task NumericIndexerOfHtmlCollectionOutOfRangeIsUndefined() + { + var result = await "typeof document.getElementsByTagName('script')[5]".EvalScriptAsync(); + Assert.AreEqual("undefined", result); + } + + // Two closed forms of IHtmlCollection in one document - each resolves its own + // indexer, and the explicit IReadOnlyList re-implementation behind them is the + // one accessor that cannot be invoked as declared. + [Test] + public async Task NumericIndexerWorksForHtmlCollectionsOfDifferentItemTypes() + { + var result = await "(function () { var d = new DOMParser().parseFromString(``, 'text/html'); return d.getElementsByTagName('img')[0].id + ',' + d.images[0].id; })()".EvalScriptAsync(); + Assert.AreEqual("x,x", result); + } + + // col and colgroup are separate classes sharing the HTMLTableColElement prototype. + [Test] + public async Task NumericIndexerWorksForElementsSharingAPrototype() + { + var result = await "(function () { var d = new DOMParser().parseFromString(`
`, 'text/html'); var g = d.getElementsByTagName('colgroup')[0], c = d.getElementsByTagName('col')[0]; return g.classList[1] + ',' + c.classList[1]; })()".EvalScriptAsync(); + Assert.AreEqual("b,d", result); + } + + [Test] + public async Task NumericIndexerOfNodeListYieldsTheNode() + { + var result = await "new DOMParser().parseFromString(`
`, 'text/html').body.childNodes[0].nodeName".EvalScriptAsync(); + Assert.AreEqual("DIV", result); + } + + [Test] + public async Task NumericIndexerOfTokenListYieldsTheToken() + { + var result = await "new DOMParser().parseFromString(`
`, 'text/html').body.firstChild.classList[1]".EvalScriptAsync(); + Assert.AreEqual("b", result); + } + + [Test] + public async Task ConsoleIsTheSameObjectOnEveryAccess() + { + var result = await "window.console === window.console".EvalScriptAsync(); + Assert.AreEqual("True", result); + } + + [Test] + public async Task ConsoleKeepsPropertiesAssignedToIt() + { + var result = await "(function () { window.console.marker = 'kept'; return window.console.marker; })()".EvalScriptAsync(); + Assert.AreEqual("kept", result); + } + + [Test] + public async Task InheritedMemberIsNotAnOwnPropertyOfTheNode() + { + var result = await "document.createElement('div').hasOwnProperty('firstChild')".EvalScriptAsync(); + Assert.AreEqual("False", result); + } + + [Test] + public async Task InheritedMemberIsStillVisibleOnTheNode() + { + var result = await "('firstChild' in document.documentElement) + ',' + (typeof document.documentElement.appendChild)".EvalScriptAsync(); + Assert.AreEqual("true,function", result); + } + + [Test] + public async Task InheritedAccessorStillReadsAndWrites() + { + var result = await "(function () { var d = document.createElement('div'); d.id = 'jint'; return d.id; })()".EvalScriptAsync(); + Assert.AreEqual("jint", result); + } + + [Test] + public async Task AssignedPropertyIsReportedConsistently() + { + var result = await "(function () { var d = document.createElement('div'); d.custom = 1; return d.hasOwnProperty('custom') + ',' + Object.getOwnPropertyNames(d).join(); })()".EvalScriptAsync(); + Assert.AreEqual("true,custom", result); + } + + // Reading an index, testing it for existence and enumerating it are three different + // questions the engine asks, and the node answers each of them from a different + // method. They have to agree. + [Test] + public async Task IndexedEntryIsReportedAsAnOwnPropertyAndReads() + { + var result = await "(function () { var c = document.getElementsByTagName('script'); return c.hasOwnProperty(0) + ',' + (0 in c) + ',' + c[0].nodeName; })()".EvalScriptAsync(); + Assert.AreEqual("true,true,SCRIPT", result); + } + + [Test] + public async Task IndexBeyondTheEndIsNoOwnPropertyAndReadsUndefined() + { + var result = await "(function () { var c = document.getElementsByTagName('script'); return c.hasOwnProperty(5) + ',' + (5 in c) + ',' + (typeof c[5]); })()".EvalScriptAsync(); + Assert.AreEqual("false,false,undefined", result); + } + + // A member of an indexed collection must not be mistaken for an index. "length" is + // the collection's own property rather than an inherited one, which is what the + // array-like projection reports for it - a browser has it on the prototype instead. + [Test] + public async Task MemberOfAnIndexedCollectionIsNotMistakenForAnIndex() + { + var result = await "(function () { var c = document.getElementsByTagName('script'); return ('length' in c) + ',' + c.length + ',' + c.propertyIsEnumerable('length'); })()".EvalScriptAsync(); + Assert.AreEqual("true,1,false", result); + } + + // A DOM collection is array-like, not an array - which is exactly what a browser + // reports for one. + [Test] + public async Task CollectionIsNotAnArray() + { + var result = await "Array.isArray(document.getElementsByTagName('script'))".EvalScriptAsync(); + Assert.AreEqual("False", result); + } + + [Test] + public async Task CollectionKeepsItsDomIdentity() + { + var result = await "(function () { var c = document.getElementsByTagName('script'); return Object.prototype.toString.call(c) + ',' + (c instanceof HTMLCollection); })()".EvalScriptAsync(); + Assert.AreEqual("[object HTMLCollection],true", result); + } + + [Test] + public async Task CollectionCanBeIterated() + { + var result = await "(function () { var n = 0; for (var s of document.getElementsByTagName('script')) { n += s.nodeName.length; } return n; })()".EvalScriptAsync(); + Assert.AreEqual("6", result); + } + + [Test] + public async Task CollectionCanBeSpread() + { + var result = await "[...document.getElementsByTagName('script')].length".EvalScriptAsync(); + Assert.AreEqual("1", result); + } + + [Test] + public async Task ArrayGenericsRunOverACollection() + { + var result = await "Array.prototype.map.call(document.getElementsByTagName('script'), function (e) { return e.nodeName; }).join()".EvalScriptAsync(); + Assert.AreEqual("SCRIPT", result); + } + + [Test] + public async Task IndicesOfACollectionAreEnumerated() + { + var result = await "JSON.stringify(Object.keys(document.getElementsByTagName('script')))".EvalScriptAsync(); + Assert.AreEqual("[\"0\"]", result); + } + + // The platform-object shape: the projection owns its indices, so script cannot delete + // one or define over it. + [Test] + public async Task IndexOfACollectionCannotBeDeleted() + { + var result = await "(function () { var c = document.getElementsByTagName('script'); return delete c[0]; })()".EvalScriptAsync(); + Assert.AreEqual("False", result); + } + + [Test] + public async Task ExpandoOnACollectionIsStillPossible() + { + var result = await "(function () { var c = document.getElementsByTagName('script'); c.marker = 'kept'; return c.marker + ',' + c.hasOwnProperty('marker'); })()".EvalScriptAsync(); + Assert.AreEqual("kept,true", result); + } + + // Existence is answered from the collection's length alone, without producing the + // element - so it has to keep agreeing with what reading it would say. + [Test] + public async Task ExistenceOfAnIndexAgreesWithReadingIt() + { + var result = await "(function () { var c = document.getElementsByTagName('script'); var r = []; for (var i = 0; i < 3; i++) { r.push((i in c) + ':' + (c[i] !== undefined)); } return r.join(); })()".EvalScriptAsync(); + Assert.AreEqual("true:true,false:false,false:false", result); + } + + [Test] + public async Task NumericIndexerOfNamedNodeMapStillReadsBothWays() + { + var result = await "(function () { var d = document.createElement('div'); d.setAttribute('title', 't'); var a = d.attributes; return a.length + ',' + a[0].name + ',' + a.title.value; })()".EvalScriptAsync(); + Assert.AreEqual("1,title,t", result); + } + + // An element whose id happens to be numeric must not surface as an index of the + // collection. The array-like projection owns every array-index key - an index past the + // end is authoritatively absent - so the named entry answers only non-index names, + // which is also how WebIDL resolves the collision. Every answer has to say the same + // thing, the descriptor included. + [Test] + public async Task NamedEntryWithAnIndexShapedNameIsNotAnIndex() + { + var result = await "(function () { var f = document.createElement('form'); f.id = '5'; document.documentElement.appendChild(f); var c = document.forms; return (Object.getOwnPropertyDescriptor(c, '5') === undefined) + ',' + ('5' in c) + ',' + (c['5'] === undefined) + ',' + c.hasOwnProperty('5') + ',' + (c[0] === f); })()".EvalScriptAsync(); + Assert.AreEqual("true,false,true,false,true", result); + } + + // The guard above must not overreach: a named entry whose name is not an array index + // keeps resolving, descriptor and all. + [Test] + public async Task NamedEntryWithAnOrdinaryNameStillResolves() + { + var result = await "(function () { var f = document.createElement('form'); f.id = 'login'; document.documentElement.appendChild(f); var c = document.forms; return (c.login === f) + ',' + (Object.getOwnPropertyDescriptor(c, 'login') !== undefined); })()".EvalScriptAsync(); + Assert.AreEqual("true,true", result); + } + + // A symbol cannot be an index, and it must not be turned into one either - the + // well-known symbols are probed on every kind of object by library code. + [Test] + public async Task SymbolKeyOnAnIndexedCollectionIsNotTreatedAsAnIndex() + { + var result = await "(function () { var c = document.getElementsByTagName('script'); return c.hasOwnProperty(Symbol.toStringTag) + ',' + (typeof c[Symbol.toStringTag]); })()".EvalScriptAsync(); + Assert.AreEqual("false,string", result); + } + + // The node's own property set lives in the DOM, so nothing in the engine changes + // when an entry appears there. A name that was absent has to start resolving on the + // node from the very next read, rather than staying on whatever the prototype said. + [Test] + public async Task NamedEntryStartsResolvingOnTheNodeAsSoonAsItExists() + { + var result = await "(function () { var d = document.createElement('div'), a = d.attributes, before = typeof a.title; d.setAttribute('title', 't'); return before + ',' + a.title.value + ',' + a.hasOwnProperty('title'); })()".EvalScriptAsync(); + Assert.AreEqual("undefined,t,true", result); + } + + [Test] + public async Task AccessorDefinedOnANodeByScriptIsInvokedOnRead() + { + var result = await "(function () { var d = document.createElement('div'); Object.defineProperty(d, 'marker', { get: function () { return 'from getter'; } }); return d.marker + ',' + d.hasOwnProperty('marker'); })()".EvalScriptAsync(); + Assert.AreEqual("from getter,true", result); + } + + [Test] + public async Task NonEnumerablePropertyOfANodeIsSeenButNotEnumerated() + { + var result = await "(function () { var d = document.createElement('div'); Object.defineProperty(d, 'hidden2', { value: 1 }); return d.hasOwnProperty('hidden2') + ',' + d.propertyIsEnumerable('hidden2') + ',' + Object.keys(d).length; })()".EvalScriptAsync(); + Assert.AreEqual("true,false,0", result); + } + + [Test] + public async Task PropertyAssignedToANodeIsCopiedAndSerialized() + { + var result = await "(function () { var d = document.createElement('div'); d.custom = 'v'; return JSON.stringify(d) + ',' + JSON.stringify(Object.assign({}, d)); })()".EvalScriptAsync(); + Assert.AreEqual("{\"custom\":\"v\"},{\"custom\":\"v\"}", result); + } + } +} diff --git a/src/AngleSharp.Js.Tests/EcmaTests.cs b/src/AngleSharp.Js.Tests/EcmaTests.cs new file mode 100644 index 0000000..8656056 --- /dev/null +++ b/src/AngleSharp.Js.Tests/EcmaTests.cs @@ -0,0 +1,151 @@ +namespace AngleSharp.Js.Tests +{ + using AngleSharp.Io; + using AngleSharp.Js.Tests.Mocks; + using NUnit.Framework; + using System; + using System.Collections.Generic; + 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); + } + + [Test] + public async Task ModuleScriptShouldRun() + { + var config = + Configuration.Default + .WithJs() + .With(new MockHttpClientRequester(new Dictionary() + { + { "/example-module.js", "import { $ } from '/jquery_4_0_0_esm.js'; $('#test').remove();" }, + { "/jquery_4_0_0_esm.js", Constants.Jquery4_0_0_ESM } + })) + .WithDefaultLoader(new LoaderOptions() { IsResourceLoadingEnabled = true }); + var context = BrowsingContext.New(config); + var html = "
Test
"; + var document = await context.OpenAsync(r => r.Content(html)); + Assert.IsNull(document.GetElementById("test")); + } + + [Test] + public async Task InlineModuleScriptShouldRun() + { + var config = + Configuration.Default + .WithJs() + .With(new MockHttpClientRequester(new Dictionary() + { + { "/jquery_4_0_0_esm.js", Constants.Jquery4_0_0_ESM } + })) + .WithDefaultLoader(new LoaderOptions() { IsResourceLoadingEnabled = true }); + var context = BrowsingContext.New(config); + var html = "
Test
"; + var document = await context.OpenAsync(r => r.Content(html)); + Assert.IsNull(document.GetElementById("test")); + } + + [Test] + public async Task ModuleScriptWithImportMapShouldRun() + { + var config = + Configuration.Default + .WithJs() + .With(new MockHttpClientRequester(new Dictionary() + { + { "/jquery_4_0_0_esm.js", Constants.Jquery4_0_0_ESM } + })) + .WithDefaultLoader(new LoaderOptions() { IsResourceLoadingEnabled = true }); + + var context = BrowsingContext.New(config); + var html = "
Test
"; + var document = await context.OpenAsync(r => r.Content(html)); + Assert.IsNull(document.GetElementById("test")); + } + + [Test] + public async Task ModuleScriptWithScopedImportMapShouldRunCorrectScript() + { + var config = + Configuration.Default + .WithJs() + .With(new MockHttpClientRequester(new Dictionary() + { + { "/example-module-1.js", "export function test() { document.getElementById('test1').remove(); }" }, + { "/example-module-2.js", "export function test() { document.getElementById('test2').remove(); }" }, + { "/test.js", "import { test } from 'example-module'; test();" }, + { "/test/test.js", "import { test } from 'example-module'; test();" } + })) + .WithDefaultLoader(new LoaderOptions() { IsResourceLoadingEnabled = true }); + + var context = BrowsingContext.New(config); + + var html1 = "
Test
Test
"; + var document1 = await context.OpenAsync(r => r.Content(html1)); + Assert.IsNull(document1.GetElementById("test1")); + Assert.IsNotNull(document1.GetElementById("test2")); + + var html2 = "
Test
Test
"; + var document2 = await context.OpenAsync(r => r.Content(html2)); + Assert.IsNull(document2.GetElementById("test2")); + Assert.IsNotNull(document2.GetElementById("test1")); + } + + [Test] + public async Task ModuleScriptWithQuoteInImportMapShouldRun() + { + var config = + Configuration.Default + .WithJs() + .With(new MockHttpClientRequester(new Dictionary() + { + { "/example-module.js", "export function test() { document.getElementById('test').remove(); }" } + })) + .WithDefaultLoader(new LoaderOptions() { IsResourceLoadingEnabled = true }); + + var context = BrowsingContext.New(config); + var html = "
Test
"; + var document = await context.OpenAsync(r => r.Content(html)); + Assert.IsNull(document.GetElementById("test")); + } + + [Test] + public async Task ImportMapContentIsNotEvaluatedAsScript() + { + var config = Configuration.Default.WithJs(); + var context = BrowsingContext.New(config); + var html = "
Test
"; + var document = await context.OpenAsync(r => r.Content(html)); + Assert.IsNotNull(document.GetElementById("test")); + } + + [Test] + public async Task ModuleScriptWithAbsoluteUrlImportMapShouldRun() + { + var config = + Configuration.Default + .WithJs() + .With(new MockHttpClientRequester(new Dictionary() + { + { "/jquery_4_0_0_esm.js", Constants.Jquery4_0_0_ESM } + })) + .WithDefaultLoader(new LoaderOptions() { IsResourceLoadingEnabled = true }); + + var context = BrowsingContext.New(config); + var html = "
Test
"; + var document = await context.OpenAsync(r => r.Content(html)); + Assert.IsNull(document.GetElementById("test")); + } + } +} diff --git a/src/AngleSharp.Js.Tests/FireEventTests.cs b/src/AngleSharp.Js.Tests/FireEventTests.cs index e468a1f..16d2567 100644 --- a/src/AngleSharp.Js.Tests/FireEventTests.cs +++ b/src/AngleSharp.Js.Tests/FireEventTests.cs @@ -3,7 +3,11 @@ namespace AngleSharp.Js.Tests using AngleSharp.Dom; using AngleSharp.Dom.Events; using AngleSharp.Scripting; + using Jint; using NUnit.Framework; + + using System; + using System.Linq; using System.Threading.Tasks; [TestFixture] @@ -57,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()); @@ -152,6 +156,76 @@ public async Task AddAndInvokeClickHandlerWithStringFunctionWontWork() Assert.IsFalse(clicked); } + [Test] + public async Task ClickHandlerIsKeptPerElement() + { + var service = new JsScriptingService(); + var cfg = Configuration.Default.With(service).WithEventLoop(); + var html = @" + + +
+
+ +"; + var document = await BrowsingContext.New(cfg).OpenAsync(m => m.Content(html)); + var engine = service.GetOrCreateJint(document); + + Assert.IsTrue(engine.GetValue("aIsF").AsBoolean()); + Assert.IsTrue(engine.GetValue("bIsG").AsBoolean()); + Assert.IsFalse(engine.GetValue("shared").AsBoolean()); + + var log = engine.GetValue("log").AsArray(); + Assert.AreEqual(2.0, log.Get("length").AsNumber()); + Assert.AreEqual("f", log.Get("0").AsString()); + Assert.AreEqual("g", log.Get("1").AsString()); + } + + [Test] + public async Task ClearingClickHandlerOfOneElementKeepsTheOther() + { + var service = new JsScriptingService(); + var cfg = Configuration.Default.With(service).WithEventLoop(); + var html = @" + + +
+
+ +"; + var document = await BrowsingContext.New(cfg).OpenAsync(m => m.Content(html)); + var engine = service.GetOrCreateJint(document); + + Assert.IsTrue(engine.GetValue("cleared").AsBoolean()); + + var log = engine.GetValue("log").AsArray(); + Assert.AreEqual(1.0, log.Get("length").AsNumber()); + Assert.AreEqual("g", log.Get("0").AsString()); + } + [Test] public async Task BodyOnloadWorksWhenSetAsAttributeInitially() { @@ -210,10 +284,8 @@ public async Task SetTimeoutWithNormalFunction() } [Test] - public async Task DomContentLoadedEventIsFired_Issue50() + public async Task DomContentLoadedEventIsFiredOnDocument_Issue50() { - //TODO Check this as well on the window level - currently works - //only against document (se AngleSharp#789) var cfg = Configuration.Default.WithJs().WithEventLoop(); var html = @" @@ -233,6 +305,28 @@ public async Task DomContentLoadedEventIsFired_Issue50() Assert.AreEqual("Success!", div?.TextContent); } + [Test] + public async Task DomContentLoadedEventIsFiredOnWindow_Issue50() + { + var cfg = Configuration.Default.WithJs().WithEventLoop(); + var html = @" + + + +"; + var document = await BrowsingContext.New(cfg).OpenAsync(m => m.Content(html)) + .WhenStable(); + + var div = document.QuerySelector("div"); + Assert.AreEqual("Success!", div?.TextContent); + } + [Test] public async Task DocumentLoadEventIsFired_Issue42() { @@ -256,6 +350,60 @@ public async Task DocumentLoadEventIsFired_Issue42() Assert.AreEqual("Success!", div?.TextContent); } + [Test] + public async Task DocumentReadyStateIsComplete_Issue86() + { + var cfg = Configuration.Default.WithJs().WithEventLoop(); + var html = @" + + + +"; + var context = BrowsingContext.New(cfg); + var document = await context.OpenAsync(m => m.Content(html)) + .WhenStable(); + + var divs = document.GetElementsByTagName("div"); + + // expected value will vary depending on AngleSharp package version + // 1.0.2 and greater, expected value will be { "interactive", "complete" + // prior to 1.0.2, expected value will be { "1", "2" } + var expected = new[] { DocumentReadyState.Interactive, DocumentReadyState.Complete } + .Select(e => e.GetOfficialName() ?? Convert.ToInt32(e).ToString()); + CollectionAssert.AreEqual(expected, divs.Select(d => d.TextContent)); + } + + [Test] + public async Task SetTimeoutWithSeveralDifferentFunctions() + { + var service = new JsScriptingService(); + var cfg = Configuration.Default.With(service).WithEventLoop(); + var html = @" + + + +"; + var document = await BrowsingContext.New(cfg).OpenAsync(m => m.Content(html)) + .WhenStable(); + var log = service.GetOrCreateJint(document).GetValue("log").AsArray(); + + Assert.AreEqual(3.0, log.Get("length").AsNumber()); + Assert.AreEqual("a", log.Get("0").AsString()); + Assert.AreEqual("b", log.Get("1").AsString()); + Assert.AreEqual("c", log.Get("2").AsString()); + } + [Test] public async Task SetTimeoutWithStringAsFunction() { diff --git a/src/AngleSharp.Js.Tests/Fixtures/Html5Test/README.md b/src/AngleSharp.Js.Tests/Fixtures/Html5Test/README.md new file mode 100644 index 0000000..9f55fb5 --- /dev/null +++ b/src/AngleSharp.Js.Tests/Fixtures/Html5Test/README.md @@ -0,0 +1,20 @@ +# HTML5test fixture + +This fixture was retrieved from `https://html5test.com/` on 2026-07-27: + +- `https://html5test.com/` +- `https://html5test.com/scripts/base.js` +- `https://html5test.com/scripts/8/engine.js` +- `https://html5test.com/scripts/8/data.js` +- `https://html5test.com/assets/detect.html` +- `https://html5test.com/assets/csp.html` + +HTML5test is Copyright (c) 2010-2016 Niels Leenheer and is distributed under +the MIT license, reproduced in `index.html`. + +The Cloudflare email-decoder script was removed from `index.html`. The remote +WhichBrowser detector was replaced by `whichbrowser-stub.js`, which reports a +clean browser and keeps the fixture deterministic. A wrapper around the +destructuring feature probe converts Jint's unsupported `eval` path into the +feature-test's expected `SyntaxError` (https://github.com/sebastienros/jint/issues/2825). +No test engine code was modified. diff --git a/src/AngleSharp.Js.Tests/Fixtures/Html5Test/assets/csp.html b/src/AngleSharp.Js.Tests/Fixtures/Html5Test/assets/csp.html new file mode 100644 index 0000000..423e959 --- /dev/null +++ b/src/AngleSharp.Js.Tests/Fixtures/Html5Test/assets/csp.html @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/src/AngleSharp.Js.Tests/Fixtures/Html5Test/assets/detect.html b/src/AngleSharp.Js.Tests/Fixtures/Html5Test/assets/detect.html new file mode 100644 index 0000000..ed6ea21 --- /dev/null +++ b/src/AngleSharp.Js.Tests/Fixtures/Html5Test/assets/detect.html @@ -0,0 +1 @@ +&&< diff --git a/src/AngleSharp.Js.Tests/Fixtures/Html5Test/index.html b/src/AngleSharp.Js.Tests/Fixtures/Html5Test/index.html new file mode 100644 index 0000000..d6b6072 --- /dev/null +++ b/src/AngleSharp.Js.Tests/Fixtures/Html5Test/index.html @@ -0,0 +1,357 @@ + + + + HTML5test - How well does your browser support HTML5? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

HTML5test how well does your browser support HTML5?

+ + +
+ +
+ + +
+
+

HTML5test is dead

+ +
+

+ HTML5test is dead. It's been dead for a while. In fact it hasn't been updated since 2016. +

+

+ And that is fine. This website has served it's purpose and helped popularise HTML5 with a + general audience and developers. It pushed companies to invest in their browsers and it kept them honest. + And from talking to people working for those companies over the years it worked. It helped + convince people higher up to invest more resources, because nobody wants their browser to look + bad. +

+

+ The goal of this website was always to push browsers to adopt HTML5. + To make HTML5 available for users and developers in all browsers. + And if just one feature is now available to developers in all browsers thanks to HTML5test, + this website has served it's purpose. And I know for sure that it has served it's purpose. + HTML5 is now generally supported and there aren't any truly bad browsers anymore. +

+

+ I'll try to keep this page online as a snapshot of the original test, and there is an unofficial + updated version available at html5test.co. +

+

+ It was fun to work on this project while it lasted. I have some awesome memories of talking to + the people at the W3C, Apple, Mozilla, Google and Microsoft. Thanks for all the support over the years! +

+

+ Niels Leenheer +

+
+
+
+ +
+ +
+ + +
+
+
+ + + + diff --git a/src/AngleSharp.Js.Tests/Fixtures/Html5Test/scripts/8/data.js b/src/AngleSharp.Js.Tests/Fixtures/Html5Test/scripts/8/data.js new file mode 100644 index 0000000..d8e2b02 --- /dev/null +++ b/src/AngleSharp.Js.Tests/Fixtures/Html5Test/scripts/8/data.js @@ -0,0 +1,2654 @@ + + +var tests = [ + + { + id: 'semantics', + name: 'Semantics', + column: 'left', + items: [ + { + id: 'parsing', + name: 'Parsing rules', + status: 'stable', + items: [ + { + id: 'doctype', + name: '<!DOCTYPE html> triggers standards mode', + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/syntax.html#the-doctype' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/syntax.html#the-doctype' ] + ] + }, { + id: 'tokenizer', + name: 'HTML5 tokenizer', + value: 3, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/syntax.html#parsing' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/syntax.html#parsing' ], + [ 'mdn', '/Web/Guide/HTML/HTML5/HTML5_Parser' ] + ] + }, { + id: 'tree', + name: 'HTML5 tree building', + value: 2, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/syntax.html#parsing' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/syntax.html#parsing' ], + [ 'mdn', '/Web/Guide/HTML/HTML5/HTML5_Parser' ] + ] + }, + + 'HTML5 defines rules for embedding SVG and MathML inside a regular HTML document. The following tests only check if the browser is following the HTML5 parsing rules for inline SVG and MathML, not if the browser can actually understand and render it.', + + { + id: 'svg', + name: 'Parsing inline SVG', + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/embedded-content-0.html#svg' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/embedded-content.html#svg-0' ], + [ 'mdn', '/Web/SVG' ] + ] + + }, { + id: 'mathml', + name: 'Parsing inline MathML', + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/embedded-content-0.html#mathml' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/embedded-content.html#mathml' ], + [ 'mdn', '/Web/MathML' ] + ] + } + ] + }, { + id: 'elements', + name: 'Elements', + status: 'stable', + items: [ + { + id: 'dataset', + name: 'Embedding custom non-visible data', + value: 2, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes' ], + [ 'mdn', '/Web/API/HTMLElement/dataset' ] + ] + }, + + 'New or modified elements', + + { + id: 'section', + name: 'Section elements', + urls: [ + [ 'mdn', '/Web/Guide/HTML/Sections_and_Outlines_of_an_HTML5_document' ] + ], + items: [ + { + id: 'section', + name: 'section element', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/sections.html#the-section-element' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/semantics.html#the-section-element' ] + ] + }, { + id: 'nav', + name: 'nav element', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/sections.html#the-nav-element' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/semantics.html#the-nav-element' ] + ] + }, { + id: 'article', + name: 'article element', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/sections.html#the-article-element' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/semantics.html#the-article-element' ] + ] + }, { + id: 'aside', + name: 'aside element', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/sections.html#the-aside-element' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/semantics.html#the-aside-element' ] + ] + }, { + id: 'header', + name: 'header element', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/sections.html#the-header-element' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/semantics.html#the-header-element' ] + ] + }, { + id: 'footer', + name: 'footer element', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/sections.html#the-footer-element' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/semantics.html#the-footer-element' ] + ] + } + ] + + }, { + id: 'grouping', + name: 'Grouping content elements', + urls: [ + [ 'mdn', '/Web/Guide/HTML/Sections_and_Outlines_of_an_HTML5_document' ] + ], + items: [ + { + id: 'main', + name: 'main element', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/html/wg/drafts/html/master/single-page.html#the-main-element' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/semantics.html#the-main-element' ] + ] + }, { + id: 'figure', + name: 'figure element', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/grouping-content.html#the-figure-element' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/semantics.html#the-figure-element' ] + ] + }, { + id: 'figcaption', + name: 'figcaption element', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/grouping-content.html#the-figcaption-element' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/semantics.html#the-figcaption-element' ] + ] + }, { + id: 'ol', + name: 'reversed attribute on the ol element', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/grouping-content.html#the-ol-element' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/semantics.html#the-ol-element' ] + ] + } + ] + }, { + id: 'semantic', + name: 'Text-level semantic elements', + items: [ + { + id: 'download', + name: 'download attribute on the a element', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/text-level-semantics.html#the-a-element' ], + [ 'whatwg', 'http://developers.whatwg.org/links.html#attr-hyperlink-download' ] + ] + }, { + id: 'ping', + name: 'ping attribute on the a element', + status: 'proposal', + value: 1, + urls: [ + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/semantics.html#ping' ] + ] + }, { + id: 'mark', + name: 'mark element', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/text-level-semantics.html#the-mark-element' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/semantics.html#the-mark-element' ] + ] + }, { + id: 'ruby', + name: 'ruby, rt and rp elements', + value: 3, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/text-level-semantics.html#the-ruby-element' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/semantics.html#the-ruby-element' ] + ] + }, { + id: 'time', + name: 'time element', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/text-level-semantics.html#the-time-element' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/semantics.html#the-time-element' ] + ] + }, { + id: 'data', + name: 'data element', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/text-level-semantics.html#the-data-element' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/semantics.html#the-data-element' ] + ] + }, { + id: 'wbr', + name: 'wbr element', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/text-level-semantics.html#the-wbr-element' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/semantics.html#the-wbr-element' ] + ] + } + ] + }, { + id: 'interactive', + name: 'Interactive elements', + items: [ + { + id: 'details', + name: 'details element', + value: 1, + urls: [ + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/forms.html#the-details-element' ] + ] + }, { + id: 'summary', + name: 'summary element', + value: 1, + urls: [ + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/forms.html#the-summary-element' ] + ] + }, { + id: 'menutoolbar', + name: 'menu element of type toolbar', + status: 'proposal', + value: { maximum: 1, award: { OLD: 0 } }, + urls: [ + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/forms.html#the-menu-element' ] + ] + }, { + id: 'menucontext', + name: 'menu element of type context', + status: 'proposal', + value: { maximum: 2, award: { OLD: 1 } }, + urls: [ + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/forms.html#the-menu-element' ] + ] + }, { + id: 'dialog', + name: 'dialog element', + status: 'proposal', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/html/wg/drafts/html/master/single-page.html#the-dialog-element' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/forms.html#the-dialog-element' ] + ] + } + ] + }, + + 'Global attributes or methods', + + { + id: 'hidden', + name: 'hidden attribute', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/editing.html#the-hidden-attribute' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/interaction.html#the-hidden-attribute' ] + ] + }, { + id: 'dynamic', + name: 'Dynamic markup insertion', + items: [ + { + id: 'outerHTML', + name: 'outerHTML property', + value: 1, + urls: [ + [ 'w3c', 'https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#widl-Element-outerHTML' ] + ] + }, { + id: 'insertAdjacentHTML', + name: 'insertAdjacentHTML function', + value: 1, + urls: [ + [ 'w3c', 'https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#widl-Element-insertAdjacentHTML-void-DOMString-position-DOMString-text' ] + ] + } + ] + } + ] + }, { + id: 'form', + name: 'Forms', + status: 'stable', + items: [ + 'Field types', + + { + id: 'text', + name: 'input type=text', + items: [ + { + id: 'element', + name: 'Minimal element support' + }, { + id: 'selection', + name: 'Selection Direction', + value: 2 + } + ] + }, { + id: 'search', + name: 'input type=search', + items: [ + { + id: 'element', + name: 'Minimal element support', + value: 1, + url: 'http://www.w3.org/TR/html5/forms.html#text-(type=text)-state-and-search-state-(type=search)' + } + ] + }, { + id: 'tel', + name: 'input type=tel', + items: [ + { + id: 'element', + name: 'Minimal element support', + value: 1, + url: 'http://www.w3.org/TR/html5/forms.html#telephone-state-(type=tel)' + } + ] + }, { + id: 'url', + name: 'input type=url', + items: [ + { + id: 'element', + name: 'Minimal element support', + value: 1, + url: 'http://www.w3.org/TR/html5/forms.html#url-state-(type=url)' + }, { + id: 'validation', + name: 'Field validation', + url: 'http://www.w3.org/TR/html5/forms.html#the-constraint-validation-api' + } + ] + }, { + id: 'email', + name: 'input type=email', + items: [ + { + id: 'element', + name: 'Minimal element support', + value: 1, + url: 'http://www.w3.org/TR/html5/forms.html#e-mail-state-(type=email)' + }, { + id: 'validation', + name: 'Field validation', + url: 'http://www.w3.org/TR/html5/forms.html#the-constraint-validation-api' + } + ] + }, { + id: 'date', + name: 'input type=date', + items: [ + { + id: 'element', + name: 'Minimal element support', + value: 2, + url: 'http://www.w3.org/TR/html5/forms.html#date-state-(type=date)' + }, { + id: 'ui', + value: 2, + name: 'Custom user-interface' + }, { + id: 'sanitization', + name: 'Value sanitization', + url: 'http://www.w3.org/TR/html5/forms.html#value-sanitization-algorithm' + }, { + id: 'min', + name: 'min attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-min' + }, { + id: 'max', + name: 'max attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-max' + }, { + id: 'step', + name: 'step attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-step' + }, { + id: 'stepDown', + name: 'stepDown() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-stepdown' + }, { + id: 'stepUp', + name: 'stepUp() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-stepup' + }, { + id: 'valueAsDate', + name: 'valueAsDate() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-valueasdate' + }, { + id: 'valueAsNumber', + name: 'valueAsNumber() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-valueasnumber' + } + ] + }, { + id: 'month', + name: 'input type=month', + items: [ + { + id: 'element', + name: 'Minimal element support', + value: 2, + url: 'http://www.w3.org/TR/html5/forms.html#month-state-(type=month)' + }, { + id: 'ui', + name: 'Custom user-interface', + value: 2 + }, { + id: 'sanitization', + name: 'Value sanitization', + url: 'http://www.w3.org/TR/html5/forms.html#value-sanitization-algorithm' + }, { + id: 'min', + name: 'min attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-min' + }, { + id: 'max', + name: 'max attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-max' + }, { + id: 'step', + name: 'step attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-step' + }, { + id: 'stepDown', + name: 'stepDown() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-stepdown' + }, { + id: 'stepUp', + name: 'stepUp() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-stepup' + }, { + id: 'valueAsDate', + name: 'valueAsDate() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-valueasdate' + }, { + id: 'valueAsNumber', + name: 'valueAsNumber() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-valueasnumber' + } + ] + }, { + id: 'week', + name: 'input type=week', + items: [ + { + id: 'element', + name: 'Minimal element support', + value: 2, + url: 'http://www.w3.org/TR/html5/forms.html#week-state-(type=week)' + }, { + id: 'ui', + name: 'Custom user-interface', + value: 2 + }, { + id: 'sanitization', + name: 'Value sanitization', + url: 'http://www.w3.org/TR/html5/forms.html#value-sanitization-algorithm' + }, { + id: 'min', + name: 'min attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-min' + }, { + id: 'max', + name: 'max attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-max' + }, { + id: 'step', + name: 'step attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-step' + }, { + id: 'stepDown', + name: 'stepDown() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-stepdown' + }, { + id: 'stepUp', + name: 'stepUp() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-stepup' + }, { + id: 'valueAsDate', + name: 'valueAsDate() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-valueasdate' + }, { + id: 'valueAsNumber', + name: 'valueAsNumber() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-valueasnumber' + } + ] + }, { + id: 'time', + name: 'input type=time', + items: [ + { + id: 'element', + name: 'Minimal element support', + value: 2, + url: 'http://www.w3.org/TR/html5/forms.html#time-state-(type=time)' + }, { + id: 'ui', + name: 'Custom user-interface', + value: 2 + }, { + id: 'sanitization', + name: 'Value sanitization', + url: 'http://www.w3.org/TR/html5/forms.html#value-sanitization-algorithm' + }, { + id: 'min', + name: 'min attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-min' + }, { + id: 'max', + name: 'max attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-max' + }, { + id: 'step', + name: 'step attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-step' + }, { + id: 'stepDown', + name: 'stepDown() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-stepdown' + }, { + id: 'stepUp', + name: 'stepUp() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-stepup' + }, { + id: 'valueAsDate', + name: 'valueAsDate() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-valueasdate' + }, { + id: 'valueAsNumber', + name: 'valueAsNumber() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-valueasnumber' + } + ] + }, { + id: 'datetime-local', + name: 'input type=datetime-local', + items: [ + { + id: 'element', + name: 'Minimal element support', + value: 2, + url: 'http://www.w3.org/TR/html5/forms.html#local-date-and-time-state-(type=datetime-local)' + }, { + id: 'ui', + name: 'Custom user-interface', + value: 2 + }, { + id: 'sanitization', + name: 'Value sanitization', + url: 'http://www.w3.org/TR/html5/forms.html#value-sanitization-algorithm' + }, { + id: 'min', + name: 'min attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-min' + }, { + id: 'max', + name: 'max attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-max' + }, { + id: 'step', + name: 'step attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-step' + }, { + id: 'stepDown', + name: 'stepDown() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-stepdown' + }, { + id: 'stepUp', + name: 'stepUp() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-stepup' + }, { + id: 'valueAsNumber', + name: 'valueAsNumber() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-valueasnumber' + } + ] + }, { + id: 'number', + name: 'input type=number', + items: [ + { + id: 'element', + name: 'Minimal element support', + value: 1, + url: 'http://www.w3.org/TR/html5/forms.html#number-state-(type=number)' + }, { + id: 'ui', + name: 'Custom user-interface', + value: 2 + }, { + id: 'sanitization', + name: 'Value sanitization', + url: 'http://www.w3.org/TR/html5/forms.html#value-sanitization-algorithm' + }, { + id: 'validation', + name: 'Field validation', + url: 'http://www.w3.org/TR/html5/forms.html#the-constraint-validation-api' + }, { + id: 'min', + name: 'min attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-min' + }, { + id: 'max', + name: 'max attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-max' + }, { + id: 'step', + name: 'step attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-step' + }, { + id: 'stepDown', + name: 'stepDown() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-stepdown' + }, { + id: 'stepUp', + name: 'stepUp() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-stepup' + }, { + id: 'valueAsNumber', + name: 'valueAsNumber() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-valueasnumber' + } + ] + }, { + id: 'range', + name: 'input type=range', + items: [ + { + id: 'element', + name: 'Minimal element support', + value: 1, + url: 'http://www.w3.org/TR/html5/forms.html#range-state-(type=range)' + }, { + id: 'ui', + name: 'Custom user-interface', + value: 2 + }, { + id: 'sanitization', + name: 'Value sanitization', + url: 'http://www.w3.org/TR/html5/forms.html#value-sanitization-algorithm' + }, { + id: 'min', + name: 'min attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-min' + }, { + id: 'max', + name: 'max attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-max' + }, { + id: 'step', + name: 'step attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-step' + }, { + id: 'stepDown', + name: 'stepDown() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-stepdown' + }, { + id: 'stepUp', + name: 'stepUp() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-stepup' + }, { + id: 'valueAsNumber', + name: 'valueAsNumber() method', + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-valueasnumber' + } + ] + }, { + id: 'color', + name: 'input type=color', + items: [ + { + id: 'element', + name: 'Minimal element support', + value: 1, + url: 'http://www.w3.org/TR/html5/forms.html#color-state-(type=color)' + }, { + id: 'ui', + name: 'Custom user-interface', + value: 2 + }, { + id: 'sanitization', + name: 'Value sanitization', + url: 'http://www.w3.org/TR/html5/forms.html#value-sanitization-algorithm' + } + ] + }, { + id: 'checkbox', + name: 'input type=checkbox', + items: [ + { + id: 'element', + name: 'Minimal element support', + url: 'http://www.w3.org/TR/html5/forms.html#checkbox-state-(type=checkbox)' + }, { + id: 'indeterminate', + name: 'indeterminate property', + value: 1, + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-indeterminate' + } + ] + }, { + id: 'image', + name: 'input type=image', + items: [ + { + id: 'element', + name: 'Minimal element support', + url: 'http://www.w3.org/TR/html5/forms.html#image-button-state-(type=image)' + }, { + id: 'width', + name: 'width property', + value: 0, + url: 'http://www.w3.org/TR/html5/embedded-content-0.html#attr-dim-width' + }, { + id: 'height', + name: 'height property', + value: 0, + url: 'http://www.w3.org/TR/html5/embedded-content-0.html#attr-dim-height' + } + ] + }, { + id: 'file', + name: 'input type=file', + items: [ + { + id: 'element', + name: 'Minimal element support', + url: 'http://www.w3.org/TR/html5/forms.html#file-upload-state-(type=file)' + }, { + id: 'files', + name: 'files property', + value: 1, + url: 'http://www.w3.org/TR/html5/forms.html#dom-input-files' + }, { + id: 'directory', + status: 'experimental', + name: 'Directory upload support', + value: 1, + url: 'https://wicg.github.io/directory-upload/proposal.html' + } + ] + }, { + id: 'textarea', + name: 'textarea', + items: [ + { + id: 'element', + name: 'Minimal element support', + url: 'http://www.w3.org/TR/html5/forms.html#the-textarea-element' + }, { + id: 'maxlength', + name: 'maxlength attribute', + value: 1, + url: 'http://www.w3.org/TR/html5/forms.html#attr-textarea-maxlength' + }, { + id: 'wrap', + name: 'wrap attribute', + value: 1, + url: 'http://www.w3.org/TR/html5/forms.html#attr-textarea-wrap' + } + ] + }, { + id: 'select', + name: 'select', + items: [ + { + id: 'element', + name: 'Minimal element support', + url: 'http://www.w3.org/TR/html5/forms.html#the-select-element' + }, { + id: 'required', + name: 'required attribute', + value: 1, + url: 'http://www.w3.org/TR/html5/forms.html#attr-select-required' + } + ] + }, { + id: 'fieldset', + name: 'fieldset', + items: [ + { + id: 'element', + name: 'Minimal element support', + url: 'http://www.w3.org/TR/html5/forms.html#the-fieldset-element' + }, { + id: 'elements', + name: 'elements attribute', + value: 1, + url: 'http://www.w3.org/TR/html5/forms.html#dom-fieldset-elements' + }, { + id: 'disabled', + name: 'disabled attribute', + value: 1, + url: 'http://www.w3.org/TR/html5/forms.html#dom-fieldset-disabled' + } + ] + }, { + id: 'datalist', + name: 'datalist', + items: [ + { + id: 'element', + name: 'Minimal element support', + value: 2, + url: 'http://www.w3.org/TR/html5/forms.html#the-datalist-element' + }, { + id: 'list', + name: 'list attribute for fields', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-list' + } + ] + }, { + id: 'output', + name: 'output', + items: [ + { + id: 'element', + name: 'Minimal element support', + value: 2, + url: 'http://www.w3.org/TR/html5/forms.html#the-output-element' + } + ] + }, { + id: 'progress', + name: 'progress', + items: [ + { + id: 'element', + name: 'Minimal element support', + value: 2, + url: 'http://www.w3.org/TR/html5/forms.html#the-progress-element' + } + ] + }, { + id: 'meter', + name: 'meter', + items: [ + { + id: 'element', + name: 'Minimal element support', + value: 2, + url: 'http://www.w3.org/TR/html5/forms.html#the-meter-element' + } + ] + }, + + 'Fields', + + { + id: 'validation', + name: 'Field validation', + items: [ + { + id: 'pattern', + name: 'pattern attribute', + value: 1, + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-pattern' + }, { + id: 'required', + name: 'required attribute', + value: 1, + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-required' + } + ] + }, { + id: 'association', + name: 'Association of controls and forms', + value: 2, + items: [ + { + id: 'control', + name: 'control property on labels', + url: 'http://www.w3.org/TR/html5/forms.html#dom-label-control' + }, { + id: 'form', + name: 'form property on fields', + url: 'http://www.w3.org/TR/html5/forms.html#attr-fae-form' + }, { + id: 'formAction', + name: 'formAction property on fields', + url: 'http://www.w3.org/TR/html5/forms.html#attr-fs-formaction' + }, { + id: 'formEnctype', + name: 'formEnctype property on fields', + url: 'http://www.w3.org/TR/html5/forms.html#attr-fs-formenctype' + }, { + id: 'formMethod', + name: 'formMethod property on fields', + url: 'http://www.w3.org/TR/html5/forms.html#attr-fs-formmethod' + }, { + id: 'formNoValidate', + name: 'formNoValidate property on fields', + url: 'http://www.w3.org/TR/html5/forms.html#attr-fs-formnovalidate' + }, { + id: 'formTarget', + name: 'formTarget property on fields', + url: 'http://www.w3.org/TR/html5/forms.html#attr-fs-formtarget' + }, { + id: 'labels', + name: 'labels property on fields', + url: 'http://www.w3.org/TR/html5/forms.html#dom-lfe-labels' + } + ] + }, { + id: 'other', + name: 'Other attributes', + value: 2, + items: [ + { + id: 'autofocus', + name: 'autofocus attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-fe-autofocus' + }, { + id: 'autocomplete', + name: 'autocomplete attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-fe-autocomplete' + }, { + id: 'placeholder', + name: 'placeholder attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-placeholder' + }, { + id: 'multiple', + name: 'multiple attribute', + url: 'http://www.w3.org/TR/html5/forms.html#attr-input-multiple' + }, { + id: 'dirname', + name: 'dirname attribute', + url: 'https://www.w3.org/TR/html5/forms.html#attr-fe-dirname' + } + ] + }, { + id: 'selectors', + name: 'CSS selectors', + value: 2, + items: [ + { + id: 'valid', + name: ':valid selector', + url: 'http://www.w3.org/TR/html5/links.html#selector-valid' + }, { + id: 'invalid', + name: ':invalid selector', + url: 'http://www.w3.org/TR/html5/links.html#selector-invalid' + }, { + id: 'optional', + name: ':optional selector', + url: 'http://www.w3.org/TR/html5/links.html#selector-optional' + }, { + id: 'required', + name: ':required selector', + url: 'http://www.w3.org/TR/html5/links.html#selector-required' + }, { + id: 'in-range', + name: ':in-range selector', + url: 'http://www.w3.org/TR/html5/links.html#selector-in-range' + }, { + id: 'out-of-range', + name: ':out-of-range selector', + url: 'http://www.w3.org/TR/html5/links.html#selector-out-of-range' + }, { + id: 'read-write', + name: ':read-write selector', + url: 'http://www.w3.org/TR/html5/links.html#selector-read-write' + }, { + id: 'read-only', + name: ':read-only selector', + url: 'http://www.w3.org/TR/html5/links.html#selector-read-only' + } + ] + }, { + id: 'events', + name: 'Events', + value: 2, + items: [ + { + id: 'oninput', + name: 'oninput event', + url: 'http://www.w3.org/TR/html5/forms.html#event-input-input' + }, { + id: 'onchange', + name: 'onchange event', + url: 'http://www.w3.org/TR/html5/forms.html#event-input-change' + }, { + id: 'oninvalid', + name: 'oninvalid event', + url: 'http://www.w3.org/TR/html5/webappapis.html#events' + } + ] + }, + + 'Forms', + + { + id: 'formvalidation', + name: 'Form validation', + items: [ + { + id: 'checkValidity', + name: 'checkValidity method', + value: 3, + url: 'http://www.w3.org/TR/html5/forms.html#dom-form-checkvalidity' + }, { + id: 'noValidate', + name: 'noValidate attribute', + value: 1, + url: 'http://www.w3.org/TR/html5/forms.html#dom-fs-novalidate' + } + ] + } + ] + }, { + id: 'components', + status: 'stable', + name: 'Web Components', + items: [ + { + id: 'custom', + name: 'Custom elements', + value: 4, + urls: [ + [ 'w3c', 'http://w3c.github.io/webcomponents/spec/custom/' ] + ] + }, { + id: 'shadowdom', + name: 'Shadow DOM', + status: 'experimental', + value: { maximum: 4, award: { OLD: 2 } }, + urls: [ + [ 'w3c', 'http://w3c.github.io/webcomponents/spec/shadow/' ] + ] + }, { + id: 'template', + name: 'HTML templates', + value: 2, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html-templates/' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/scripting.html#the-template-element' ], + [ 'wp', '/tutorials/webcomponents/htmlimports' ] + ] + }, { + id: 'imports', + name: 'HTML imports', + status: 'rejected', + urls: [ + [ 'w3c', 'http://w3c.github.io/webcomponents/spec/imports/' ] + ] + } + ] + } + ] + }, + + + { + id: 'deviceaccess', + name: 'Device Access', + column: 'left', + items: [ + { + id: 'location', + name: 'Location and Orientation', + status: 'stable', + items: [ + { + id: 'geolocation', + name: 'Geolocation', + value: 15, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/geolocation-API/' ], + [ 'wp', '/apis/geolocation' ], + [ 'mdn', '/Web/API/Geolocation/Using_geolocation' ] + ] + }, { + id: 'orientation', + name: 'Device Orientation', + value: 3, + urls: [ + [ 'w3c', 'http://dev.w3.org/geo/api/spec-source-orientation.html' ], + [ 'mdn', '/Web/API/DeviceOrientationEvent' ] + ] + }, { + id: 'motion', + name: 'Device Motion', + value: 2, + urls: [ + [ 'w3c', 'http://dev.w3.org/geo/api/spec-source-orientation.html' ], + [ 'mdn', '/Web/API/DeviceMotionEvent' ] + ] + } + ] + }, { + id: 'output', + name: 'Output', + status: 'proposal', + items: [ + { + id: 'requestFullScreen', + name: 'Full screen support', + value: { maximum: 5, award: { PREFIX: 3 } }, + urls: [ + [ 'w3c', 'http://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html#api' ], + [ 'wp', '/dom/Element/requestFullscreen' ], + [ 'mdn', '/Web/Guide/API/DOM/Using_full_screen_mode' ] + ] + }, { + id: 'notifications', + name: 'Web Notifications', + value: { maximum: 5, award: { PREFIX: 3 } }, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/notifications/' ], + [ 'whatwg', 'https://notifications.spec.whatwg.org' ] + ] + } + ] + }, { + id: 'input', + name: 'Input', + status: 'proposal', + items: [ + { + id: 'getGamepads', + name: 'Gamepad control', + value: { maximum: 2, award: { PREFIX: 1 } }, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/gamepad/' ], + [ 'wp', '/apis/gamepad' ] + ] + }, { + id: 'pointerevents', + name: 'Pointer Events', + value: { maximum: 5, award: { PREFIX: 3 } }, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/pointerevents/' ], + [ 'wp', '/concepts/Pointer_Events' ] + ] + }, { + id: 'pointerLock', + name: 'Pointer Lock support', + value: { maximum: 3, award: { PREFIX: 2 } }, + urls: [ + [ 'w3c', 'http://dvcs.w3.org/hg/pointerlock/raw-file/default/index.html' ], + [ 'wp', '/dom/Element/requestPointerLock' ], + [ 'mdn', '/Web/API/Pointer_Lock_API' ] + ] + } + ] + } + ] + }, + + { + id: 'multimedia', + name: 'Multimedia', + column: 'right', + items: [ + { + id: 'video', + name: 'Video', + status: 'stable', + items: [ + { + id: 'element', + name: 'video element', + value: 16, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/embedded-content-0.html#the-video-element' ], + [ 'wp', '/html/elements/video' ], + [ 'mdn', '/Web/Guide/HTML/Using_HTML5_audio_and_video' ] + ] + }, { + id: 'subtitle', + name: 'Subtitles', + value: 8, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/embedded-content-0.html#the-track-element' ], + [ 'wp', '/html/elements/track' ] + ] + }, { + id: 'audiotracks', + name: 'Audio track selection', + value: 2, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/embedded-content-0.html#dom-media-audiotracks' ] + ] + }, { + id: 'videotracks', + name: 'Video track selection', + value: 2, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/embedded-content-0.html#dom-media-videotracks' ] + ] + }, { + id: 'poster', + name: 'Poster images', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/embedded-content-0.html#attr-video-poster' ], + [ 'wp', '/dom/HTMLVideoElement/poster' ] + ] + }, { + id: 'canplaytype', + name: 'Codec detection', + value: 4, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/embedded-content-0.html#dom-navigator-canplaytype' ], + [ 'wp', '/dom/HTMLMediaElement/canPlayType' ] + ] + }, + + 'Video codecs', + + { + id: 'codecs.mp4.mpeg4', + name: 'MPEG-4 ASP support', + status: 'optional' + }, { + id: 'codecs.mp4.h264', + name: 'H.264 support', + status: 'optional', + urls: [ + [ 'other', 'http://ip.hhi.de/imagecom_G1/assets/pdfs/csvt_overview_0305.pdf' ] + ] + }, { + id: 'codecs.mp4.h265', + name: 'H.265 support', + status: 'optional' + }, { + id: 'codecs.ogg.theora', + name: 'Ogg Theora support', + status: 'optional', + urls: [ + [ 'xiph', 'http://theora.org/doc/Theora.pdf' ] + ] + }, { + id: 'codecs.webm.vp8', + name: 'WebM with VP8 support', + status: 'optional', + urls: [ + [ 'webm', 'http://www.webmproject.org/' ], + [ 'ietf', 'http://www.rfc-editor.org/rfc/rfc6386.txt' ] + ] + }, { + id: 'codecs.webm.vp9', + name: 'WebM with VP9 support', + status: 'optional', + urls: [ + [ 'webm', 'http://www.webmproject.org/' ], + [ 'ietf', 'http://tools.ietf.org/id/draft-grange-vp9-bitstream-00.txt' ] + ] + } + ] + }, { + id: 'audio', + name: 'Audio', + status: 'stable', + items: [ + { + id: 'element', + name: 'audio element', + value: 18, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/embedded-content-0.html#the-audio-element' ], + [ 'wp', '/html/elements/audio' ], + [ 'mdn', '/Web/Guide/HTML/Using_HTML5_audio_and_video' ] + ] + }, { + id: 'loop', + name: 'Loop audio', + value: 1, + url: 'http://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop' + }, { + id: 'preload', + name: 'Preload in the background', + value: 1, + url: 'http://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload' + }, + + + 'Advanced', + + { + id: 'webaudio', + name: 'Web Audio API', + value: { maximum: 5, award: { PREFIX: 3 } }, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/webaudio/' ], + [ 'wp', '/apis/webaudio' ] + ] + }, + + { + id: 'speechrecognition', + name: 'Speech Recognition', + status: 'experimental', + value: { maximum: 3, award: { PREFIX: 2 } }, + url: 'https://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html' + }, + + { + id: 'speechsynthesis', + name: 'Speech Synthesis', + status: 'experimental', + value: { maximum: 2, award: { PREFIX: 1 } }, + url: 'https://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html' + }, + + 'Audio codecs', + + { + id: 'codecs.pcm', + name: 'PCM audio support', + status: 'optional' + }, { + id: 'codecs.mp3', + name: 'MP3 support', + status: 'optional' + }, { + id: 'codecs.mp4.aac', + name: 'AAC support', + status: 'optional' + }, { + id: 'codecs.mp4.ac3', + name: 'Dolby Digital support', + status: 'optional' + }, { + id: 'codecs.mp4.ec3', + name: 'Dolby Digital Plus support', + status: 'optional' + }, { + id: 'codecs.ogg.vorbis', + name: 'Ogg Vorbis support', + status: 'optional' + }, { + id: 'codecs.ogg.opus', + name: 'Ogg Opus support', + status: 'optional' + }, { + id: 'codecs.webm.vorbis', + name: 'WebM with Vorbis support', + status: 'optional' + }, { + id: 'codecs.webm.opus', + name: 'WebM with Opus support', + status: 'optional' + } + ] + }, { + id: 'streaming', + name: 'Streaming', + status: 'stable', + items: [ + { + id: 'mediasource', + name: 'Media Source extensions', + value: { maximum: 5, award: { PREFIX: 2 } }, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/media-source/' ], + [ 'wp', '/apis/media_source_extensions' ] + ] + }, { + id: 'drm', + name: 'DRM support', + status: 'controversial', + url: 'http://www.w3.org/TR/encrypted-media/' + }, + + 'Adaptive bit rate', + + { + id: 'type.dash', + name: 'Dynamic Adaptive Streaming / MPEG-DASH' + }, { + id: 'type.hls', + name: 'HTTP Live Streaming / HLS' + }, + + 'Codecs', + + { + id: 'video.codecs', + name: 'Video codecs', + items: [ + { + id: 'mp4.h264', + name: 'MP4 with H.264 support', + status: 'optional', + urls: [ + [ 'other', 'http://ip.hhi.de/imagecom_G1/assets/pdfs/csvt_overview_0305.pdf' ] + ] + }, { + id: 'mp4.h265', + name: 'MP4 with H.265 support', + status: 'optional' + }, { + id: 'ts.h264', + name: 'TS with H.264 support', + status: 'optional', + urls: [ + [ 'other', 'http://ip.hhi.de/imagecom_G1/assets/pdfs/csvt_overview_0305.pdf' ] + ] + }, { + id: 'ts.h265', + name: 'TS with H.265 support', + status: 'optional' + }, { + id: 'webm.vp8', + name: 'WebM with VP8 support', + status: 'optional', + urls: [ + [ 'webm', 'http://www.webmproject.org/' ], + [ 'ietf', 'http://www.rfc-editor.org/rfc/rfc6386.txt' ] + ] + }, { + id: 'webm.vp9', + name: 'WebM with VP9 support', + status: 'optional', + urls: [ + [ 'webm', 'http://www.webmproject.org/' ], + [ 'ietf', 'http://tools.ietf.org/id/draft-grange-vp9-bitstream-00.txt' ] + ] + } + ] + }, { + id: 'audio.codecs', + name: 'Audio codecs', + items: [ + { + id: 'mp4.aac', + name: 'MP4 with AAC support', + status: 'optional' + }, { + id: 'mp4.ac3', + name: 'MP4 with Dolby Digital support', + status: 'optional' + }, { + id: 'mp4.ec3', + name: 'MP4 with Dolby Digital Plus support', + status: 'optional' + }, { + id: 'ts.aac', + name: 'TS with AAC support', + status: 'optional' + }, { + id: 'ts.ac3', + name: 'TS with Dolby Digital support', + status: 'optional' + }, { + id: 'ts.ec3', + name: 'TS with Dolby Digital Plus support', + status: 'optional' + }, { + id: 'webm.vorbis', + name: 'WebM with Vorbis support', + status: 'optional' + }, { + id: 'webm.opus', + name: 'WebM with Opus support', + status: 'optional' + } + ] + } + ] + } + ] + }, + + { + id: 'graphicseffects', + name: '3D, Graphics & Effects', + column: 'right', + items: [ + { + id: 'responsive', + status: 'stable', + name: 'Responsive images', + items: [ + { + id: 'picture', + name: 'picture element', + value: 5, + urls: [ + [ 'ricg', 'http://responsiveimages.org/' ], + [ 'w3c', 'http://www.w3.org/html/wg/drafts/html/master/single-page.html#the-picture-element' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/embedded-content.html#the-picture-element' ] + ] + }, { + id: 'srcset', + name: 'srcset attribute', + value: 5, + urls: [ + [ 'ricg', 'http://responsiveimages.org/' ], + [ 'w3c', 'http://www.w3.org/html/wg/drafts/srcset/w3c-srcset/' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/embedded-content.html#attr-img-srcset' ] + ] + }, { + id: 'sizes', + name: 'sizes attribute', + value: 5, + urls: [ + [ 'ricg', 'http://responsiveimages.org/' ], + [ 'w3c', 'http://www.w3.org/html/wg/drafts/html/master/single-page.html#valid-source-size-list' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-sizes' ], + ] + } + ] + }, { + id: 'canvas', + name: '2D Graphics', + status: 'stable', + items: [ + { + id: 'context', + name: 'Canvas 2D graphics', + value: 10, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/2dcontext/' ], + [ 'wp', '/apis/canvas' ], + [ 'mdn', '/Web/API/Canvas_API' ] + ] + }, + + 'Drawing primitives', + + { + id: 'text', + name: 'Text support', + value: 2, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/2dcontext/#drawing-text-to-the-canvas' ], + [ 'wp', '/apis/canvas/CanvasRenderingContext2D/fillText' ] + ] + }, { + id: 'path', + name: 'Path support', + value: { maximum: 2, award: { OLD: 1 } }, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/2dcontext/#path-objects' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/scripting.html#path2d-objects' ] + ] + }, { + id: 'ellipse', + name: 'Ellipse support', + value: 2, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/2dcontext/#dom-context-2d-ellipse' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/scripting.html#dom-context-2d-ellipse' ] + ] + }, { + id: 'dashed', + name: 'Dashed line support', + value: 2, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/scripting.html#dom-context-2d-setlinedash' ] + ] + }, { + id: 'focusring', + name: 'System focus ring support', + value: 1, + urls: [ + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/scripting.html#dom-context-2d-drawfocusifneeded' ] + ] + }, + + 'Features', + + { + id: 'hittest', + name: 'Hit testing support', + status: 'proposal', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/2dcontext/#dom-context-2d-addhitregion' ], + [ 'whatwg', 'http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-addhitregion' ] + ] + }, { + id: 'blending', + name: 'Blending modes', + status: 'proposal', + value: 5, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/compositing-1/#canvascompositingandblending' ] + ] + }, + + 'Image export formats', + + { + id: 'png', + name: 'PNG support', + status: 'optional' + }, { + id: 'jpeg', + name: 'JPEG support', + status: 'optional' + }, { + id: 'jpegxr', + name: 'JPEG-XR support', + status: 'optional' + }, { + id: 'webp', + name: 'WebP support', + status: 'optional' + } + ] + }, { + id: '3d', + status: 'stable', + name: '3D and VR', + items: [ + '3D Graphics', + + { + id: 'webgl', + name: 'WebGL', + value: { maximum: 15, award: { PREFIX: 10 } }, + urls: [ + [ 'khronos', 'https://www.khronos.org/registry/webgl/specs/latest/1.0/' ], + [ 'wp', '/webgl' ], + [ 'mdn', '/Web/API/WebGL_API' ] + ] + + }, { + id: 'webgl2', + name: 'WebGL 2', + status: 'experimental', + value: 5, + urls: [ + [ 'khronos', 'https://www.khronos.org/registry/webgl/specs/latest/2.0/' ], + [ 'wp', '/webgl' ], + [ 'mdn', '/Web/API/WebGL_API' ] + ] + + }, + + 'VR Headset', + + { + id: 'webvr', + name: 'WebVR', + status: 'experimental', + value: 3, + url: 'https://w3c.github.io/webvr/' + + } + ] + }, { + id: 'animation', + status: 'stable', + name: 'Animation', + items: [ + { + id: 'webanimation', + name: 'Web Animations API', + status: 'experimental', + value: 3, + urls: [ + [ 'w3c', 'https://w3c.github.io/web-animations/' ] + ] + }, { + id: 'requestAnimationFrame', + name: 'window.requestAnimationFrame', + value: { maximum: 5, award: { PREFIX: 3 } }, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/animation-timing/#requestAnimationFrame' ], + [ 'wp', '/dom/Window/requestAnimationFrame' ], + [ 'mdn', '/Web/API/window/requestAnimationFrame' ] + ] + } + ] + } + ] + }, + + { + id: 'connectivity', + name: 'Connectivity', + column: 'left', + items: [ + { + id: 'communication', + status: 'stable', + name: 'Communication', + items: [ + { + id: 'eventSource', + name: 'Server-Sent Events', + value: 5, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/eventsource/' ], + [ 'mdn', '/Web/API/Server-sent_events/Using_server-sent_events' ] + ] + }, + + { + id: 'beacon', + name: 'Beacon', + status: 'proposal', + value: 2, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/beacon/' ], + [ 'mdn', '/Web/API/Navigator/sendBeacon' ] + ] + }, + + { + id: 'fetch', + name: 'Fetch', + status: 'proposal', + value: 6, + urls: [ + [ 'whatwg', 'https://fetch.spec.whatwg.org/' ], + [ 'mdn', '/Web/API/Fetch_API' ] + ] + }, + + + 'XMLHttpRequest Level 2', + + { + id: 'xmlhttprequest2.upload', + name: 'Upload files', + value: 5, + url: 'http://www.w3.org/TR/XMLHttpRequest2/#the-upload-attribute' + }, { + id: 'xmlhttprequest2.response', + name: 'Response type support', + urls: [ + [ 'mdn', '/Web/API/XMLHttpRequest' ] + ], + items: [ + { + id: 'text', + name: 'Text response type', + value: 1, + url: 'http://www.w3.org/TR/XMLHttpRequest2/#dom-xmlhttprequest-responsetype' + }, { + id: 'document', + name: 'Document response type', + value: 2, + url: 'http://www.w3.org/TR/XMLHttpRequest2/#dom-xmlhttprequest-responsetype' + }, { + id: 'array', + name: 'ArrayBuffer response type', + value: 2, + url: 'http://www.w3.org/TR/XMLHttpRequest2/#dom-xmlhttprequest-responsetype' + }, { + id: 'blob', + name: 'Blob response type', + value: 2, + url: 'http://www.w3.org/TR/XMLHttpRequest2/#dom-xmlhttprequest-responsetype' + } + ] + }, + + 'WebSocket', + + { + id: 'websocket.basic', + name: 'Basic socket communication', + value: { maximum: 10, award: { PREFIX: 7, OLD: 5 } }, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/websockets/' ], + [ 'mdn', '/Web/API/WebSockets_API' ] + ] + }, { + id: 'websocket.binary', + name: 'ArrayBuffer and Blob support', + value: 5, + urls: [ + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/comms.html#dom-websocket-binarytype' ], + [ 'mdn', '/Web/API/WebSockets_API' ] + ] + } + ] + }, { + id: 'streams', + status: 'experimental', + name: 'Streams', + items: [ + { + id: 'readable', + name: 'Readable streams', + value: 4, + urls: [ + [ 'whatwg', 'https://streams.spec.whatwg.org/' ] + ] + }, { + id: 'writeable', + name: 'Writable streams', + value: 2, + urls: [ + [ 'whatwg', 'https://streams.spec.whatwg.org/' ] + ] + } + ] + }, { + id: 'rtc', + name: 'Peer To Peer', + status: 'stable', + items: [ + 'Connectivity', + + { + id: 'webrtc', + name: 'WebRTC 1.0', + value: { maximum: 15, award: { PREFIX: 10 } }, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/webrtc/' ], + [ 'wp', '/apis/webrtc/RTCPeerConnection' ], + [ 'mdn', '/Web/Guide/API/WebRTC' ] + ] + }, { + id: 'objectrtc', + name: 'ObjectRTC API for WebRTC', + status: 'proposal', + value: { maximum: 15, award: { PREFIX: 10 }, conditional: '!rtc.webrtc' }, + urls: [ + [ 'w3c', 'http://ortc.org/wp-content/uploads/2014/10/ortc.html' ] + ] + }, { + id: 'datachannel', + name: 'Data channel', + value: { maximum: 5, award: { PREFIX: 3 } }, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/webrtc/#peer-to-peer-data-api' ], + [ 'wp', '/apis/webrtc/RTCDataChannel' ], + [ 'mdn', '/Web/Guide/API/WebRTC' ] + ] + }, + + 'Input', + + { + key: 'media.getUserMedia', + name: 'Access the webcam', + value: { maximum: 15, award: { PREFIX: 10, OLD: 10 } }, + urls: [ + [ 'w3c', 'http://dev.w3.org/2011/webrtc/editor/getusermedia.html' ], + [ 'wp', '/dom/Navigator/getUserMedia' ], + [ 'mdn', '/Web/Guide/API/WebRTC' ] + ] + }, { + key: 'media.getDisplayMedia', + name: 'Screen Capture', + status: 'experimental', + value: 5, + urls: [ + [ 'w3c', 'https://w3c.github.io/mediacapture-screen-share/' ] + ] + }, { + key: 'media.enumerateDevices', + name: 'Enumerate devices', + status: 'proposal', + value: 3, + urls: [ + [ 'w3c', 'https://w3c.github.io/mediacapture-main/#mediadevices' ] + ] + }, + + 'Recording', + + { + id: 'recorder', + name: 'Media Stream recorder', + status: 'proposal', + value: 2, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/mediastream-recording/' ] + ] + } + ] + } + ] + }, + + { + id: 'performanceintegration', + name: 'Performance & Integration', + column: 'left', + items: [ + { + id: 'interaction', + status: 'stable', + name: 'User interaction', + items: [ + 'Drag and drop', + + { + id: 'dragdrop.attributes', + name: 'Attributes', + urls: [ + [ 'mdn', '/Web/Guide/HTML/Drag_and_drop' ] + ], + items: [ + { + id: 'draggable', + name: 'draggable attribute', + value: 1, + url: 'http://www.w3.org/TR/html5/editing.html#the-draggable-attribute' + }, { + id: 'dropzone', + name: 'dropzone attribute', + value: 1, + url: 'http://www.w3.org/TR/html5/editing.html#the-dropzone-attribute ' + } + ] + }, { + id: 'dragdrop.events', + name: 'Events', + urls: [ + [ 'mdn', '/Web/Guide/HTML/Drag_and_drop' ] + ], + items: [ + { + id: 'ondrag', + name: 'ondrag event', + url: 'http://www.w3.org/TR/html5/editing.html#dndevents' + }, { + id: 'ondragstart', + name: 'ondragstart event', + url: 'http://www.w3.org/TR/html5/editing.html#dndevents' + }, { + id: 'ondragenter', + name: 'ondragenter event', + url: 'http://www.w3.org/TR/html5/editing.html#dndevents' + }, { + id: 'ondragover', + name: 'ondragover event', + url: 'http://www.w3.org/TR/html5/editing.html#dndevents' + }, { + id: 'ondragleave', + name: 'ondragleave event', + url: 'http://www.w3.org/TR/html5/editing.html#dndevents' + }, { + id: 'ondragend', + name: 'ondragend event', + url: 'http://www.w3.org/TR/html5/editing.html#dndevents' + }, { + id: 'ondrop', + name: 'ondrop event', + url: 'http://www.w3.org/TR/html5/editing.html#dndevents' + } + ] + }, + + 'HTML editing', + + { + id: 'editing.elements', + name: 'Editing elements', + urls: [ + [ 'mdn', '/Web/Guide/HTML/Content_Editable' ] + ], + items: [ + { + id: 'contentEditable', + name: 'contentEditable attribute', + value: 5, + url: 'http://www.w3.org/TR/html5/editing.html#contenteditable' + }, { + id: 'isContentEditable', + name: 'isContentEditable property', + value: 1, + url: 'http://www.w3.org/TR/html5/editing.html#contenteditable' + } + ] + }, { + id: 'editing.documents', + name: 'Editing documents', + urls: [ + [ 'mdn', '/Web/Guide/HTML/Content_Editable' ] + ], + items: [ + { + id: 'designMode', + name: 'designMode attribute', + value: 1, + url: 'http://www.w3.org/TR/html5/editing.html#designMode' + } + ] + }, { + id: 'editing.selectors', + name: 'CSS selectors', + value: { maximum: 2, award: { PREFIX: 1 } }, + urls: [ + [ 'mdn', '/Web/Guide/HTML/Content_Editable' ] + ], + items: [ + { + id: 'read-write', + name: ':read-write selector', + url: 'http://www.w3.org/TR/html5/links.html#selector-read-write' + }, { + id: 'read-only', + name: ':read-only selector', + url: 'http://www.w3.org/TR/html5/links.html#selector-read-only' + } + ] + }, { + id: 'editing.apis', + name: 'APIs', + value: 2, + urls: [ + [ 'mdn', '/Web/Guide/HTML/Content_Editable' ] + ], + items: [ + { + id: 'execCommand', + name: 'execCommand method', + url: 'https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html' + }, { + id: 'queryCommandEnabled', + name: 'queryCommandEnabled method', + url: 'https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html' + }, { + id: 'queryCommandIndeterm', + name: 'queryCommandIndeterm method', + url: 'https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html' + }, { + id: 'queryCommandState', + name: 'queryCommandState method', + url: 'https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html' + }, { + id: 'queryCommandSupported', + name: 'queryCommandSupported method', + url: 'https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html' + }, { + id: 'queryCommandValue', + name: 'queryCommandValue method', + url: 'https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html' + } + ] + }, + + 'Clipboard', + + { + id: 'clipboard', + name: 'Clipboard API and events', + value: 5, + url: 'https://w3c.github.io/clipboard-apis/' + }, + + 'Spellcheck', + + { + id: 'spellcheck', + name: 'spellcheck attribute', + value: 2, + url: 'http://www.w3.org/TR/html5/editing.html#attr-spellcheck' + } + ] + }, { + id: 'performance', + status: 'stable', + name: 'Performance', + items: [ + 'Workers', + + { + id: 'worker', + name: 'Web Workers', + value: 10, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/workers/#dedicated-workers-and-the-worker-interface' ], + [ 'mdn', '/Web/API/Web_Workers_API/Using_web_workers' ] + ] + }, { + id: 'sharedWorker', + name: 'Shared Workers', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/workers/#shared-workers-and-the-sharedworker-interface' ], + [ 'mdn', '/Web/API/Web_Workers_API/Using_web_workers' ] + ] + }, + + 'Other', + + { + id: 'requestIdleCallback', + name: 'window.requestIdleCallback', + status: 'experimental', + value: 1, + url: 'https://w3c.github.io/requestidlecallback/#the-requestidlecallback-method' + } + ] + }, { + id: 'security', + status: 'stable', + name: 'Security', + items: [ + { + id: 'crypto', + name: 'Web Cryptography API', + status: 'proposal', + value: { maximum: 5, award: { PREFIX: 3 } }, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/WebCryptoAPI/' ] + ] + }, { + id: 'csp10', + name: 'Content Security Policy 1', + value: 3, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/CSP1/' ], + [ 'mdn', '/Web/Security/CSP' ] + ] + }, { + id: 'csp11', + name: 'Content Security Policy 2', + status: 'proposal', + value: 2, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/CSP2/' ], + [ 'mdn', '/Web/Security/CSP' ] + ] + }, { + id: 'cors', + name: 'Cross-Origin Resource Sharing', + value: 4, + urls: [ + [ 'mdn', '/Web/HTTP/Access_control_CORS' ] + ] + }, { + id: 'integrity', + name: 'Subresource Integrity', + status: 'proposal', + value: 2, + url: 'http://www.w3.org/TR/SRI/' + }, { + id: 'postMessage', + name: 'Cross-document messaging', + value: 2, + urls: [ + [ 'w3c', 'http://dev.w3.org/html5/postmsg/' ], + [ 'wp', '/apis/web-messaging' ], + [ 'mdn', '/Web/API/Window/postMessage' ] + ] + }, + + 'Authentication', + + { + id: 'authentication', + name: 'Web Authentication / FIDO 2', + status: 'experimental', + value: 3, + url: 'https://w3c.github.io/webauthn/' + }, + + { + id: 'credential', + name: 'Credential Management', + status: 'experimental', + value: 3, + url: 'http://w3c.github.io/webappsec-credential-management/' + }, + + 'Iframes', + + { + id: 'sandbox', + name: 'Sandboxed iframe', + value: 4, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/embedded-content-0.html#attr-iframe-sandbox' ], + [ 'mdn', '/Web/HTML/Element/iframe#attr-sandbox' ] + ] + }, { + id: 'srcdoc', + name: 'iframe with inline contents', + value: 4, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/embedded-content-0.html#attr-iframe-srcdoc' ], + [ 'mdn', '/Web/HTML/Element/iframe#attr-srcdoc' ] + ] + } + ] + }, { + id: 'payments', + status: 'experimental', + name: 'Payments', + items: [ + { + id: 'payments', + name: 'Web Payments', + value: 5, + url: 'https://w3c.github.io/browser-payment-api/specs/paymentrequest.html' + } + ] + } + ] + }, + + { + id: 'offlinestorage', + name: 'Offline & Storage', + column: 'right', + items: [ + { + id: 'offline', + name: 'Web applications', + status: 'stable', + items: [ + 'Offline resources', + + { + id: 'applicationCache', + name: 'Application Cache', + value: 3, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/browsers.html#offline' ], + [ 'wp', '/apis/appcache/ApplicationCache' ], + [ 'mdn', '/Web/HTML/Using_the_application_cache' ] + ] + }, { + id: 'serviceWorkers', + name: 'Service Workers', + status: 'proposal', + value: 10, + urls: [ + [ 'w3c', 'https://www.w3.org/TR/service-workers/' ], + [ 'mdn', '/Web/API/Service_Worker_API' ] + ] + }, { + id: 'pushMessages', + name: 'Push Messages', + status: 'proposal', + value: 2, + urls: [ + [ 'w3c', 'https://w3c.github.io/push-api/' ], + [ 'mdn', '/Web/API/Push_API' ] + ] + }, + + 'Content and Scheme handlers', + + { + id: 'registerProtocolHandler', + name: 'Custom scheme handlers', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/webappapis.html#custom-handlers' ], + [ 'mdn', '/Web-based_protocol_handlers' ] + ] + }, { + id: 'registerContentHandler', + name: 'Custom content handlers', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/webappapis.html#custom-handlers' ], + [ 'mdn', '/Web/API/Navigator/registerContentHandler' ] + ] + } + ] + }, { + id: 'storage', + name: 'Storage', + status: 'stable', + items: [ + 'Key-value storage', + + { + id: 'sessionStorage', + name: 'Session Storage', + value: 5, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/webstorage/#the-sessionstorage-attribute' ], + [ 'wp', '/apis/web-storage' ], + [ 'mdn', '/Web/API/Web_Storage_API' ] + ] + }, { + id: 'localStorage', + name: 'Local Storage', + value: 5, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/webstorage/#the-localstorage-attribute' ], + [ 'wp', '/apis/web-storage' ], + [ 'mdn', '/Web/API/Web_Storage_API' ] + ] + }, + + 'Database storage', + + { + id: 'indexedDB.basic', + name: 'IndexedDB', + value: { maximum: 21, award: { PREFIX: 16 } }, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/IndexedDB/' ], + [ 'wp', '/apis/indexeddb' ], + [ 'mdn', '/Web/API/IndexedDB_API' ] + ] + }, { + id: 'indexedDB.blob', + name: 'Objectstore Blob support', + value: 2, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/IndexedDB/' ], + [ 'wp', '/apis/indexeddb' ], + [ 'mdn', '/Web/API/IndexedDB_API' ] + ] + }, { + id: 'indexedDB.arraybuffer', + name: 'Objectstore ArrayBuffer support', + value: 2, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/IndexedDB/' ], + [ 'wp', '/apis/indexeddb' ], + [ 'mdn', '/Web/API/IndexedDB_API' ] + ] + }, + + 'The Web SQL Database specification is no longer being updated and has been replaced by IndexedDB. Because at least 3 vendors have shipped implementations of this specification we still include it in this test.', + + { + id: 'sqlDatabase', + name: 'Web SQL Database', + status: 'rejected', + value: { maximum: 5, conditional: '!storage.indexedDB.basic' }, + + url: 'http://www.w3.org/TR/webdatabase/' + } + ] + }, { + id: 'files', + name: 'Files', + status: 'stable', + items: [ + 'Reading files', + + { + id: 'fileReader', + name: 'Basic support for reading files', + value: 7, + urls: [ + [ 'w3c', 'http://dev.w3.org/2006/webapi/FileAPI/#filereader-interface' ], + [ 'wp', '/apis/file' ], + [ 'mdn', '/Using_files_from_web_applications' ] + ] + }, { + id: 'fileReader.blob', + name: 'Create a Blob from a file', + value: 2, + urls: [ + [ 'w3c', 'http://dev.w3.org/2006/webapi/FileAPI/#dfn-Blob' ], + ] + }, { + id: 'fileReader.dataURL', + name: 'Create a Data URL from a Blob', + value: 2, + urls: [ + [ 'w3c', 'http://dev.w3.org/2006/webapi/FileAPI/#dfn-readAsDataURL' ], + ] + }, { + id: 'fileReader.arraybuffer', + name: 'Create an ArrayBuffer from a Blob', + value: 2, + urls: [ + [ 'w3c', 'http://dev.w3.org/2006/webapi/FileAPI/#dfn-readAsArrayBuffer' ], + ] + }, { + id: 'fileReader.objectURL', + name: 'Create a Blob URL from a Blob', + value: 2, + urls: [ + [ 'w3c', 'http://dev.w3.org/2006/webapi/FileAPI/#dfn-createObjectURL' ], + ] + }, + + 'Accessing the file system', + + { + id: 'getFileSystem', + name: 'FileSystem API', + status: 'experimental', + urls: [ + [ 'w3c', 'http://w3c.github.io/filesystem-api/' ], + ] + }, + + 'The Directories and System API proposal has failed to gain traction among browser vendors and is only supported in some Webkit based browsers. No additional points are awarded for supporting this API.', + + { + id: 'fileSystem', + name: 'File API: Directories and System', + status: 'rejected', + urls: [ + [ 'w3c', 'http://www.w3.org/TR/file-system-api/' ], + [ 'wp', '/apis/filesystem' ] + ] + } + ] + } + ] + }, + + { + id: 'other', + name: 'Other', + column: 'right', + items: [ + { + id: 'scripting', + name: 'Scripting', + status: 'stable', + items: [ + 'Script execution', + + { + id: 'async', + name: 'Asynchronous script execution', + value: 3, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/scripting-1.html#attr-script-async' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/scripting.html#attr-script-async' ], + [ 'mdn', '/Web/HTML/Element/script' ], + [ 'wp', '/html/elements/script' ] + ] + }, { + id: 'defer', + name: 'Defered script execution', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/scripting-1.html#attr-script-defer' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/scripting.html#attr-script-defer' ], + [ 'mdn', '/Web/HTML/Element/script' ], + [ 'wp', '/html/elements/script' ] + ] + }, { + id: 'executionevents', + name: 'Script execution events', + status: 'rejected', + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/scripting-1.html#the-script-element' ], + [ 'whatwg', 'http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#the-script-element' ], + [ 'mdn', '/Web/Events/beforescriptexecute' ] + ] + }, { + id: 'onerror', + name: 'Runtime script error reporting', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/webappapis.html#runtime-script-errors' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/webappapis.html#runtime-script-errors' ], + [ 'mdn', '/Web/API/GlobalEventHandlers/onerror' ] + ] + }, + + 'ECMAScript 5', + + { + id: 'es5.json', + name: 'JSON encoding and decoding', + value: 2, + urls: [ + [ 'ecma', 'http://www.ecma-international.org/ecma-262/6.0/#sec-json-object' ], + [ 'mdn', '/JSON' ], + [ 'wp', '/apis/json' ] + ] + }, + + 'ECMAScript 6', + + { + id: 'es6.modules', + name: 'Modules', + value: 3, + urls: [ + [ 'ecma', 'https://tc39.github.io/ecma262/#prod-Module' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/scripting.html#attr-script-type' ], + ] + }, { + id: 'es6.class', + name: 'Classes', + value: 1, + urls: [ + [ 'ecma', 'http://www.ecma-international.org/ecma-262/6.0/#sec-class-definitions' ], + ] + }, { + id: 'es6.arrow', + name: 'Arrow functions', + value: 1, + urls: [ + [ 'ecma', 'http://www.ecma-international.org/ecma-262/6.0/#sec-arrow-function-definitions' ], + ] + }, { + id: 'es6.promises', + name: 'Promises', + value: 3, + urls: [ + [ 'ecma', 'http://www.ecma-international.org/ecma-262/6.0/#sec-promise-objects' ], + [ 'mdn', '/Web/JavaScript/Reference/Global_Objects/Promise' ] + ] + }, { + id: 'es6.template', + name: 'Template strings', + value: 1, + urls: [ + [ 'ecma', 'http://www.ecma-international.org/ecma-262/6.0/#sec-template-literals' ], + ] + }, { + id: 'es6.datatypes', + name: 'Typed arrays', + value: 2, + status: 'stable', + urls: [ + [ 'khronos', 'http://www.khronos.org/registry/typedarray/specs/latest/' ], + [ 'ecma', 'http://www.ecma-international.org/ecma-262/6.0/#sec-structured-data' ] + ] + }, { + id: 'es6.i18n', + name: 'Internationalization', + value: 2, + urls: [ + [ 'ecma', 'http://www.ecma-international.org/ecma-402/1.0/' ], + [ 'mdn', '/Web/JavaScript/Reference/Global_Objects/Intl' ] + ] + }, + + 'ECMAScript 7', + + { + id: 'es7.async', + name: 'Async and Await', + value: 3, + urls: [ + [ 'ecma', 'https://tc39.github.io/ecmascript-asyncawait/' ] + ] + }, + + 'Other API\'s', + + { + id: 'base64', + name: 'Base64 encoding and decoding', + value: 1, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/webappapis.html#atob' ], + [ 'whatwg', 'https://html.spec.whatwg.org/multipage/webappapis.html#atob' ], + [ 'mdn', '/Web/API/WindowBase64/atob' ] + ] + }, { + id: 'mutationObserver', + name: 'Mutation Observer', + value: { maximum: 2, award: { PREFIX: 1 } }, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/dom/#mutation-observers' ], + [ 'mdn', '/Web/API/MutationObserver' ] + ] + }, { + id: 'url', + name: 'URL API', + value: { maximum: 2, award: { PREFIX: 1 } }, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/url/' ] + ] + }, { + id: 'encoding', + name: 'Encoding API', + value: 2, + urls: [ + [ 'whatwg', 'https://encoding.spec.whatwg.org' ], + [ 'mdn', '/Web/API/TextDecoder' ] + ] + } + ] + }, { + id: 'other', + name: 'Other', + status: 'stable', + items: [ + { + id: 'history', + name: 'Session history', + value: 4, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/html5/browsers.html#the-history-interface' ], + [ 'wp', '/dom/History' ], + [ 'mdn', '/Web/Guide/API/DOM/Manipulating_the_browser_history' ] + ] + }, { + id: 'pagevisiblity', + name: 'Page Visibility', + value: 2, + urls: [ + [ 'w3c', 'http://www.w3.org/TR/page-visibility/' ], + [ 'mdn', '/Web/Guide/User_experience/Using_the_Page_Visibility_API' ] + ] + }, { + id: 'getSelection', + name: 'Text selection', + value: 2, + url: 'http://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#selections' + }, { + id: 'scrollIntoView', + name: 'Scroll into view', + value: 1, + url: 'http://dev.w3.org/csswg/cssom-view/#dom-element-scrollintoview' + } + ] + } + ] + } +] diff --git a/src/AngleSharp.Js.Tests/Fixtures/Html5Test/scripts/8/engine.js b/src/AngleSharp.Js.Tests/Fixtures/Html5Test/scripts/8/engine.js new file mode 100644 index 0000000..5041149 --- /dev/null +++ b/src/AngleSharp.Js.Tests/Fixtures/Html5Test/scripts/8/engine.js @@ -0,0 +1,4563 @@ + +Test = +Test8 = (function () { + + var release = 8; + + var NO = 0, + YES = 1, + OLD = 2, + BUGGY = 4, + PREFIX = 8, + BLOCKED = 16, + DISABLED = 32, + UNCONFIRMED = 64, + UNKNOWN = 128, + EXPERIMENTAL = 256; + + var blacklists = []; + + + var testsuite = [ + + /* doctype */ + + function (results) { + results.addItem({ + key: 'parsing.doctype', + passed: document.compatMode == 'CSS1Compat' + }); + }, + + + /* tokenizer */ + + function (results) { + var result = true; + var e = document.createElement('div'); + + try { + e.innerHTML = ""; + result &= e.firstChild && e.firstChild.nodeName == "DIV"; + result &= e.firstChild && (e.firstChild.attributes[0].nodeName == "\"foo" || e.firstChild.attributes[0].name == "\"foo"); + + e.innerHTML = ""; + result &= e.firstChild && e.firstChild.getAttribute("href") == "\nbar"; + + e.innerHTML = ""; + result &= e.firstChild == null; + + e.innerHTML = "\u000D"; + result &= e.firstChild && e.firstChild.nodeValue == "\u000A"; + + e.innerHTML = "⟨⟩"; + result &= e.firstChild.nodeValue == "\u27E8\u27E9"; + + e.innerHTML = "'"; + result &= e.firstChild.nodeValue == "'"; + + e.innerHTML = "ⅈ"; + result &= e.firstChild.nodeValue == "\u2148"; + + e.innerHTML = "𝕂"; + result &= e.firstChild.nodeValue == "\uD835\uDD42"; + + e.innerHTML = "∉"; + result &= e.firstChild.nodeValue == "\u2209"; + + e.innerHTML = ''; + result &= e.firstChild && e.firstChild.nodeType == 8 && e.firstChild.nodeValue == '?import namespace="foo" implementation="#bar"'; + + e.innerHTML = ''; + result &= e.firstChild && e.firstChild.nodeType == 8 && e.firstChild.nodeValue == 'foo--bar'; + + e.innerHTML = ''; + result &= e.firstChild && e.firstChild.nodeType == 8 && e.firstChild.nodeValue == '[CDATA[x]]'; + + e.innerHTML = "-->"; + result &= e.firstChild && e.firstChild.firstChild && e.firstChild.firstChild.nodeValue == ""; + result &= e.firstChild && e.firstChild.firstChild && e.firstChild.firstChild.nodeValue == ""; + result &= e.firstChild && e.firstChild.firstChild && e.firstChild.firstChild.nodeValue == ""; + result &= e.firstChild && e.firstChild.firstChild && e.firstChild.firstChild.nodeValue == "