diff --git a/.agents/skills/elsa-roadmap-refresh/SKILL.md b/.agents/skills/elsa-roadmap-refresh/SKILL.md new file mode 100644 index 000000000..412af9514 --- /dev/null +++ b/.agents/skills/elsa-roadmap-refresh/SKILL.md @@ -0,0 +1,126 @@ +--- +name: elsa-roadmap-refresh +description: Refresh the Elsa roadmap from current evidence. Use when Codex needs to update ROADMAP.md or the public roadmap issue by researching elsa-core, elsa-studio, and elsa-extensions source code, specs, releases, commits, issues, pull requests, and discussions; classify shipped foundations, partial/productization work, roadmap candidates, stale items, and recommendations; then update the roadmap checklist and GitHub issue coherently. +--- + +# Elsa Roadmap Refresh + +## Purpose + +Use this skill to refresh Elsa's roadmap from evidence across the Elsa product surface: + +- `elsa-workflows/elsa-core` +- `elsa-workflows/elsa-studio` +- `elsa-workflows/elsa-extensions` + +The output should be a coherent product roadmap, not a raw issue digest. Ground every substantial change in source code, specs, releases, issues, pull requests, or discussions. + +## Safety Rules + +- Before editing, run `git status --short` in `elsa-core`. +- Never revert unrelated user changes. +- If `ROADMAP.md` or `README.md` already has uncommitted user edits, stop and report the conflict unless the user explicitly asked to work through it. +- Edit only roadmap-related files unless the user asks for more. +- Do not commit, push, or publish unless the user or automation prompt explicitly asks for it. +- If updating GitHub issue `elsa-core#3232`, use the final `ROADMAP.md` body as the issue body. + +## Evidence Workflow + +1. Read the current roadmap. + - `ROADMAP.md` + - `README.md` roadmap link, if relevant + - GitHub issue `elsa-workflows/elsa-core#3232` + +2. Inspect `elsa-core`. + - Source modules under `src/modules` + - App hosts under `src/apps` + - Specs under `specs` + - Docs under `doc` and `design` + - Recent releases, commits, open issues, discussions, and open PRs + +3. Inspect `elsa-studio`. + - Source layout and feature modules + - Designer, diagnostics, auth, localization, embedding, workflow authoring, and instance UX + - Recent releases, commits, open issues, discussions, and open PRs + +4. Inspect `elsa-extensions`. + - Module families and integration foundations + - Connections, Secrets, Agents, OpenAPI, schedulers, messaging, persistence, data tooling, and package manifests + - Recent releases, commits, open issues, and open PRs + - Discussions if enabled; otherwise state that issue/PR signal is the available source + +Use `gh` for GitHub data when available. Prefer local clones when present; otherwise use temporary clones or `gh repo clone` into `/tmp`. + +## Classification Rules + +Use these categories consistently: + +- `[x]` shipped foundation: implemented in source or released enough to build on. +- `[~]` partially shipped or needs productization: code exists, but docs, Studio UX, integration, tests, release packaging, or operational readiness are incomplete. +- `[ ]` roadmap candidate: valuable capability not yet implemented or only represented by issue/PR/proposal. +- stale/obsolete: roadmap item is already done, superseded, or no longer matches repository direction. + +Be explicit when a conclusion is an inference from evidence rather than a direct source fact. + +## Roadmap Editing Rules + +- Keep `ROADMAP.md` product-oriented and exciting, but technically defensible. +- Preserve the main structure unless a better structure is clearly needed: + - North Star + - Capability Checklist + - Current Foundations + - Production Confidence + - Authoring Productivity + - Integrations And Ecosystem + - Observability And Operations + - Security, Identity, And Enterprise Readiness + - AI-Assisted Workflow Engineering + - Recommended Sequencing + - Maintainership Recommendations +- Update `Last refreshed` to the current date. +- Keep issue and PR links close to the claims they support. +- Prefer platform tracks over long lists of unrelated features. +- Separate what is already present from what still needs productization. +- Do not overpromise release dates. + +## High-Value Themes To Re-Evaluate Each Refresh + +- Runtime recovery, graceful shutdown, distributed execution, scheduler/message reliability +- Studio designer reliability, state machine authoring, debugging, progress/timeline, embedded components +- Studio diagnostics, structured logs, console logs, OpenTelemetry, workflow incident timelines +- Extension Platform, package manifests, Connections, Secrets, generated activities, connector SDK +- Agents, MCP/tooling, provider matrix, AI-assisted authoring +- OpenAPI activity provider, Azure Functions, Azure DevOps, Microsoft 365 and Google Workspace integrations +- Security, OIDC, tenant/role activity visibility, localization, white-label readiness +- Marketplace/plugin installation path and package maturity states + +## Recommended GitHub Commands + +```bash +gh issue view 3232 --repo elsa-workflows/elsa-core --json title,body,updatedAt,url +gh issue list --repo elsa-workflows/elsa-core --state open --limit 200 --json number,title,labels,updatedAt,url +gh issue list --repo elsa-workflows/elsa-studio --state open --limit 200 --json number,title,labels,updatedAt,url +gh issue list --repo elsa-workflows/elsa-extensions --state open --limit 200 --json number,title,labels,updatedAt,url +gh pr list --repo elsa-workflows/elsa-core --state open --limit 100 --json number,title,updatedAt,url +gh pr list --repo elsa-workflows/elsa-studio --state open --limit 100 --json number,title,updatedAt,url +gh pr list --repo elsa-workflows/elsa-extensions --state open --limit 100 --json number,title,updatedAt,url +gh release list --repo elsa-workflows/elsa-core --limit 10 +gh release list --repo elsa-workflows/elsa-studio --limit 10 +gh release list --repo elsa-workflows/elsa-extensions --limit 10 +``` + +## Publishing + +When asked to mirror the roadmap to GitHub: + +```bash +gh issue edit 3232 --repo elsa-workflows/elsa-core --body-file ROADMAP.md +``` + +After publishing, verify: + +```bash +gh issue view 3232 --repo elsa-workflows/elsa-core --json title,url,updatedAt +``` + +Final response should summarize changed themes, whether the GitHub issue was updated, and any files left modified. diff --git a/.agents/skills/elsa-roadmap-refresh/agents/openai.yaml b/.agents/skills/elsa-roadmap-refresh/agents/openai.yaml new file mode 100644 index 000000000..dd0db5ea5 --- /dev/null +++ b/.agents/skills/elsa-roadmap-refresh/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Elsa Roadmap Refresh" + short_description: "Refresh the Elsa roadmap from source and GitHub evidence" + default_prompt: "Use $elsa-roadmap-refresh to update ROADMAP.md and mirror it to the public roadmap issue." diff --git a/.specify/feature.json b/.specify/feature.json index 692144c11..1c74f069f 100644 --- a/.specify/feature.json +++ b/.specify/feature.json @@ -1,3 +1,3 @@ { - "feature_directory": "specs/007-secrets-module" + "feature_directory": "specs/010-workflow-json-hardening" } diff --git a/AGENTS.md b/AGENTS.md index 420dc3934..3390d955c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -83,7 +83,7 @@ Before handing off changes, verify the following when applicable: For additional context about technologies to be used, project structure, -shell commands, and other important information, read `specs/007-secrets-module/plan.md`. +shell commands, and other important information, read `specs/010-workflow-json-hardening/plan.md`. ## Active Technologies diff --git a/Directory.Packages.props b/Directory.Packages.props index 7ff006312..22622fee5 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -99,8 +99,10 @@ - - + + + + @@ -153,13 +155,13 @@ - + - - - - - + + + + + diff --git a/Elsa.sln b/Elsa.sln index 469ecff98..2fc20c983 100644 --- a/Elsa.sln +++ b/Elsa.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.7.34003.232 @@ -347,6 +347,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Secrets.UnitTests", "t EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Workflows.Api.UnitTests", "test\unit\Elsa.Workflows.Api.UnitTests\Elsa.Workflows.Api.UnitTests.csproj", "{81CFD2E0-2E5E-4810-ADB8-A08301199166}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Diagnostics.OpenTelemetry", "src\modules\Elsa.Diagnostics.OpenTelemetry\Elsa.Diagnostics.OpenTelemetry.csproj", "{8F4AD54E-8586-4D8C-82E6-69218DD4280F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Diagnostics.OpenTelemetry.UnitTests", "test\unit\Elsa.Diagnostics.OpenTelemetry.UnitTests\Elsa.Diagnostics.OpenTelemetry.UnitTests.csproj", "{60F844CC-6DA6-45EB-BA5E-B480B4E77624}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Diagnostics.OpenTelemetry.IntegrationTests", "test\integration\Elsa.Diagnostics.OpenTelemetry.IntegrationTests\Elsa.Diagnostics.OpenTelemetry.IntegrationTests.csproj", "{B6A62D42-D9AA-47BE-BCBC-FCB866D346F0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1387,6 +1393,42 @@ Global {81CFD2E0-2E5E-4810-ADB8-A08301199166}.Release|x64.Build.0 = Release|Any CPU {81CFD2E0-2E5E-4810-ADB8-A08301199166}.Release|x86.ActiveCfg = Release|Any CPU {81CFD2E0-2E5E-4810-ADB8-A08301199166}.Release|x86.Build.0 = Release|Any CPU + {8F4AD54E-8586-4D8C-82E6-69218DD4280F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8F4AD54E-8586-4D8C-82E6-69218DD4280F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8F4AD54E-8586-4D8C-82E6-69218DD4280F}.Debug|x64.ActiveCfg = Debug|Any CPU + {8F4AD54E-8586-4D8C-82E6-69218DD4280F}.Debug|x64.Build.0 = Debug|Any CPU + {8F4AD54E-8586-4D8C-82E6-69218DD4280F}.Debug|x86.ActiveCfg = Debug|Any CPU + {8F4AD54E-8586-4D8C-82E6-69218DD4280F}.Debug|x86.Build.0 = Debug|Any CPU + {8F4AD54E-8586-4D8C-82E6-69218DD4280F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8F4AD54E-8586-4D8C-82E6-69218DD4280F}.Release|Any CPU.Build.0 = Release|Any CPU + {8F4AD54E-8586-4D8C-82E6-69218DD4280F}.Release|x64.ActiveCfg = Release|Any CPU + {8F4AD54E-8586-4D8C-82E6-69218DD4280F}.Release|x64.Build.0 = Release|Any CPU + {8F4AD54E-8586-4D8C-82E6-69218DD4280F}.Release|x86.ActiveCfg = Release|Any CPU + {8F4AD54E-8586-4D8C-82E6-69218DD4280F}.Release|x86.Build.0 = Release|Any CPU + {60F844CC-6DA6-45EB-BA5E-B480B4E77624}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {60F844CC-6DA6-45EB-BA5E-B480B4E77624}.Debug|Any CPU.Build.0 = Debug|Any CPU + {60F844CC-6DA6-45EB-BA5E-B480B4E77624}.Debug|x64.ActiveCfg = Debug|Any CPU + {60F844CC-6DA6-45EB-BA5E-B480B4E77624}.Debug|x64.Build.0 = Debug|Any CPU + {60F844CC-6DA6-45EB-BA5E-B480B4E77624}.Debug|x86.ActiveCfg = Debug|Any CPU + {60F844CC-6DA6-45EB-BA5E-B480B4E77624}.Debug|x86.Build.0 = Debug|Any CPU + {60F844CC-6DA6-45EB-BA5E-B480B4E77624}.Release|Any CPU.ActiveCfg = Release|Any CPU + {60F844CC-6DA6-45EB-BA5E-B480B4E77624}.Release|Any CPU.Build.0 = Release|Any CPU + {60F844CC-6DA6-45EB-BA5E-B480B4E77624}.Release|x64.ActiveCfg = Release|Any CPU + {60F844CC-6DA6-45EB-BA5E-B480B4E77624}.Release|x64.Build.0 = Release|Any CPU + {60F844CC-6DA6-45EB-BA5E-B480B4E77624}.Release|x86.ActiveCfg = Release|Any CPU + {60F844CC-6DA6-45EB-BA5E-B480B4E77624}.Release|x86.Build.0 = Release|Any CPU + {B6A62D42-D9AA-47BE-BCBC-FCB866D346F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6A62D42-D9AA-47BE-BCBC-FCB866D346F0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6A62D42-D9AA-47BE-BCBC-FCB866D346F0}.Debug|x64.ActiveCfg = Debug|Any CPU + {B6A62D42-D9AA-47BE-BCBC-FCB866D346F0}.Debug|x64.Build.0 = Debug|Any CPU + {B6A62D42-D9AA-47BE-BCBC-FCB866D346F0}.Debug|x86.ActiveCfg = Debug|Any CPU + {B6A62D42-D9AA-47BE-BCBC-FCB866D346F0}.Debug|x86.Build.0 = Debug|Any CPU + {B6A62D42-D9AA-47BE-BCBC-FCB866D346F0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6A62D42-D9AA-47BE-BCBC-FCB866D346F0}.Release|Any CPU.Build.0 = Release|Any CPU + {B6A62D42-D9AA-47BE-BCBC-FCB866D346F0}.Release|x64.ActiveCfg = Release|Any CPU + {B6A62D42-D9AA-47BE-BCBC-FCB866D346F0}.Release|x64.Build.0 = Release|Any CPU + {B6A62D42-D9AA-47BE-BCBC-FCB866D346F0}.Release|x86.ActiveCfg = Release|Any CPU + {B6A62D42-D9AA-47BE-BCBC-FCB866D346F0}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1504,12 +1546,15 @@ Global {A0D906D7-9E4D-4C50-93B4-8720BB0AAFA7} = {78FD90A4-90A5-445F-97F2-74BA835AFA5D} {695814F0-7E8F-469E-9A5A-E46759A4D67C} = {18453B51-25EB-4317-A4B3-B10518252E92} {FB7836E3-1D05-4123-B4FA-B9E722723603} = {1B8D5897-902E-4632-8698-E89CAF3DDF54} + {195FD304-EC3F-4350-93C8-AFE80C4E6896} = {78FD90A4-90A5-445F-97F2-74BA835AFA5D} {D8739449-22DC-42D4-85A4-4BA547B0B458} = {18453B51-25EB-4317-A4B3-B10518252E92} {93E9213A-694D-4AB4-870E-05E44F793133} = {1B8D5897-902E-4632-8698-E89CAF3DDF54} {09B4B78B-FE02-44E2-8667-E182AF921C54} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79} {7D905CEC-B30B-4C99-B5F7-3052D33EC8E9} = {18453B51-25EB-4317-A4B3-B10518252E92} {81CFD2E0-2E5E-4810-ADB8-A08301199166} = {18453B51-25EB-4317-A4B3-B10518252E92} - {195FD304-EC3F-4350-93C8-AFE80C4E6896} = {78FD90A4-90A5-445F-97F2-74BA835AFA5D} + {8F4AD54E-8586-4D8C-82E6-69218DD4280F} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79} + {60F844CC-6DA6-45EB-BA5E-B480B4E77624} = {18453B51-25EB-4317-A4B3-B10518252E92} + {B6A62D42-D9AA-47BE-BCBC-FCB866D346F0} = {1B8D5897-902E-4632-8698-E89CAF3DDF54} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D4B5CEAA-7D70-4FCB-A68E-B03FBE5E0E5E} diff --git a/NuGet.Config b/NuGet.Config index af5965e56..6a0629d8a 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -6,6 +6,7 @@ + @@ -19,5 +20,9 @@ + + + + diff --git a/ROADMAP.md b/ROADMAP.md index c27195307..4470b613d 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,6 +1,6 @@ # Elsa Roadmap -Last refreshed: 2026-05-19 +Last refreshed: 2026-05-29 This roadmap is a product direction document, not a fixed release calendar. Elsa is developed through a mix of core maintainer work, customer-funded work, and community contributions, so sequencing can change when real-world demand changes. The intent is stable: make Elsa the most productive, dependable, and extensible workflow platform for the .NET ecosystem. @@ -38,13 +38,13 @@ Legend: `[x]` shipped foundation, `[~]` partially shipped or needs productizatio - [x] Distributed runtime package - [x] Structured logs - [x] Console logs -- [x] Studio structured-log and console-log foundations +- [x] Studio structured-log, console-log, and OpenTelemetry diagnostics foundations - [~] Durable structured log persistence - [~] Scheduler and message-bus foundations through Quartz, Hangfire, MassTransit, Kafka, and Azure Service Bus -- [ ] OpenTelemetry traces and default workflow metrics +- [~] OpenTelemetry diagnostics backend and default workflow metrics - [ ] Scheduler/message reliability hardening for clustered production workloads - [ ] Production security guide -- [ ] Enterprise deployment checklist +- [ ] Enterprise deployment platform and checklist ### Authoring And Studio @@ -56,8 +56,8 @@ Legend: `[x]` shipped foundation, `[~]` partially shipped or needs productizatio - [~] React Flow, sequence, and state-machine designer foundations - [~] Workflow organization with labels/categories/folders - [~] Workflow progress/timeline surface -- [~] Studio OIDC and identity modules -- [~] Studio diagnostics pages for structured and console logs +- [x] Studio OIDC and identity modules +- [~] Studio diagnostics pages for structured logs, console logs, and OpenTelemetry - [~] Studio alterations module - [ ] Designer reliability/regression hardening - [ ] Input validation and activity version visibility @@ -66,7 +66,7 @@ Legend: `[x]` shipped foundation, `[~]` partially shipped or needs productizatio - [ ] First-class workflow debugging - [ ] Designer extensibility, embedding, and white-label recipes - [ ] Tenant/role-based activity visibility -- [ ] AI-assisted workflow generation +- [~] AI-assisted workflow generation and copilot foundations ### Integrations @@ -77,11 +77,11 @@ Legend: `[x]` shipped foundation, `[~]` partially shipped or needs productizatio - [~] OpenAPI activity/provider foundations - [ ] Connector SDK - [ ] Marketplace/plugin installation -- [ ] Agent provider matrix and MCP/tool lifecycle +- [~] Agent provider matrix, with MCP/tool lifecycle still roadmap - [ ] Dynamic activity generation from OpenAPI, Azure Functions, registered methods, and schemas - [ ] Azure DevOps, Teams, OneDrive, SharePoint, Google Docs, and Google Sheets integration strategy - [ ] SQL authoring quality: Studio drag/drop reliability and IntelliSense -- [ ] Dapper package split and MongoDB secrets parity +- [~] Dapper package split and MongoDB secrets parity - [ ] MassTransit v9 strategy - [ ] Azure Functions / worker-service hosting guidance - [ ] WatchFileSystem and command-line automation activities @@ -93,21 +93,24 @@ Legend: `[x]` shipped foundation, `[~]` partially shipped or needs productizatio These are already present in the codebase and should be treated as foundations for the next roadmap slices: - Multi-targeting for `net8.0`, `net9.0`, and `net10.0` in [`src/Directory.Build.props`](src/Directory.Build.props). +- The `3.7.0` release train shipped across [Core](https://github.com/elsa-workflows/elsa-core/releases/tag/3.7.0), [Studio](https://github.com/elsa-workflows/elsa-studio/releases/tag/3.7.0), and [Extensions](https://github.com/elsa-workflows/elsa-extensions/releases/tag/3.7.0) in May 2026, promoting shell integration, Studio authentication, workflow diagnostics, and extension package metadata into released foundations. - Modular core packages under [`src/modules`](src/modules), with code-first features and CShells shell features documented in [`doc/wiki/module-system.md`](doc/wiki/module-system.md). - A modular server host using CShells and Nuplane package loading in [`src/apps/Elsa.ModularServer.Web`](src/apps/Elsa.ModularServer.Web). - Runtime admin, quiescence, drain, and interrupted recovery infrastructure in [`Elsa.Workflows.Runtime`](src/modules/Elsa.Workflows.Runtime) and runtime admin endpoints in [`Elsa.Workflows.Api`](src/modules/Elsa.Workflows.Api/Endpoints/RuntimeAdmin). - Distributed runtime support in [`Elsa.Workflows.Runtime.Distributed`](src/modules/Elsa.Workflows.Runtime.Distributed). - Structured diagnostics with recent/live capture plus SQLite persistence in [`Elsa.Diagnostics.StructuredLogs`](src/modules/Elsa.Diagnostics.StructuredLogs) and [`Elsa.Diagnostics.StructuredLogs.Persistence.Sqlite`](src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Sqlite). -- Raw stdout/stderr console diagnostics in [`Elsa.Diagnostics.ConsoleLogs`](src/modules/Elsa.Diagnostics.ConsoleLogs). +- Raw stdout/stderr console diagnostics in [`Elsa.Diagnostics.ConsoleLogs`](src/modules/Elsa.Diagnostics.ConsoleLogs), with the post-3.7 console pipeline now carrying workflow and activity execution context through [PR #7536](https://github.com/elsa-workflows/elsa-core/pull/7536). +- Core OpenTelemetry diagnostics are actively in productization through [PR #7537](https://github.com/elsa-workflows/elsa-core/pull/7537), which adds OTLP ingestion, bounded storage, REST APIs, SignalR live updates, collector configuration, security checks, and tests. - State machine core activity support in [`Elsa.Workflows.Core/Activities/StateMachine`](src/modules/Elsa.Workflows.Core/Activities/StateMachine). - ElsaScript DSL and blob storage integration in [`Elsa.Dsl.ElsaScript`](src/modules/Elsa.Dsl.ElsaScript) and [`Elsa.WorkflowProviders.BlobStorage.ElsaScript`](src/modules/Elsa.WorkflowProviders.BlobStorage.ElsaScript). - Activity unit testing helpers and guidance in [`src/common/Elsa.Testing.Shared`](src/common/Elsa.Testing.Shared) and [`doc/qa/test-guidelines.md`](doc/qa/test-guidelines.md). - Label infrastructure in [`Elsa.Labels`](src/modules/Elsa.Labels), which is the likely backend foundation for workflow categories, tags, and folders. - Elsa Studio is already a modular Blazor product shell with workflow authoring, instance browsing, designer modules, diagnostics, authentication, localization, branding, custom elements, and early React wrapper work in [elsa-workflows/elsa-studio](https://github.com/elsa-workflows/elsa-studio). -- Studio `main` includes structured-log and console-log modules, newer React Flow/sequence/state-machine designer work, OIDC/identity infrastructure, custom elements, and an alterations module. +- Studio `3.7.0` shipped the modern authentication framework, Elsa Identity and OIDC modules, activity call-stack visualization, incident count badges, pending-instance filtering, and custom theme/DataPanel extensibility. +- Studio `main` includes structured-log, console-log, and OpenTelemetry diagnostics modules, newer React Flow/sequence/state-machine designer work, OIDC/identity infrastructure, custom elements, and an alterations module. The OpenTelemetry Studio module landed in [elsa-studio#834](https://github.com/elsa-workflows/elsa-studio/pull/834). - Elsa Extensions is an active modular integration repository with 70+ module projects in [elsa-workflows/elsa-extensions](https://github.com/elsa-workflows/elsa-extensions), targeting `net8.0`, `net9.0`, and `net10.0`. - Extensions already provide broad integration foundations: Connections, Secrets, Agents, OpenAPI, SQL/CSV/data tooling, messaging, schedulers, cloud storage, logging, webhooks, persistence providers, and external system activities. -- Recent extension work adds package manifest metadata, Kafka multitenancy/schema triggers, Quartz lifecycle/job cleanup fixes, Dapper bookmark cleanup, and other operational hardening. +- Extensions `3.7.0` adds package manifest metadata, infrastructure attributes, shell features for MassTransit/Quartz/Webhooks, Dapper and MongoDB activity execution-chain lookups, Dapper bookmark queue filtering, Kafka multitenancy/schema-trigger work, Quartz lifecycle/job cleanup fixes, and other operational hardening. The public roadmap issue remains useful history: [elsa-workflows/elsa-core#3232](https://github.com/elsa-workflows/elsa-core/issues/3232). Several items in that issue are now done in code but still open in the issue body, so this file should be considered the current working roadmap. @@ -123,12 +126,14 @@ High-value items: - Treat scheduler and messaging correctness as release-blocking infrastructure. Extensions issues around Quartz clustering and recovery ([elsa-extensions#109](https://github.com/elsa-workflows/elsa-extensions/issues/109), [elsa-extensions#101](https://github.com/elsa-workflows/elsa-extensions/issues/101)), Hangfire duplicate jobs ([elsa-extensions#121](https://github.com/elsa-workflows/elsa-extensions/issues/121)), MassTransit stimulus routing ([elsa-extensions#72](https://github.com/elsa-workflows/elsa-extensions/issues/72)), and Kafka extensibility ([elsa-extensions#134](https://github.com/elsa-workflows/elsa-extensions/issues/134)) all point to the same production theme: clustered workload behavior must be boring, observable, and customizable. - Turn the draft native background execution architecture into an implementation plan. [#7356](https://github.com/elsa-workflows/elsa-core/issues/7356) and [#7313](https://github.com/elsa-workflows/elsa-core/issues/7313) point toward an engine-owned, workflow-aware runtime that can evolve toward an actor-model abstraction without coupling Elsa to Orleans, Proto.Actor, or any single backend. - Treat persistence and migration reliability as a product feature: provider-specific migration validation, large-tenant performance tests, safer defaults, and upgrade notes that cover SQL Server, PostgreSQL, MySQL, SQLite, Oracle, and MongoDB scenarios. +- Promote the Elsa Deployment Platform PRD into scoped implementation work. [#7469](https://github.com/elsa-workflows/elsa-core/issues/7469) defines the right product boundary: declarative environment manifests, immutable deployment artifacts, dry-run validation, deployment history, and GitOps-compatible reconciliation should manage control-plane state without reconciling runtime execution state. - Maintain a security hardening track: document scripting trust boundaries, production-safe Docker posture, OIDC setup, default auth patterns, and secrets redaction. [#7096](https://github.com/elsa-workflows/elsa-core/issues/7096) is a reminder that optional code execution must be explained and guarded clearly. Recommended success measures: - rolling deploys do not leave workflows ambiguous or unrecoverable - every runtime admin action is observable and auditable +- deployments can be previewed, validated, promoted, rolled back, and audited without copying databases or reconciling runtime state - core distributed scenarios have component tests, not only unit coverage - upgrade guides call out migrations, package renames, and production security implications before users hit them @@ -142,7 +147,7 @@ High-value items: - Make designer reliability a visible workstream. Recent Studio issues show expression/input rendering regressions after 3.6 ([elsa-studio#791](https://github.com/elsa-workflows/elsa-studio/issues/791), [elsa-studio#781](https://github.com/elsa-workflows/elsa-studio/issues/781), [elsa-studio#795](https://github.com/elsa-workflows/elsa-studio/issues/795)); these should drive a regression harness for designer rendering, property editors, expression descriptors, drag/drop, and WASM/Server parity. - Make workflow progress visible to application users: a current-state/step API, timeline model, and embeddable progress component. This responds to [discussion #6012](https://github.com/elsa-workflows/elsa-core/discussions/6012) and should reuse execution logs, activity records, call-stack tracking, and real-time workflow updates. - Finish the state machine product surface. The core activity exists, but [#5085](https://github.com/elsa-workflows/elsa-core/issues/5085) should be closed only when JSON serialization, Studio authoring, docs, and examples make state machines approachable. -- Build first-class workflow testing and debugging: test runners for full workflows, breakpoint-like inspection, replay from execution logs where feasible, better failed-activity retry flows, child/descendant workflow instance navigation, and Studio affordances for fault investigation. This expands the activity test helper work that addressed [#3978](https://github.com/elsa-workflows/elsa-core/issues/3978) and matches Studio requests for child workflow visibility ([elsa-studio#152](https://github.com/elsa-workflows/elsa-studio/issues/152)) and breakpoint debugging ([elsa-studio discussion #662](https://github.com/elsa-workflows/elsa-studio/discussions/662)). +- Build first-class workflow testing and debugging: test runners for full workflows, breakpoint-like inspection, replay from execution logs where feasible, better failed-activity retry flows, child/descendant workflow instance navigation, and Studio affordances for fault investigation. The Studio `3.7.0` activity call-stack viewer is a useful foundation, but requests for child workflow visibility ([elsa-studio#152](https://github.com/elsa-workflows/elsa-studio/issues/152)) and breakpoint debugging ([elsa-studio discussion #662](https://github.com/elsa-workflows/elsa-studio/discussions/662)) still need a coherent debugging experience. - Improve Studio authoring fundamentals: input validation ([elsa-studio#15](https://github.com/elsa-workflows/elsa-studio/issues/15)), activity version indicators ([elsa-studio#284](https://github.com/elsa-workflows/elsa-studio/issues/284)), async `/dispatch` instead of blocking `/execute` where appropriate ([elsa-studio#811](https://github.com/elsa-workflows/elsa-studio/issues/811)), designer image export ([elsa-studio#585](https://github.com/elsa-workflows/elsa-studio/issues/585)), and expression evaluation controls ([elsa-studio#643](https://github.com/elsa-workflows/elsa-studio/issues/643)). - Improve designer extensibility, embedding, and white-labeling: custom activity property editors, custom list actions, embeddable designer/viewer recipes, custom elements, React wrapper direction, auth modes, base-path hosting, branding/theme, and clear Blazor/WASM/Server guidance. Community demand appears in [#4743](https://github.com/elsa-workflows/elsa-core/issues/4743), [#6685](https://github.com/elsa-workflows/elsa-core/issues/6685), [discussion #7246](https://github.com/elsa-workflows/elsa-core/discussions/7246), [elsa-studio#137](https://github.com/elsa-workflows/elsa-studio/issues/137), and [elsa-studio discussion #665](https://github.com/elsa-workflows/elsa-studio/discussions/665). - Ship user preference and UI state persistence as a Studio platform feature. [elsa-studio#703](https://github.com/elsa-workflows/elsa-studio/issues/703) already scopes theme, layout, table state, local/session storage, reset behavior, and future server profile storage. @@ -166,10 +171,10 @@ High-value items: - Create an OpenAPI activity provider that turns an OpenAPI document into typed designer activities. This is a recurring ask in [#2961](https://github.com/elsa-workflows/elsa-core/issues/2961) and [#6360](https://github.com/elsa-workflows/elsa-core/issues/6360), and it is the best foundation for a broad connector story. The existing Extensions OpenAPI work should be reconciled with this product goal. - Define a connector SDK before adding many one-off integrations. The SDK should cover authentication, secrets, generated activities, testing, metadata, versioning, packaging, Studio property editors, and manifest-driven installation. - Continue marketplace and plugin infrastructure. The Nuplane modular server, sample package, extension package manifest metadata, and [#7310](https://github.com/elsa-workflows/elsa-core/issues/7310) point to a compelling future where Elsa distributions can install safe custom modules without users maintaining a separate host app. -- Promote Agents to a strategic integration lane: provider matrix, OpenAI and Claude PR resolution, local/OpenRouter/custom endpoints, MCP/tool lifecycle, tool selection in Studio, and auditability. [elsa-extensions#58](https://github.com/elsa-workflows/elsa-extensions/issues/58), [elsa-extensions#98](https://github.com/elsa-workflows/elsa-extensions/pull/98), and [elsa-extensions#63](https://github.com/elsa-workflows/elsa-extensions/pull/63) show both demand and active work. +- Promote Agents to a strategic integration lane: provider matrix, OpenAI and Claude PR resolution, local/OpenRouter/custom endpoints, MCP/tool lifecycle, tool selection in Studio, and auditability. The Extensions source already contains Agents, OpenAI, Azure OpenAI, persistence, API, and Studio modules, while [elsa-extensions#58](https://github.com/elsa-workflows/elsa-extensions/issues/58), [elsa-extensions#98](https://github.com/elsa-workflows/elsa-extensions/pull/98), and [elsa-extensions#63](https://github.com/elsa-workflows/elsa-extensions/pull/63) show the provider matrix and Claude/OpenAI work are still actively moving. - Prioritize enterprise productivity integrations by leverage: Azure DevOps has a concrete implementation path ([elsa-extensions#124](https://github.com/elsa-workflows/elsa-extensions/issues/124), [elsa-extensions#125](https://github.com/elsa-workflows/elsa-extensions/pull/125)); Teams, OneDrive, SharePoint, Google Docs, and Google Sheets should follow a shared connector model rather than separate bespoke designs. - Treat dynamic activity generation as a platform primitive. Azure Functions ([elsa-extensions#39](https://github.com/elsa-workflows/elsa-extensions/issues/39)) and registered-method activities ([elsa-extensions#48](https://github.com/elsa-workflows/elsa-extensions/issues/48)) both point toward schema/method-driven activity generation that can also serve OpenAPI, SDK-generated connectors, and internal enterprise APIs. -- Improve data and automation authoring quality: SQL drag/drop reliability ([elsa-extensions#79](https://github.com/elsa-workflows/elsa-extensions/issues/79)), SQL IntelliSense ([elsa-extensions#88](https://github.com/elsa-workflows/elsa-extensions/issues/88)), Dapper package splitting ([elsa-extensions#131](https://github.com/elsa-workflows/elsa-extensions/issues/131), [elsa-extensions#132](https://github.com/elsa-workflows/elsa-extensions/pull/132)), MongoDB secrets parity ([elsa-extensions#126](https://github.com/elsa-workflows/elsa-extensions/issues/126)), WatchFileSystem ([elsa-extensions#90](https://github.com/elsa-workflows/elsa-extensions/issues/90)), and command-line activities ([elsa-extensions#36](https://github.com/elsa-workflows/elsa-extensions/issues/36)). +- Improve data and automation authoring quality: SQL result typing ([elsa-extensions#153](https://github.com/elsa-workflows/elsa-extensions/issues/153), [elsa-extensions#154](https://github.com/elsa-workflows/elsa-extensions/pull/154)), SQL drag/drop reliability ([elsa-extensions#79](https://github.com/elsa-workflows/elsa-extensions/issues/79)), SQL IntelliSense ([elsa-extensions#88](https://github.com/elsa-workflows/elsa-extensions/issues/88)), Dapper package splitting ([elsa-extensions#131](https://github.com/elsa-workflows/elsa-extensions/issues/131), [elsa-extensions#132](https://github.com/elsa-workflows/elsa-extensions/pull/132)), MongoDB secrets parity ([elsa-extensions#126](https://github.com/elsa-workflows/elsa-extensions/issues/126)), WatchFileSystem ([elsa-extensions#90](https://github.com/elsa-workflows/elsa-extensions/issues/90)), and command-line activities ([elsa-extensions#36](https://github.com/elsa-workflows/elsa-extensions/issues/36)). - Resolve the MassTransit strategy after the v9 licensing change. [discussion #6583](https://github.com/elsa-workflows/elsa-core/discussions/6583) raises a practical ecosystem risk; Elsa should either provide a clean split or reduce dependency weight through a smaller messaging abstraction. - Clarify Azure Functions and worker-service hosting patterns. [discussion #4707](https://github.com/elsa-workflows/elsa-core/discussions/4707) and [discussion #7420](https://github.com/elsa-workflows/elsa-core/discussions/7420) show demand for non-traditional hosts, Windows services, and serverless-adjacent deployments. - Add data movement and streaming workflow primitives. [#4809](https://github.com/elsa-workflows/elsa-core/issues/4809) frames this as datasets, linked services, transforms, and stream-oriented processing inspired by Azure Data Factory and stream analytics. @@ -188,9 +193,9 @@ Recommended success measures: High-value items: -- Finish the diagnostics trilogy: structured logs, console logs, and an explicit OpenTelemetry boundary. Structured and console logs now exist; OpenTelemetry traces/metrics need a current module story because [PR #5810](https://github.com/elsa-workflows/elsa-core/pull/5810) previously introduced a module, [#5988](https://github.com/elsa-workflows/elsa-core/issues/5988) asks for default metrics, and the current repo no longer contains an `Elsa.OpenTelemetry` module. -- Add default workflow semantic metrics: started, resumed, suspended, faulted, completed, active, activity executed/faulted, queue depth, recovery count, drain count, and dispatch latency. Align with OpenTelemetry semantic convention work where possible. -- Build Studio diagnostics pages that are useful under pressure: live console, structured logs, trace/metric links, workflow incident timelines, source health, dropped-event counters, source selection, filters, URL state, export/copy affordances, and direct deep links to workflow instances. +- Finish the diagnostics trilogy: structured logs, console logs, and OpenTelemetry. Structured and console logs now exist; Studio `main` has an OpenTelemetry diagnostics page from [elsa-studio#834](https://github.com/elsa-workflows/elsa-studio/pull/834), and Core has an active backend PR for OTLP ingestion, bounded stores, REST endpoints, SignalR live updates, collector configuration, and tests in [#7537](https://github.com/elsa-workflows/elsa-core/pull/7537). The remaining product work is to merge, release, document, and correlate this with workflow incidents. +- Add default workflow semantic metrics: started, resumed, suspended, faulted, completed, active, activity executed/faulted, queue depth, recovery count, drain count, and dispatch latency. [#5988](https://github.com/elsa-workflows/elsa-core/issues/5988) remains the durable demand signal, while [#7537](https://github.com/elsa-workflows/elsa-core/pull/7537) supplies the first current module boundary. +- Build Studio diagnostics pages that are useful under pressure: live console, structured logs, OpenTelemetry traces/metrics/logs, workflow incident timelines, source health, dropped-event counters, source selection, filters, URL state, export/copy affordances, and direct deep links to workflow instances. - Make execution history easier to reason about: distinguish faulted, interrupted, cancelled, crash-recovered, retried, and operator-modified workflows consistently across API, Studio, logs, and metrics. - Connect diagnostics to workflow navigation: trace/span IDs, log source IDs, child workflow chains, alterations, runtime admin actions, and recovery actions should be correlated instead of presented as isolated tables. @@ -206,7 +211,7 @@ Recommended success measures: High-value items: -- Publish canonical OIDC recipes for Blazor Server, WASM, separate server/studio, and all-in-one hosts. [#7181](https://github.com/elsa-workflows/elsa-core/issues/7181) shows both implementation and documentation demand. +- Publish canonical OIDC recipes for Blazor Server, WASM, separate server/studio, all-in-one hosts, and reverse-proxy sub-path deployments. Studio `3.7.0` shipped the modern authentication modules, [#7181](https://github.com/elsa-workflows/elsa-core/issues/7181) shows Core-side implementation and documentation demand, and [elsa-studio#809](https://github.com/elsa-workflows/elsa-studio/pull/809) shows sub-path redirect URI handling is still being hardened. - Provide a production security guide: API keys, JWT/OIDC, default admin bootstrap, scripting trust levels, C# expression risks, Docker demo boundaries, secret masking, tenant isolation, and permission design. - Expand authorization coverage tests around workflow instances, runtime admin, diagnostics, labels, tenants, and HTTP endpoint activities. - Add Studio governance controls: tenant/role-based activity visibility, permission-aware menus/routes, feature-gated modules, and clear behavior for hidden activities in existing workflow definitions. [elsa-studio#584](https://github.com/elsa-workflows/elsa-studio/issues/584) captures the authoring side of this enterprise need. @@ -226,10 +231,10 @@ Recommended success measures: High-value items: -- Build AI-assisted workflow generation that produces multiple visible activities from intent rather than hiding logic in one script activity. This direction is proposed in [discussion #7367](https://github.com/elsa-workflows/elsa-core/discussions/7367). +- Build AI-assisted workflow generation that produces multiple visible activities from intent rather than hiding logic in one script activity. This direction is proposed in [discussion #7367](https://github.com/elsa-workflows/elsa-core/discussions/7367), and [#7523](https://github.com/elsa-workflows/elsa-core/pull/7523) now provides an active Weaver AI Copilot foundation with AI abstractions, provider/session contracts, chat/tool endpoints, audit events, proposal persistence, EF Core storage, and integration/unit tests. - Provide an Elsa MCP/tooling surface for reading, validating, editing, and explaining workflow JSON/ElsaScript. This would make Elsa a strong fit for AI-enabled .NET development environments. - Align AI authoring with the Extensions Agents work: provider abstractions, MCP tools, OpenAI/Claude/local model support, tool approval, secrets handling, and Studio UX should share contracts instead of creating parallel AI stacks. -- Build a Studio copilot only after the authoring contracts are stable: validation, generated activity metadata, designer APIs, diagnostics links, and test scaffolding should be available before AI generation becomes prominent. [elsa-studio#553](https://github.com/elsa-workflows/elsa-studio/issues/553) has clear community signal and maintainer interest, but it should be an accelerator on top of reliable authoring. +- Build a Studio copilot only after the authoring contracts are stable: validation, generated activity metadata, designer APIs, diagnostics links, and test scaffolding should be available before AI generation becomes prominent. [elsa-studio#553](https://github.com/elsa-workflows/elsa-studio/issues/553) has clear community signal and maintainer interest, while [#7523](https://github.com/elsa-workflows/elsa-core/pull/7523) is still Core/backend-oriented and should not be treated as a complete Studio product surface. - Add "explain this workflow", "find risky activities", "suggest tests", and "generate migration notes" capabilities backed by workflow graph metadata. - Pair AI generation with validation: generated workflows should include test scaffolds, required input/output definitions, secrets handling, and clear review diffs. @@ -245,16 +250,17 @@ Near term: 1. Finish runtime confidence work: graceful shutdown remaining tasks, recovery clarity, distributed runtime regressions, security documentation, and OIDC recipes. 2. Stabilize Studio authoring: designer regression harness, input/property-editor fixes, async dispatch/run UX, state machine Studio/docs completion, and a clear UI framework direction. -3. Make workflow authoring easier to manage at scale: organization, search, progress/timeline APIs, testing docs, and user preference/table-state persistence. -4. Reconcile shipped extension foundations with roadmap status: package manifests, Connections/Secrets, OpenAPI, Agents, schedulers, messaging, and integration maturity labels. +3. Complete the diagnostics trilogy: merge/release the Core OpenTelemetry backend, connect it to the Studio OpenTelemetry page, document collector setup, and correlate traces/logs/metrics with workflow incidents. +4. Make workflow authoring easier to manage at scale: organization, search, progress/timeline APIs, testing docs, and user preference/table-state persistence. +5. Reconcile shipped extension foundations with roadmap status: package manifests, Connections/Secrets, OpenAPI, Agents, schedulers, messaging, and integration maturity labels. Mid term: -1. OpenAPI activity provider plus connector SDK. -2. Extension Platform: generated activities, contribution harnesses, Studio extension recipes, package manifest maturity, and marketplace/plugin installation path built on Nuplane and shell features. -3. OpenTelemetry module boundary, default workflow metrics, and Studio trace/log/incident correlation. +1. Promote [#7469](https://github.com/elsa-workflows/elsa-core/issues/7469) from deployment-platform PRD into an implementation spec covering manifests, immutable artifacts, dry-run validation, deployment history, and API/CLI surfaces. +2. OpenAPI activity provider plus connector SDK. +3. Extension Platform: generated activities, contribution harnesses, Studio extension recipes, package manifest maturity, and marketplace/plugin installation path built on Nuplane and shell features. 4. Workflow debugging, replay-oriented incident analysis, child workflow navigation, and operator recovery UX. -5. Agents provider matrix and MCP/tool lifecycle, with Studio UX that keeps generated workflows inspectable. +5. Weaver AI Copilot productization and Agents provider matrix/MCP lifecycle, with Studio UX that keeps generated workflows inspectable. Longer term: diff --git a/design/video/elsa-readme-video/package-lock.json b/design/video/elsa-readme-video/package-lock.json index 00808f410..4810e9cf9 100644 --- a/design/video/elsa-readme-video/package-lock.json +++ b/design/video/elsa-readme-video/package-lock.json @@ -8,10 +8,10 @@ "name": "elsa-readme-video", "version": "0.1.0", "dependencies": { - "@remotion/cli": "4.0.462", + "@remotion/cli": "4.0.469", "react": "19.2.6", "react-dom": "19.2.6", - "remotion": "4.0.462" + "remotion": "4.0.469" }, "devDependencies": { "@types/react": "19.2.14", @@ -20,18 +20,18 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -660,23 +660,21 @@ } }, "node_modules/@remotion/bundler": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/bundler/-/bundler-4.0.462.tgz", - "integrity": "sha512-GlKjrFkrkl/UgiSTCzMPxRtTnOswOUozo5kk0TmK27tDlF9Mkm6Vyy/Dk5UptPIxDeTi8RIvGWrRRhgVUgzzeQ==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/bundler/-/bundler-4.0.469.tgz", + "integrity": "sha512-vHJD/Ey3aTmjlFJ2m9stA+BK3uoacjNB7dT0hSSFQjuN0X4suNmSgA3lRhxPBcUFrrziy4HRXaiJp5H2y3Yc2Q==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@remotion/media-parser": "4.0.462", - "@remotion/studio": "4.0.462", - "@remotion/studio-shared": "4.0.462", - "@remotion/timeline-utils": "4.0.462", + "@remotion/media-parser": "4.0.469", + "@remotion/studio": "4.0.469", + "@remotion/studio-shared": "4.0.469", + "@remotion/timeline-utils": "4.0.469", "@rspack/core": "1.7.6", "@rspack/plugin-react-refresh": "1.6.1", + "css-loader": "7.1.4", "esbuild": "0.28.0", - "loader-utils": "2.0.4", - "postcss": "8.5.10", - "postcss-value-parser": "4.2.0", "react-refresh": "0.18.0", - "remotion": "4.0.462", + "remotion": "4.0.469", "style-loader": "4.0.0", "webpack": "5.105.0" }, @@ -686,22 +684,22 @@ } }, "node_modules/@remotion/cli": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/cli/-/cli-4.0.462.tgz", - "integrity": "sha512-ZFeXBM2bl1Eku8OroJyCOK+kflMTbJ7HBhUaH8qN3WSyX0dOngBKkNa9DRFbiDJVDGgE0ziG7uiSuU/oB1HPqQ==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/cli/-/cli-4.0.469.tgz", + "integrity": "sha512-dv3hpY0CsjzkwPVXQJcJQHikXLHzupFyJg835rp5zBuqF+i/HmhZM8VZdh4LZDEut3OHJD3vkEgAk35R18Q8iQ==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@remotion/bundler": "4.0.462", - "@remotion/media-utils": "4.0.462", - "@remotion/player": "4.0.462", - "@remotion/renderer": "4.0.462", - "@remotion/studio": "4.0.462", - "@remotion/studio-server": "4.0.462", - "@remotion/studio-shared": "4.0.462", + "@remotion/bundler": "4.0.469", + "@remotion/media-utils": "4.0.469", + "@remotion/player": "4.0.469", + "@remotion/renderer": "4.0.469", + "@remotion/studio": "4.0.469", + "@remotion/studio-server": "4.0.469", + "@remotion/studio-shared": "4.0.469", "dotenv": "17.3.1", "minimist": "1.2.6", "prompts": "2.4.2", - "remotion": "4.0.462" + "remotion": "4.0.469" }, "bin": { "remotion": "remotion-cli.js", @@ -714,9 +712,9 @@ } }, "node_modules/@remotion/compositor-darwin-arm64": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/compositor-darwin-arm64/-/compositor-darwin-arm64-4.0.462.tgz", - "integrity": "sha512-soKDNA0jSppazP9jxbz4OFQRTVS9mIj5w+5EtmcH23gCdnZejjCEO8839YE7nhHi5C7wgqU/sdkwRs3FyfP+tg==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/compositor-darwin-arm64/-/compositor-darwin-arm64-4.0.469.tgz", + "integrity": "sha512-Ke/PljsHgvHIJD7rGlgTGkvmY044abjTUo2QI3Qq368NGzzEHe2USVyqycacKTilHCtcZG1n8CMbofpkXHurcg==", "cpu": [ "arm64" ], @@ -726,9 +724,9 @@ ] }, "node_modules/@remotion/compositor-darwin-x64": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/compositor-darwin-x64/-/compositor-darwin-x64-4.0.462.tgz", - "integrity": "sha512-xAkk7095Ud/Ugs3SP7GERnTwm2sljuZ4K89Gb5Y8tvdObqH70u1TMobzNWPcBOJcYOl7hgfc4dqV9pvMTHo+hw==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/compositor-darwin-x64/-/compositor-darwin-x64-4.0.469.tgz", + "integrity": "sha512-e6usJHMZQN1qUrjLfaVXAHk212W+FMDzDQWJAnxzXDnb+diPpFvzmW8tGdZWTOjU5mBttEJQmS507zHvs2q4uQ==", "cpu": [ "x64" ], @@ -738,9 +736,9 @@ ] }, "node_modules/@remotion/compositor-linux-arm64-gnu": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-arm64-gnu/-/compositor-linux-arm64-gnu-4.0.462.tgz", - "integrity": "sha512-8Qy3lGKQsX/Kuxlji9AENnlpzRSDuG/K5DIe7o73YBitxey539sp1D3Ww0VCrE0uyH4Gj85KiPrT8YEESMcpCA==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-arm64-gnu/-/compositor-linux-arm64-gnu-4.0.469.tgz", + "integrity": "sha512-/N7Bhq024Fw10n6kvx53D8EO3UQOOL6gmq8PJ3o7XORDSANzyYtTogyqHFMJ7LxZ5MLRP1vbdu2kqimBYJA3qw==", "cpu": [ "arm64" ], @@ -753,9 +751,9 @@ ] }, "node_modules/@remotion/compositor-linux-arm64-musl": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-arm64-musl/-/compositor-linux-arm64-musl-4.0.462.tgz", - "integrity": "sha512-dZjq3H8GngDdZs3/cqOdrPKOhW1UhQb99emYNx+G4Mv4kIpqX3sOEGYZNokCDZxR8hiAehI8BqblHk1NGDa0mQ==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-arm64-musl/-/compositor-linux-arm64-musl-4.0.469.tgz", + "integrity": "sha512-kVlqB1SSJ/ihVncgwEh9uKqMhjdtS+6NTuUTpZbVlEx34s8SN7Y7MV0cHHQnx4KiksbFvVABGVjL9a6yiqIuEw==", "cpu": [ "arm64" ], @@ -768,9 +766,9 @@ ] }, "node_modules/@remotion/compositor-linux-x64-gnu": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-x64-gnu/-/compositor-linux-x64-gnu-4.0.462.tgz", - "integrity": "sha512-nfqqBOc81+CnkmoOFhQF0EzqiGK1N5FwrcwrxexJxoQkxpNk4kMRp2CKyaOd6cHEx1hQKKCl/pPiScEez8ZwfA==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-x64-gnu/-/compositor-linux-x64-gnu-4.0.469.tgz", + "integrity": "sha512-lP+Hzujpk3IB41thQEAf3vnK3bhfqjPrxytKqQ4gWxV830mhQ7g3Htgu9oWGYfshdbfWeMjlRF8rEClzcU/xBw==", "cpu": [ "x64" ], @@ -783,9 +781,9 @@ ] }, "node_modules/@remotion/compositor-linux-x64-musl": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-x64-musl/-/compositor-linux-x64-musl-4.0.462.tgz", - "integrity": "sha512-AFNmG/Ll2lP3Hh9E7qjWkTIKaNfxZwQJeke2bWmcOV+tlWJa/mFccNVHnoDP5NpjpYwAHvemCUxmPIV1l2/7lw==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-x64-musl/-/compositor-linux-x64-musl-4.0.469.tgz", + "integrity": "sha512-5NV/W1rmZIQFn4ivYCNyg/YooUxKkd+EX/d+rdt/sidPzQUpySRm81F+pnnuqnVldlHmr6LGl9sNe5DSH9dJtw==", "cpu": [ "x64" ], @@ -798,9 +796,9 @@ ] }, "node_modules/@remotion/compositor-win32-x64-msvc": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/compositor-win32-x64-msvc/-/compositor-win32-x64-msvc-4.0.462.tgz", - "integrity": "sha512-lXjrweVS3cEpfR33TH7so93GKUtx77zfK0iKBkrTcwZw7IIYYIBG8Y7H2M2MTIW3xQDPtuJPhOuVTiUFcocmcw==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/compositor-win32-x64-msvc/-/compositor-win32-x64-msvc-4.0.469.tgz", + "integrity": "sha512-0lEP9HvbCgQa7HxMl804DrE49kmctidNgSNHavVT7O7B4E03uxAt4kaRRy1P7SLeGMJ/1wKIYLfWtvV4sd7HKA==", "cpu": [ "x64" ], @@ -810,25 +808,25 @@ ] }, "node_modules/@remotion/licensing": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/licensing/-/licensing-4.0.462.tgz", - "integrity": "sha512-NbTiGVmqp7NJsLbjJP84jB5oLO92a6TJiq2KckpdpZlekLPbITpKp984rXMZjZgE/B0LkeYkIHRNO75AikFQLQ==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/licensing/-/licensing-4.0.469.tgz", + "integrity": "sha512-ZSM0no+STTcEQAYGyyarXKkpQet18kXgJR59oTmRa0iqS+nN78OMBE4Uj7totpfmhXYV98T4gWgkGHqjDjqcBg==", "license": "MIT" }, "node_modules/@remotion/media-parser": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/media-parser/-/media-parser-4.0.462.tgz", - "integrity": "sha512-wSXZcVhNppSxsw+kDF6Y00YqnTQvw88OU3sM6P2JR6IKzsKq2bSMgm4amqVs1K1hP7m3CAdx4NqG/5H9a9/kzw==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/media-parser/-/media-parser-4.0.469.tgz", + "integrity": "sha512-mBHh2e7YK3CFiDvfXVoFxgxZrg7PtlDnYKCQHmkoqleBP3rpJlYaXeCgHt+mDwSUd0HFxGFdKYlDdXEn0Kh4kQ==", "license": "Remotion License https://remotion.dev/license" }, "node_modules/@remotion/media-utils": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/media-utils/-/media-utils-4.0.462.tgz", - "integrity": "sha512-naC7SVMO979E6kRzXxL3H1IoaNdTucE+7NbYDbt6ixrlsFtenpiRaVH0RlJPmYXmcwss3dvmmabVwrQ7RrMB5Q==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/media-utils/-/media-utils-4.0.469.tgz", + "integrity": "sha512-L1Qk0PR0BQRhuCgBBnPSKi0zVTe2U2vx8Z2GmNgTqaJvNnzyMJ4WyWyMWYegNs68nFKoUJ5yskkI6oPUwrhCmg==", "license": "MIT", "dependencies": { "mediabunny": "1.45.0", - "remotion": "4.0.462" + "remotion": "4.0.469" }, "peerDependencies": { "react": ">=16.8.0", @@ -836,12 +834,12 @@ } }, "node_modules/@remotion/player": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/player/-/player-4.0.462.tgz", - "integrity": "sha512-w/zBCWwLXsoNwsokaPwKxpdv+CBw52FuR3pQZegZvcnKwx1d8bq2P4xBjhCs+o5XP7kiRS0FQIIFYiCmXZXYgw==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/player/-/player-4.0.469.tgz", + "integrity": "sha512-cAnin3JPrJx0mBFT7bcZ9N8xOwXygMIWeM4qHgDONfIwgqouir8gQFPIxRtyAzNubMl8xvLjbPSBbDeusNDAGw==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "remotion": "4.0.462" + "remotion": "4.0.469" }, "peerDependencies": { "react": ">=16.8.0", @@ -849,27 +847,26 @@ } }, "node_modules/@remotion/renderer": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/renderer/-/renderer-4.0.462.tgz", - "integrity": "sha512-qwOsGvtGb3CIpYMrVeO+wTwJN+C3uigT9gKyM0tl24IrPbq8UWqkX1mDJv5pYcWUbCj1mEdeakh7ue9+zgdEgA==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/renderer/-/renderer-4.0.469.tgz", + "integrity": "sha512-9529YcfPbZCQCVhq/eGQaqsuQzAeXClWzq9Eq3vC1UpJrAwsA3DfpDZiwu8IOXVhKqR4uouYJZQagcAahhH9bg==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@remotion/licensing": "4.0.462", - "@remotion/streaming": "4.0.462", + "@remotion/licensing": "4.0.469", + "@remotion/streaming": "4.0.469", "execa": "5.1.1", - "extract-zip": "2.0.1", - "remotion": "4.0.462", + "remotion": "4.0.469", "source-map": "0.8.0-beta.0", - "ws": "8.17.1" + "ws": "8.20.1" }, "optionalDependencies": { - "@remotion/compositor-darwin-arm64": "4.0.462", - "@remotion/compositor-darwin-x64": "4.0.462", - "@remotion/compositor-linux-arm64-gnu": "4.0.462", - "@remotion/compositor-linux-arm64-musl": "4.0.462", - "@remotion/compositor-linux-x64-gnu": "4.0.462", - "@remotion/compositor-linux-x64-musl": "4.0.462", - "@remotion/compositor-win32-x64-msvc": "4.0.462" + "@remotion/compositor-darwin-arm64": "4.0.469", + "@remotion/compositor-darwin-x64": "4.0.469", + "@remotion/compositor-linux-arm64-gnu": "4.0.469", + "@remotion/compositor-linux-arm64-musl": "4.0.469", + "@remotion/compositor-linux-x64-gnu": "4.0.469", + "@remotion/compositor-linux-x64-musl": "4.0.469", + "@remotion/compositor-win32-x64-msvc": "4.0.469" }, "peerDependencies": { "react": ">=16.8.0", @@ -877,29 +874,29 @@ } }, "node_modules/@remotion/streaming": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/streaming/-/streaming-4.0.462.tgz", - "integrity": "sha512-o3+GgxZURUr1wwlTSKg3JRIF/r3ctSMUrMFB3rjxlcXKNW4Z/Izkho2lWmZlONYtZHJVshg6hfS3OxjTK2zwdA==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/streaming/-/streaming-4.0.469.tgz", + "integrity": "sha512-ACYjvcoCxIhVLICgm6zNyxKtXOsRnQ+GocWyY8SdHS2LNpLj/ihRj2xXAdJcuqQI/FaITHIvMiK9kwGAv3J6iw==", "license": "MIT" }, "node_modules/@remotion/studio": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/studio/-/studio-4.0.462.tgz", - "integrity": "sha512-Rl+VhBesr1cCDuFogE2p+oAIF/IVM0fQYZDWWSLHFwF37gb6jLIfEgrrFqgarPwNTAEZwY2qqr2c7J3uooeH1Q==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/studio/-/studio-4.0.469.tgz", + "integrity": "sha512-YMwNokK3XDfhCjZs0J6zj4kcOXlb96YugMMfOY3xBHyVmbKOnSyhNHyZ07E9Kr48p2lorzzS6n6kpFrpOt2FLQ==", "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.31", - "@remotion/media-utils": "4.0.462", - "@remotion/player": "4.0.462", - "@remotion/renderer": "4.0.462", - "@remotion/studio-shared": "4.0.462", - "@remotion/timeline-utils": "4.0.462", - "@remotion/web-renderer": "4.0.462", - "@remotion/zod-types": "4.0.462", + "@remotion/media-utils": "4.0.469", + "@remotion/player": "4.0.469", + "@remotion/renderer": "4.0.469", + "@remotion/studio-shared": "4.0.469", + "@remotion/timeline-utils": "4.0.469", + "@remotion/web-renderer": "4.0.469", + "@remotion/zod-types": "4.0.469", "mediabunny": "1.45.0", "memfs": "3.4.3", "open": "8.4.2", - "remotion": "4.0.462", + "remotion": "4.0.469", "semver": "7.5.3", "zod": "4.3.6" }, @@ -909,54 +906,54 @@ } }, "node_modules/@remotion/studio-server": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/studio-server/-/studio-server-4.0.462.tgz", - "integrity": "sha512-RI4KwdLju6yKO1IDDAtLVy0gelYf+rfLqhpRpRoutFj3X9euajbX2o7Fghfc3Qn6UfAz3VA78U8z4ZO75BAeQg==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/studio-server/-/studio-server-4.0.469.tgz", + "integrity": "sha512-QnkXtHS6exjHXEQbIK8qXN/8c6jAO6FKrK7917+8E/+0Bl8I18K63yX/CxtONcRuj7qOPfq/s0fIpBO2awczbw==", "license": "MIT", "dependencies": { "@babel/parser": "7.24.1", "@babel/types": "7.24.0", - "@remotion/bundler": "4.0.462", - "@remotion/renderer": "4.0.462", - "@remotion/studio-shared": "4.0.462", + "@remotion/bundler": "4.0.469", + "@remotion/renderer": "4.0.469", + "@remotion/studio-shared": "4.0.469", "memfs": "3.4.3", "open": "8.4.2", "prettier": "3.8.1", "recast": "0.23.11", - "remotion": "4.0.462", + "remotion": "4.0.469", "semver": "7.5.3" } }, "node_modules/@remotion/studio-shared": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/studio-shared/-/studio-shared-4.0.462.tgz", - "integrity": "sha512-j8Q5+E4IWqpKWwSanxGI7+WG1rblpyf9Fb65cUoXmGrC28gq+dMqvPo+od2gSd77hfKZ80Po1u45cdP83B9tNA==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/studio-shared/-/studio-shared-4.0.469.tgz", + "integrity": "sha512-JN4jdfaLNYLo/aV5jPt13A7dheRm3MuF27Y9ON0Gs/VZva9G+nHyz89zUqMYWLaXU3gG5Sq9HkFa/lGMWC+2Ow==", "license": "MIT", "dependencies": { - "remotion": "4.0.462" + "remotion": "4.0.469" } }, "node_modules/@remotion/timeline-utils": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/timeline-utils/-/timeline-utils-4.0.462.tgz", - "integrity": "sha512-xC6ErhwO9Jz6oP+0vfJHJVxEl7ZVTbyJOEbz4BzT1h0Wq4f6d9hH7d8VvmrvZ2IQwb1VaqrkR7URvaW+VfJ14A==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/timeline-utils/-/timeline-utils-4.0.469.tgz", + "integrity": "sha512-Jrl0IUdgljfh64SgOxkFvgMX4UY1nYxDp8Hddrk2R8edIcVUJrMoe2+xLlgFoKwyhyZNE4kHNXnrVlUoSI4d5g==", "license": "MIT", "dependencies": { "mediabunny": "1.45.0" } }, "node_modules/@remotion/web-renderer": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/web-renderer/-/web-renderer-4.0.462.tgz", - "integrity": "sha512-Wj2IIACwNaRWGxc79LKs1vzbIEzhvs63u1rnJwvh+EDuHbhMZBCU7wJGVuSKZifNsKb9k999HiSS43d+j1OhpQ==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/web-renderer/-/web-renderer-4.0.469.tgz", + "integrity": "sha512-6Bgx3zLy4AgQiT2ERQCqiBUatNfQhZ4amod6kIy3Xmc8nUw7m2KtzUXZfy7V+Ln3/yo3cRcBa1ehFSRiNbUfCg==", "license": "UNLICENSED", "dependencies": { "@mediabunny/aac-encoder": "1.45.0", "@mediabunny/flac-encoder": "1.45.0", "@mediabunny/mp3-encoder": "1.45.0", - "@remotion/licensing": "4.0.462", + "@remotion/licensing": "4.0.469", "mediabunny": "1.45.0", - "remotion": "4.0.462" + "remotion": "4.0.469" }, "peerDependencies": { "react": ">=18.0.0", @@ -964,12 +961,12 @@ } }, "node_modules/@remotion/zod-types": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/@remotion/zod-types/-/zod-types-4.0.462.tgz", - "integrity": "sha512-q+wgcvD4AVFg17hPvpklZUU1oUt/A/tK1dTNi1o7NyXZmqic3Ko0iZpW01lEe5AsOW7so4XSWgv89Gs+r/R4dQ==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/@remotion/zod-types/-/zod-types-4.0.469.tgz", + "integrity": "sha512-AfWk/Y4vRepXAsQI41lHwjZyxm0KtNjx04EfTdfvKZq5lcTAEvLcpRlVQhGBazuCY4XXbhsNTSANeOpNAJF2yw==", "license": "MIT", "dependencies": { - "remotion": "4.0.462" + "remotion": "4.0.469" }, "peerDependencies": { "zod": "4.3.6" @@ -1240,9 +1237,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.8.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.8.0.tgz", - "integrity": "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==", + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", + "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", "license": "MIT", "dependencies": { "undici-types": ">=7.24.0 <7.24.7" @@ -1268,16 +1265,6 @@ "@types/react": "^19.2.0" } }, - "node_modules/@types/yauzl": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", - "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", - "license": "MIT", - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -1518,9 +1505,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.10.29", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.29.tgz", - "integrity": "sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==", + "version": "2.10.33", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz", + "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -1529,15 +1516,6 @@ "node": ">=6.0.0" } }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/browserslist": { "version": "4.28.2", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", @@ -1571,15 +1549,6 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -1587,9 +1556,9 @@ "license": "MIT" }, "node_modules/caniuse-lite": { - "version": "1.0.30001792", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001792.tgz", - "integrity": "sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==", + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", "funding": [ { "type": "opencollective", @@ -1635,6 +1604,65 @@ "node": ">= 8" } }, + "node_modules/css-loader": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.4.tgz", + "integrity": "sha512-vv3J9tlOl04WjiMvHQI/9tmIrCxVrj6PFbHemBB1iihpeRbi/I4h033eoFIhwxBBqLhI0KYFS7yvynBFhIZfTw==", + "license": "MIT", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.40", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.6.3" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || ^1.0.0 || ^2.0.0-0", + "webpack": "^5.27.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-loader/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", @@ -1642,23 +1670,6 @@ "dev": true, "license": "MIT" }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -1681,33 +1692,15 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.357", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.357.tgz", - "integrity": "sha512-NHlTIQDK8fmVwHwuIzmXYEJ1Ewq3D9wDNc0cWXxDGysP6Pb21giwGNkxiTifyKy/4SoPuN5l6GLP1W9Sv7zB2g==", + "version": "1.5.364", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.364.tgz", + "integrity": "sha512-G/dYE3+AYhyHwzTwg8UbnXf7zqMERYh7l2jJ3QujhFsH8agSYwtnGAR2aZ7f0AakIKJXd5En/Hre4igIUrdlYw==", "license": "ISC" }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/enhanced-resolve": { - "version": "5.21.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.3.tgz", - "integrity": "sha512-QyL119InA+XXEkNLNTPCXPugSvOfhwv0JOlGNzvxs0hZaiHLNvXSpudUWsOlsXGWJh8G6ckCScEkVHfX3kw/2Q==", + "version": "5.22.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.1.tgz", + "integrity": "sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -1870,41 +1863,6 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "license": "BSD-2-Clause", - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/extract-zip/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -1927,15 +1885,6 @@ ], "license": "BSD-3-Clause" }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - } - }, "node_modules/fs-monkey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", @@ -2000,6 +1949,18 @@ "node": ">=10.17.0" } }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -2071,18 +2032,6 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -2105,20 +2054,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "license": "MIT", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, "node_modules/lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -2209,12 +2144,6 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "license": "MIT" }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, "node_modules/nanoid": { "version": "3.3.12", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", @@ -2240,10 +2169,13 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.44", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.44.tgz", - "integrity": "sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==", - "license": "MIT" + "version": "2.0.46", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz", + "integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==", + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/npm-run-path": { "version": "4.0.1", @@ -2257,15 +2189,6 @@ "node": ">=8" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -2307,12 +2230,6 @@ "node": ">=8" } }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "license": "MIT" - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -2320,9 +2237,9 @@ "license": "ISC" }, "node_modules/postcss": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", - "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "funding": [ { "type": "opencollective", @@ -2339,7 +2256,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -2347,6 +2264,78 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "license": "MIT", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "license": "ISC", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", @@ -2381,16 +2370,6 @@ "node": ">= 6" } }, - "node_modules/pump": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", - "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -2456,9 +2435,9 @@ } }, "node_modules/remotion": { - "version": "4.0.462", - "resolved": "https://registry.npmjs.org/remotion/-/remotion-4.0.462.tgz", - "integrity": "sha512-0bcwIiN7H0IcHtcDlfWHE2ho46RF0VmnVN1fAc26uMkonmAMMhqB+1aogfTE8eiYESEzFokh0lRc0t6pI8wzNA==", + "version": "4.0.469", + "resolved": "https://registry.npmjs.org/remotion/-/remotion-4.0.469.tgz", + "integrity": "sha512-wD8LK3bFfcv44gnj8KLS1R1iGI+n0XGtPvdIiIaGfE+CTX3p2FJYKw2Vc5OfyfdVSACLn3r654XW9VteA9cTIQ==", "license": "SEE LICENSE IN LICENSE.md", "peerDependencies": { "react": ">=16.8.0", @@ -2648,9 +2627,9 @@ } }, "node_modules/terser": { - "version": "5.47.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.47.1.tgz", - "integrity": "sha512-tPbLXTI6ohPASb/1YViL428oEHu6/qv1OxqYnfaonVCFHqx4+wCd95pHrQWsL5X4pl90CTyW9piSAsS2L0VoMw==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz", + "integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==", "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -2666,9 +2645,9 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.0.tgz", - "integrity": "sha512-Eum+5ajkaOhf5KbM26osvv21kLD7BaGqQ1UA4Ami4arYwylmGUQTgHFpHDdmJod1q4QXa66p0to/FBKID+J1vA==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.1.tgz", + "integrity": "sha512-201R5j+sJpK8nFWwKVyNfZot8FaJbLZDq5evriVzbV1wDtSXDjRUDRfJzHpAaxFDMEhsZL1QkeqM61wgsS3KaQ==", "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", @@ -2805,6 +2784,12 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, "node_modules/watchpack": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", @@ -2873,9 +2858,9 @@ } }, "node_modules/webpack-sources": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.4.1.tgz", - "integrity": "sha512-eACpxRN02yaawnt+uUNIF7Qje6A9zArxBbcAJjK1PK3S9Ycg5jIuJ8pW4q8EMnwNZCEGltcjkRx1QzOxOkKD8A==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.0.tgz", + "integrity": "sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==", "license": "MIT", "engines": { "node": ">=10.13.0" @@ -2907,16 +2892,10 @@ "node": ">= 8" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", + "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -2940,16 +2919,6 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "license": "ISC" }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, "node_modules/zod": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", diff --git a/design/video/elsa-readme-video/package.json b/design/video/elsa-readme-video/package.json index e7db66a7e..4962c9d07 100644 --- a/design/video/elsa-readme-video/package.json +++ b/design/video/elsa-readme-video/package.json @@ -9,10 +9,10 @@ "still": "remotion still ElsaReadme ../exports/elsa-workflows-readme-poster.png --frame=36" }, "dependencies": { - "@remotion/cli": "4.0.462", + "@remotion/cli": "4.0.469", "react": "19.2.6", "react-dom": "19.2.6", - "remotion": "4.0.462" + "remotion": "4.0.469" }, "devDependencies": { "@types/react": "19.2.14", diff --git a/design/video/exports/elsa-workflows-readme-poster.png b/design/video/exports/elsa-workflows-readme-poster.png index 07bf79484..62a5eaa31 100644 Binary files a/design/video/exports/elsa-workflows-readme-poster.png and b/design/video/exports/elsa-workflows-readme-poster.png differ diff --git a/doc/website/product-website-feature-source.md b/doc/website/product-website-feature-source.md new file mode 100644 index 000000000..aa6ffea8e --- /dev/null +++ b/doc/website/product-website-feature-source.md @@ -0,0 +1,438 @@ +# Elsa Product Website Feature Source + +This document is source material for a product website aimed at developers, architects, and CTOs evaluating workflow engines. It was compiled from: + +- `elsa-core`: `/Users/sipke/Projects/Elsa/elsa-core` +- `elsa-studio`: `/Users/sipke/Projects/Elsa/elsa-studio` +- `elsa-extensions`: `/Users/sipke/Projects/Elsa/elsa-extensions-investigation` (`Elsa.Extensions.sln`) + +Use this as the comprehensive feature inventory. The website should not show every item with equal weight; the final section contains instructions for Lovable AI to select and present the strongest public-facing set. + +## Core Workflow Engine + +### Embeddable .NET Workflow Engine + +Elsa runs inside any .NET application and gives teams a workflow runtime they can embed directly into their own products, services, portals, back-office systems, and integration platforms. Workflows can be hosted in ASP.NET Core, run from worker services, or exposed through Elsa's server-style API surface. This matters to engineering teams that need workflow automation without handing orchestration to a black-box SaaS product. + +### Code-First, Designer-First, and JSON Workflows + +Workflows can be authored in C#, visually in Elsa Studio, or represented as JSON. Developers can keep critical workflows close to source control, product teams can iterate visually, and platforms can import/export workflow definitions through APIs or storage providers. This gives organizations a practical path from developer-owned automation to collaborative workflow operations. + +### Long-Running and Short-Running Workflows + +Elsa supports short-running automations as well as durable, long-running business processes that wait for external events, approvals, timers, or callbacks. The runtime persists workflow state, bookmarks, triggers, execution records, and incidents, allowing processes to pause and resume across application restarts and infrastructure events. + +### Rich Control Flow + +Elsa includes core control-flow activities such as `Sequence`, `If`, `Switch`, `For`, `ForEach`, `While`, `Parallel`, `Fork`, `Break`, `End`, `Finish`, `Complete`, and `Fault`. Teams can model simple linear automations, branching business rules, parallel work, loops, and failure paths without building custom orchestration logic for every process. + +### Flowcharts, Sequences, and State Machines + +Elsa's engine includes flowchart, sequence, and state machine execution models. Flowcharts support visual business-process modeling with joins, forks, switches, and token-based execution semantics. Sequences provide straightforward procedural automation. State machines model named states and trigger-driven transitions for processes that are naturally lifecycle-oriented. + +### Triggers, Bookmarks, and Event-Driven Resumption + +Workflows can start from triggers and resume from bookmarks. This is the foundation for event-driven automation: HTTP requests, timers, messages, webhooks, user actions, or external systems can start or continue the right workflow instance. Bookmarks are indexed by the runtime so waiting workflows can be found and resumed efficiently. + +### Background Dispatch and Runtime Workers + +The workflow runtime includes background dispatch for workflows, stimuli, tasks, and activities. This allows requests to hand off work and return while Elsa continues processing asynchronously. It also supports patterns where one workflow dispatches another workflow without coupling the caller to immediate execution. + +### Transactional Dispatch Outbox + +Elsa can use a transactional outbox for workflow dispatches created from inside a running workflow. The outbox prevents silent loss when a process crashes between persisting workflow state and enqueueing a dispatch command. Delivery is at-least-once, with idempotency support for child workflow dispatches. + +### Graceful Shutdown and Recovery + +The runtime includes node-local quiescence, drain orchestration, ingress-source pause/resume behavior, and interrupted workflow recovery. This gives operators a controlled way to stop servers without accepting new work mid-drain, and it helps recover work that was interrupted by shutdowns or crashes. + +### Runtime Administration APIs + +Elsa exposes runtime administration endpoints for status, pause, resume, and force-drain operations. Operators can inspect and control workflow runtime state through API-driven automation rather than relying only on process-level controls. + +### Dead-Lettered Bookmark Queue Management + +Bookmark queue items that expire or exceed delivery attempts can be moved to a dead-letter store. APIs allow operators to inspect, replay, and delete dead-lettered items. This is valuable for production workflows where failed event delivery should be visible and recoverable. + +### Workflow Versioning and Migration + +Elsa supports workflow definition versioning and API-driven migration. Teams can evolve workflows over time, publish new versions, and manage compatibility between definitions and running instances. + +### Workflow Management APIs + +Elsa has API surfaces for definitions, instances, execution journals, activity executions, runtime administration, triggers, bookmarks, and related workflow management concerns. This allows workflow capabilities to be embedded into custom platforms and integrated with existing developer or operator tooling. + +### Custom Activities + +Developers can add first-party or product-specific activities with strongly typed inputs and outputs, descriptors, UI hints, and designer integration. This is the extension point that turns Elsa from a generic workflow engine into a domain automation platform for a specific business. + +### Activities as Composable Building Blocks + +Elsa models workflow work as activities. Activities can be composed into higher-level workflows, and workflows themselves can be exposed as callable units. This supports reuse and standardization across teams. + +### Dynamic Activity Handling + +Elsa includes dynamic and missing-activity handling, allowing workflow definitions and designer/API surfaces to evolve while maintaining controlled behavior when activity types are not available. + +### Expressions and Scripting + +Elsa supports dynamic expressions through C#, JavaScript, Python, and Liquid expression modules. Activities can evaluate runtime data, inputs, variables, outputs, workflow context, and external values without forcing every transformation into compiled code. + +### Workflow Inputs, Outputs, Variables, and Correlation + +Elsa includes typed input/output models, variables, workflow input, activity outputs, correlation, and runtime state capture. This gives workflows structured data flow and allows external systems to correlate events with the right workflow instance. + +### Persistence-Agnostic Architecture + +Elsa is persistence-agnostic and includes persistence packages for EF Core providers such as SQLite, SQL Server, PostgreSQL, MySQL, and Oracle. Extension packages also add Dapper and MongoDB persistence options. This lets teams choose infrastructure that fits existing operational standards. + +### Multi-Tenancy and Identity + +Elsa includes identity, authorization, tenant support, and tenant-aware runtime behavior. This is important for SaaS platforms and internal platforms where different teams, customers, or environments need isolated workflow definitions, instances, and permissions. + +### Secrets Management + +Elsa includes a secrets module design with in-memory, configuration-backed, and encrypted Elsa-managed stores. Secrets are intended for use by activities and integrations that need credentials without exposing sensitive values in workflow definitions. + +### Labels, Key Values, SAS Tokens, and Supporting Infrastructure + +Elsa includes supporting modules such as labels, key-value storage, SAS tokens, caching, mediator infrastructure, and feature/module composition. These are less visible as standalone marketing features but help developers build complete workflow-enabled products. + +## Operations and Observability + +### Workflow Execution Journal + +Elsa stores workflow and activity execution records that can be exposed through APIs and Studio. Operators and developers can inspect what ran, what failed, and how a workflow reached its current state. + +### Structured Log Capture + +`Elsa.Diagnostics.StructuredLogs` captures semantic `ILogger` events from Elsa hosts, redacts sensitive data, stores recent records, exposes REST query endpoints, and streams live events to Studio over SignalR. Records include rendered messages, templates, properties, scopes, exceptions, source metadata, trace/span IDs, workflow context, tenant, and correlation fields. + +### Durable Structured Log Persistence + +Structured logs default to a bounded in-memory store, with relational/SQLite persistence available for durable storage. The design includes bounded write queues, batch writes, retention services, storage diagnostics, and dropped-write reporting. + +### Console Log Streaming + +`Elsa.Diagnostics.ConsoleLogs` captures raw stdout and stderr, preserves the original console output destination, redacts content before buffering or streaming, and exposes recent/live console lines through REST and SignalR. This helps operators diagnose container or process-level output without leaving the workflow management experience. + +### OpenTelemetry Workflow Diagnostics + +The extensions repository includes `Elsa.OpenTelemetry`, and Studio includes an OpenTelemetry diagnostics module. The intent is workflow-aware trace, metric, and log exploration where Core remains responsible for ingestion, redaction, storage, permissions, and API contracts while Studio presents normalized diagnostics views. + +### Configurable Workflow Logging Framework + +The extensions repository includes a logging framework with configurable sinks such as console and Serilog, appsettings-based configuration, custom sink factories, and a `Log` activity for emitting structured log entries from workflows. + +### Source and Storage Diagnostics + +Diagnostics modules track source metadata, source health, storage pressure, dropped durable writes, dropped console lines, and live subscription state. These details are useful in clustered or high-volume environments where observability itself needs operational guardrails. + +## Elsa Studio + +### Modular Workflow Management UI + +Elsa Studio is a modular Blazor application framework built with MudBlazor for managing workflows and related entities. It can run as Blazor Server, Blazor WebAssembly, hosted WebAssembly, or custom elements depending on host requirements. + +### Visual Workflow Designer + +Studio provides a drag-and-drop workflow designer for authoring workflows visually. It integrates with Elsa activity descriptors and UI hints so custom activities can appear in the designer alongside built-in activities. + +### Workflow Definition and Instance Management + +Studio includes workflow modules for managing definitions, viewing workflow state, and working with execution/runtime data exposed by the backend. This turns the engine from a library into an operator-facing workflow platform. + +### Real-Time Workflow and Diagnostics Updates + +Studio uses SignalR-backed clients for live updates such as structured logs and console logs. Authentication providers can configure SignalR connections consistently, allowing live operational views to work with JWT, Elsa Identity, or OpenID Connect setups. + +### Structured Logs Viewer + +Studio's structured log viewer loads recent semantic logs, subscribes to live updates, supports source selection, filtering, pause/reconnect/clear behaviors, and exposes detailed log inspection with properties, scopes, exceptions, trace/span fields, tenant, workflow, correlation, and raw JSON. + +### Console Logs Viewer + +Studio includes a diagnostics console page for raw stdout/stderr streaming. Navigation is feature-gated by backend capability and permission, with unavailable and unauthorized states handled in the UI. + +### OpenTelemetry Diagnostics Viewer + +Studio includes a diagnostics OpenTelemetry shell at `/diagnostics/opentelemetry`, with expected views for resource search, trace search/detail, metrics, OTLP logs, storage diagnostics, and collector configuration. + +### Authentication Options + +Studio supports Elsa Identity and OpenID Connect authentication modules across Blazor Server and WebAssembly hosting models. The architecture includes token providers, automatic refresh, backend API token acquisition, SignalR authentication configuration, and custom unauthorized UI rendering. + +### Localization + +Studio includes localization modules for Blazor Server and WebAssembly. Applications can register localization providers, configure supported cultures, and translate the Studio UI for international teams. + +### Extensible Studio Modules + +Studio modules include dashboard, workflows, designer, labels, environments, security, UI hints, diagnostics, localization, authentication, secrets, workflow contexts, and agents. The modular architecture lets product teams compose the Studio experience that fits their platform. + +### Performance-Oriented Designer + +Recent designer work includes batched activity size calculation, activity size caching, and conditional size updates to improve large workflow loading. This matters for teams building complex workflows with many activities. + +### React Wrapper and Custom Embedding + +Studio includes wrapper projects and host variants that support embedding Elsa workflow design experiences into different frontends, including React-oriented integration samples. + +## Built-In Core Capabilities and Activities + +### HTTP Workflows + +Elsa includes HTTP activities for exposing endpoints, sending HTTP requests, downloading HTTP files, and writing HTTP responses or file responses. This makes it natural to build API-triggered workflows, webhook receivers, integration endpoints, and workflow-backed HTTP services. + +### Scheduling and Timers + +Scheduling activities include cron, delay, start-at, and timer behavior. Workflows can run on schedules, pause until a specific time, or wait for durations without custom background job code. + +### Alterations + +Elsa includes alteration modules for applying operational changes to workflow instances. Extensions add a MassTransit-backed alteration background runner for broker-backed, more resilient background processing. + +### Resilience + +Elsa includes resilience modules for workflow execution and activity behavior. These support more robust process automation in failure-prone distributed systems. + +### Workflow Providers + +Elsa includes workflow providers for loading definitions from blob storage and ElsaScript sources. This allows teams to source workflows from external storage rather than only from the management database. + +### ElsaScript DSL + +The ElsaScript DSL module provides a workflow definition scripting format, useful for teams that want text-based workflow authoring and source-controlled definitions. + +## Extensions Ecosystem + +### AI Agents and Multi-Agent Workflows + +The extensions repository includes an Elsa Agents module built on Microsoft's Agent Framework/Semantic Kernel Agents. It supports configuration-based agents, code-first agents, multi-agent workflows, tool calling, persistent conversations/state, REST APIs, persistence packages, OpenAI and Azure OpenAI providers, workflow activities, and Studio UI. + +### Connections Framework + +The extensions repository includes connection modules for registering, describing, and applying connection information to activities. This is a foundation for reusable, centrally managed integration credentials and connection settings. + +### SQL Automation + +The SQL extension provides `SqlQuery`, `SqlCommand`, and `SqlSingleValue` activities, with providers for MySQL, PostgreSQL, SQLite, and SQL Server. It supports parameterization of workflow inputs, outputs, variables, activity context, execution context, workflow properties, POCOs, dictionaries, arrays, lists, and JSON objects, plus SQL syntax highlighting in Studio. + +### CSV Processing + +The CSV extension provides a `ReadCsv` activity that can read byte arrays, streams, strings, URLs, and uploaded files. It supports delimiters, header detection, dictionary output, and optional strongly typed mapping through CsvHelper. + +### Email Automation + +The extensions repository includes an email module with a `SendEmail` activity. This is a common workflow primitive for notifications, approvals, and operational alerts. + +### Slack Automation + +The Slack extension includes activities for channels, messages, reminders, reactions, stars, files, users, search, and event triggers. Workflows can create/update/delete messages, pin/unpin messages, upload files, manage reminders, list/search users and channels, and react to Slack events. + +### GitHub DevOps Automation + +The GitHub extension includes activities for issues, comments, labels, pull requests, repositories, users, organizations, milestones, releases, gists, branch search, GraphQL queries, and webhook-style triggers for issues, pull requests, and branches. Tokens should be stored securely through Elsa secrets. + +### Service Bus and Messaging + +Extensions include Azure Service Bus, Kafka, and MassTransit packages. Activities can send/publish/produce messages and react to received messages, enabling event-driven workflow automation across common messaging infrastructure. + +### Distributed Runtime with Proto.Actor + +The extensions repository includes actor-based runtime packages, including Proto.Actor-backed workflow runtime and actor modules. This extends Elsa's throughput and distributed execution story beyond the base runtime. + +### Distributed Caching + +Extensions include distributed caching modules over MassTransit and Proto.Actor. These support clustered scenarios where local in-memory assumptions are not enough. + +### Scheduling Backends + +Extensions include Hangfire and Quartz scheduling packages, with Quartz EF Core providers for MySQL, PostgreSQL, SQL Server, and SQLite. This lets teams use mature scheduling infrastructure behind Elsa's workflow scheduling concepts. + +### Persistence Extensions + +Extensions add persistence options such as Dapper, MongoDB, and Elasticsearch. These broaden deployment choices for organizations that standardize on specific storage technologies. + +### File and Blob Storage + +Extensions include Azure Storage and local file storage activities such as upload blob, save file, and open file. Workflows can move files through storage systems as part of business processes. + +### HTTP OpenAPI and Webhooks + +Extensions include OpenAPI and webhook modules for HTTP workflows. These help expose, document, and consume HTTP-driven workflow integration surfaces. + +### Compression and I/O + +Extensions include I/O and compression modules, including ZIP archive creation. These are useful in document, file transfer, and batch processing workflows. + +### Telnyx Telephony Automation + +The Telnyx extension includes call-control activities and webhook triggers such as answer call, hang up, dial, bridge calls, speak text, gather DTMF input, get call status, and react to call hangup or general webhook events. + +### Orchard Core Integration + +The extensions repository includes Orchard Core integration modules, useful for teams building CMS-backed or modular application platforms that also need workflow automation. + +### Retention + +The retention extension includes cleanup strategies and collectors for workflow-related records. This supports operational lifecycle management for workflow data. + +### Workflow Contexts + +Workflow context modules let activities set and use contextual parameters associated with workflow context providers. Studio modules add UI support for workflow context activity settings. + +### Drop-Ins + +Drop-in modules suggest a packaging and extension mechanism for pluggable capabilities. These are relevant to teams building modular workflow platforms. + +### Planned and Roadmap Extensions + +The extensions README lists planned or in-development integrations for Telegram, Discord, Microsoft Teams, Gmail, Outlook, Google Calendar, Microsoft Calendar, Google Drive, OneDrive, Azure Storage, Dropbox, Azure DevOps, GitLab, Jenkins, Datadog, cloud functions, CRM systems, payment providers, AI providers, video platforms, and industrial protocols such as OPC UA, Modbus, and MQTT Sparkplug. These should be presented carefully as ecosystem direction unless confirmed released. + +## Architectural Selling Points + +### Modular Feature System + +Elsa uses explicit feature/module registration, dependency declarations, and extension methods. Teams can add only the capabilities they need, keep hosts lean, and build their own modules using the same conventions as first-party packages. + +### Provider-Neutral Boundaries + +Many Elsa capabilities are expressed behind provider contracts: persistence, structured logs, scheduling, workflow providers, SQL clients, authentication, storage, logging sinks, and diagnostics. This gives architects flexibility to standardize on their own infrastructure. + +### API-First and Studio-Ready + +Core capabilities are exposed through APIs and then surfaced in Studio. This means teams can automate through APIs, use Studio as an operator interface, or build their own UI on top of the same contracts. + +### Production Operations Mindset + +The runtime includes operational concepts such as graceful shutdown, recovery scanning, dead-letter queues, storage diagnostics, redaction, bounded buffers, authorization, tenant-aware behavior, and runtime admin endpoints. These are the details architects and CTOs look for when evaluating production fit. + +### Developer Extensibility + +Elsa is designed for developers to extend: custom activities, expression providers, API endpoints, stores, workflow providers, runtime ingress sources, Studio modules, authentication providers, log sinks, SQL clients, agent providers, and integration modules all have clear extension paths. + +### Open Source and Ecosystem Friendly + +Elsa is distributed through NuGet packages, Docker images, GitHub repositories, and community channels. The ecosystem includes Core, Studio, Extensions, Templates, package catalogs, and professional support options. + +## Recommended Website Feature Selection + +For the public product website, do not display all features as a flat checklist. Select the most compelling features for evaluators: + +1. Visual workflow designer plus embeddable .NET runtime. +2. Code-first, visual, and JSON authoring. +3. Long-running durable workflows with triggers and bookmarks. +4. Rich control flow, including flowcharts, sequences, state machines, and parallel execution. +5. API-first workflow management and runtime administration. +6. Persistence choices and production-ready storage boundaries. +7. Observability: execution journal, structured logs, console logs, OpenTelemetry direction. +8. Security and platform fit: identity, authorization, multi-tenancy, secrets. +9. Extensibility: custom activities, modules, expression providers, Studio modules. +10. Integration ecosystem: HTTP, scheduling, SQL, Slack, GitHub, messaging, files, AI agents. +11. Operational readiness: graceful shutdown, recovery, dead-letter handling, durable dispatch outbox. +12. Studio as a modular operations console, not only a designer. + +## Suggested Public Website Copy + +### Hero + +**Title:** Workflow automation for .NET teams + +**Description:** Elsa is an open-source workflow engine and visual workflow platform for building long-running, event-driven, and integration-heavy processes inside your own .NET applications. + +### Feature: Build Workflows Your Way + +**Title:** Code-first, visual, or JSON workflows + +**Description:** Define workflows in C#, design them visually in Elsa Studio, or store them as JSON for API-driven platforms. Developers can keep critical automation close to source control while business and operations teams collaborate through a visual designer. + +### Feature: Durable Event-Driven Runtime + +**Title:** Long-running workflows that wait, resume, and recover + +**Description:** Model processes that pause for timers, webhooks, approvals, messages, and external events. Elsa persists workflow state, indexes triggers and bookmarks, and resumes the right instance when the next signal arrives. + +### Feature: Visual Studio Experience + +**Title:** A modular Studio for designers and operators + +**Description:** Elsa Studio provides a Blazor-based workflow designer, management UI, diagnostics views, authentication modules, localization, and extensible modules for custom platform experiences. + +### Feature: Integration-Ready + +**Title:** Connect workflows to real systems + +**Description:** Use built-in and extension activities for HTTP, scheduling, SQL, CSV, email, Slack, GitHub, Azure Service Bus, Kafka, files, storage, telephony, and AI agents. Add custom activities when your domain needs first-class workflow building blocks. + +### Feature: Production Operations + +**Title:** Built for production workflow operations + +**Description:** Elsa includes runtime administration, execution journals, graceful shutdown, recovery scanning, dead-letter handling, structured log capture, console streaming, redaction, permissions, and storage diagnostics. + +### Feature: Architecture Fit + +**Title:** Modular, provider-neutral, and extensible + +**Description:** Compose only the features you need, plug in your persistence and infrastructure choices, and extend the platform with custom modules, activities, expression providers, APIs, authentication providers, and Studio screens. + +### Feature: Observability + +**Title:** See what workflows are doing + +**Description:** Inspect workflow execution history, activity records, structured logs, raw console output, source metadata, trace and span correlation, workflow context, tenant, and correlation fields from API and Studio diagnostics views. + +### Feature: Security and Multi-Tenancy + +**Title:** Designed for secure platforms + +**Description:** Elsa includes identity, authorization, tenant-aware behavior, secrets management, authenticated SignalR diagnostics, and permission-gated APIs for teams building SaaS, internal platforms, and regulated automation systems. + +### Feature: AI Workflow Orchestration + +**Title:** Orchestrate agents inside workflows + +**Description:** Elsa Agents brings configuration-based and code-first AI agents, multi-agent workflows, tool calling, stateful conversations, OpenAI and Azure OpenAI providers, APIs, persistence, and Studio integration into the workflow model. + +## Lovable AI Instructions + +Use the source inventory above to design a product website section for Elsa Workflows. The target audience is developers, software architects, engineering managers, and CTOs evaluating workflow engines for .NET platforms. + +Prioritize clarity, technical credibility, and enterprise-readiness over hype. Select the most interesting features rather than displaying the complete inventory. The site should make Elsa feel like a serious embeddable workflow platform with a strong visual designer, production runtime, and integration ecosystem. + +Recommended structure: + +1. Hero: "Workflow automation for .NET teams" with a concise description about open-source, embeddable, event-driven workflow automation. +2. Primary feature grid: 6-8 cards covering authoring flexibility, durable runtime, visual Studio, integrations, operations, observability, security, and extensibility. +3. Architecture band: explain modular/provider-neutral design, custom activities, APIs, and persistence choices. +4. Integrations band: show categories rather than a huge checklist. Use "HTTP & APIs", "Scheduling", "Databases", "Messaging", "DevOps", "Communication", "Files & Storage", and "AI Agents". +5. Operations band: highlight graceful shutdown, recovery, dead-letter queues, runtime admin, logs, and diagnostics. +6. CTA: invite visitors to try the Docker image, explore docs, or view GitHub. + +Use these exact card titles unless the layout requires shorter labels: + +- Build Workflows Your Way +- Durable Event-Driven Runtime +- Visual Workflow Studio +- Integration-Ready Automation +- Production Workflow Operations +- Observable by Design +- Secure Multi-Tenant Platform +- Extensible by Developers + +Use concise card descriptions derived from the suggested public copy. Avoid listing unreleased/planned extensions as if they are shipped. If planned ecosystem items are mentioned, label them as roadmap or ecosystem direction. + +Visual direction: + +- Use product screenshots or workflow/designer imagery prominently. +- Keep the design technical, polished, and readable. +- Avoid vague abstract SaaS imagery. +- Favor architecture diagrams, workflow nodes, log/detail panels, integration icons, and code snippets. +- Make the first viewport communicate that Elsa is both a workflow engine and a visual workflow platform. + +Tone: + +- Direct, practical, developer-first. +- Avoid exaggerated claims such as "effortless", "revolutionary", or "no-code magic". +- Emphasize control, extensibility, operational readiness, and .NET-native integration. diff --git a/doc/wiki/opentelemetry-workflows.md b/doc/wiki/opentelemetry-workflows.md index f41449514..3896934cf 100644 --- a/doc/wiki/opentelemetry-workflows.md +++ b/doc/wiki/opentelemetry-workflows.md @@ -6,8 +6,12 @@ To collect workflow traces, configure OpenTelemetry to listen to the `Elsa.Workf ```csharp services.AddOpenTelemetry() - .WithTracing(builder => builder.AddSource("Elsa.Workflows")) - .WithMetrics(builder => builder.AddMeter("Elsa.Workflows")); + .WithTracing(builder => builder + .AddSource("Elsa.Workflows") + .AddOtlpExporter()) + .WithMetrics(builder => builder + .AddMeter("Elsa.Workflows") + .AddOtlpExporter()); ``` If you previously enabled workflow tracing through the `Elsa.OpenTelemetry` extension package, avoid enabling both the extension tracing middleware and the first-party workflow spans for the same host unless duplicate workflow and activity spans are acceptable. Both integrations publish to the `Elsa.Workflows` activity source so existing collectors can keep the same source configuration. @@ -30,3 +34,53 @@ The `Elsa.Workflows` meter emits: - `elsa.activity.duration` in seconds Metric tags use the same low-cardinality workflow and activity metadata as the spans where practical. The started counter omits execution status tags because it records the pre-execution boundary; completed and faulted counters include terminal workflow status tags. + +## Elsa Diagnostics Collector + +The `Elsa.Diagnostics.OpenTelemetry` module can collect OTLP HTTP/protobuf telemetry for local diagnostics and Studio visualization. The default ingestion routes are: + +- `/elsa/otlp/v1/traces` +- `/elsa/otlp/v1/metrics` +- `/elsa/otlp/v1/logs` + +Use the collector for development and focused troubleshooting. Production deployments should usually export to an external OpenTelemetry Collector or observability backend unless Elsa collector capacity, retention, and ingress security are deliberately configured for that environment. + +### .NET Setup + +Configure the .NET OpenTelemetry SDK to collect Elsa workflow instrumentation and export via OTLP: + +```csharp +services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddSource("Elsa.Workflows") + .AddOtlpExporter()) + .WithMetrics(builder => builder + .AddMeter("Elsa.Workflows") + .AddOtlpExporter()); +``` + +Then configure standard OTEL environment variables for the process: + +```bash +OTEL_SERVICE_NAME=elsa-server +OTEL_RESOURCE_ATTRIBUTES=service.instance.id=local-dev +OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:5000/elsa/otlp/v1 +OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf +OTEL_BSP_SCHEDULE_DELAY=1000 +OTEL_METRIC_EXPORT_INTERVAL=1000 +``` + +If the collector is exposed beyond loopback, also configure the required API key header. The header name is returned by the collector configuration API; do not expose the secret value through Studio or documentation. + +### Polyglot Setup + +Non-.NET services can use the same standard OTEL variables: + +```bash +OTEL_SERVICE_NAME=worker +OTEL_RESOURCE_ATTRIBUTES=service.instance.id=worker-1 +OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:5000/elsa/otlp/v1 +OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf +``` + +Use each language SDK's OTLP exporter package. Studio identifies resources by `service.name` and `service.instance.id` when those attributes are present. diff --git a/doc/wiki/workflow-core.md b/doc/wiki/workflow-core.md index 83707c568..c82a48106 100644 --- a/doc/wiki/workflow-core.md +++ b/doc/wiki/workflow-core.md @@ -148,6 +148,14 @@ Core serializers live under [Serialization](../../src/modules/Elsa.Workflows.Cor Custom constructor and additional converter configurators are registered by `WorkflowsFeature`. +### Workflow JSON Type Identifiers + +Workflow JSON type resolution uses the shared `ISerializationTypeRegistry` from `Elsa.Common.Serialization`, not expression type aliases. Register workflow-serializable payload types through `SerializationTypeOptions`; keep `ExpressionOptions` for expression/type metadata only. + +New workflow JSON writes preferred aliases when a type is registered. Compatibility reads also accept explicitly registered legacy names, including selected CLR names from older persisted workflow JSON. Unknown CLR names are rejected rather than loaded dynamically. Polymorphic object reads also reject abstract, interface, open generic, and unsupported collection targets unless the resolver can map a known collection interface to a concrete collection type. + +Public API payloads that expose workflow JSON type identifiers should emit values from `ISerializationTypeRegistry`. For example, incident strategy descriptors return the alias that workflow JSON accepts, while registered legacy CLR names remain readable during the compatibility window. + ## When To Change This Layer Change workflow core only when you are changing engine semantics, activity contracts, execution state, serialization, core activity behavior, or flowchart behavior. If the change is about persisted definitions, API DTOs, background dispatch, or a module-specific transport, start in management, API, runtime, or the extension module instead. diff --git a/docker/ElsaServer-Datadog.Dockerfile b/docker/ElsaServer-Datadog.Dockerfile index 9305f71e8..13c6f966d 100644 --- a/docker/ElsaServer-Datadog.Dockerfile +++ b/docker/ElsaServer-Datadog.Dockerfile @@ -13,7 +13,7 @@ COPY *.props ./ RUN dotnet restore "./src/apps/Elsa.Server.Web/Elsa.Server.Web.csproj" # Build and publish (UseAppHost=false creates platform independent binaries). -WORKDIR /source/src/bundles/Elsa.Server.Web +WORKDIR /source/src/apps/Elsa.Server.Web RUN dotnet build "Elsa.Server.Web.csproj" -c Release -o /app/build RUN dotnet publish "Elsa.Server.Web.csproj" -c Release -o /app/publish /p:UseAppHost=false --no-restore -f net10.0 @@ -27,20 +27,21 @@ RUN apt-get update \ && apt-get install -y --no-install-recommends \ ca-certificates \ curl \ - libpython3.11 \ - python3.11 \ - python3.11-dev \ + libpython3-dev \ + python3 \ + python3-dev \ python3-pip \ unzip \ wget \ && update-ca-certificates \ + && ln -s "$(find /usr/lib -name 'libpython3*.so' -print -quit)" /usr/local/lib/libpython3.so \ && rm -rf /var/lib/apt/lists/* COPY docker/entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh # Set PYTHONNET_PYDLL environment variable -ENV PYTHONNET_PYDLL=/usr/lib/aarch64-linux-gnu/libpython3.11.so +ENV PYTHONNET_PYDLL=/usr/local/lib/libpython3.so # Set environment variables for OpenTelemetry Auto-Instrumentation ENV OTEL_DOTNET_AUTO_HOME=/otel \ diff --git a/docker/ElsaServer.Dockerfile b/docker/ElsaServer.Dockerfile index c194e4253..30d51c454 100644 --- a/docker/ElsaServer.Dockerfile +++ b/docker/ElsaServer.Dockerfile @@ -23,18 +23,19 @@ COPY --from=build /app/publish ./ RUN apt-get update \ && apt-get install -y --no-install-recommends \ ca-certificates \ - libpython3.11 \ - python3.11 \ - python3.11-dev \ + libpython3-dev \ + python3 \ + python3-dev \ python3-pip \ && update-ca-certificates \ + && ln -s "$(find /usr/lib -name 'libpython3*.so' -print -quit)" /usr/local/lib/libpython3.so \ && rm -rf /var/lib/apt/lists/* COPY docker/entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh # Set PYTHONNET_PYDLL environment variable -ENV PYTHONNET_PYDLL=/usr/lib/aarch64-linux-gnu/libpython3.11.so +ENV PYTHONNET_PYDLL=/usr/local/lib/libpython3.so EXPOSE 8080/tcp EXPOSE 443/tcp diff --git a/docker/ElsaServerAndStudio.Dockerfile b/docker/ElsaServerAndStudio.Dockerfile index 726904cd0..95c1c7bfb 100644 --- a/docker/ElsaServerAndStudio.Dockerfile +++ b/docker/ElsaServerAndStudio.Dockerfile @@ -7,13 +7,12 @@ COPY ./NuGet.Config ./ COPY *.props ./ # restore packages. -RUN dotnet restore "./src/apps/ElsaStudioWebAssembly/ElsaStudioWebAssembly.csproj" -RUN dotnet restore "./src/apps/Elsa.ServerAndStudio.Web/Elsa.ServerAndStudio.Web.csproj" +RUN dotnet restore "./src/apps/Elsa.ModularServer.Web/Elsa.ModularServer.Web.csproj" # build and publish (UseAppHost=false creates platform independent binaries). -WORKDIR /source/src/apps/Elsa.ServerAndStudio.Web -RUN dotnet build "Elsa.ServerAndStudio.Web.csproj" -c Release -o /app/build -RUN dotnet publish "Elsa.ServerAndStudio.Web.csproj" -c Release -o /app/publish /p:UseAppHost=false --no-restore -f net10.0 +WORKDIR /source/src/apps/Elsa.ModularServer.Web +RUN dotnet build "Elsa.ModularServer.Web.csproj" -c Release -o /app/build +RUN dotnet publish "Elsa.ModularServer.Web.csproj" -c Release -o /app/publish /p:UseAppHost=false --no-restore -f net10.0 # move binaries into smaller base image. FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base @@ -24,20 +23,21 @@ COPY --from=build /app/publish ./ RUN apt-get update \ && apt-get install -y --no-install-recommends \ ca-certificates \ - libpython3.11 \ - python3.11 \ - python3.11-dev \ + libpython3-dev \ + python3 \ + python3-dev \ python3-pip \ && update-ca-certificates \ + && ln -s "$(find /usr/lib -name 'libpython3*.so' -print -quit)" /usr/local/lib/libpython3.so \ && rm -rf /var/lib/apt/lists/* COPY docker/entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh # Set PYTHONNET_PYDLL environment variable -ENV PYTHONNET_PYDLL=/usr/lib/aarch64-linux-gnu/libpython3.11.so +ENV PYTHONNET_PYDLL=/usr/local/lib/libpython3.so EXPOSE 8080/tcp EXPOSE 443/tcp ENTRYPOINT ["/entrypoint.sh"] -CMD ["dotnet", "Elsa.ServerAndStudio.Web.dll"] +CMD ["dotnet", "Elsa.ModularServer.Web.dll"] diff --git a/docker/ElsaStudio.Dockerfile b/docker/ElsaStudio.Dockerfile index 34b69c0c9..61b6032f3 100644 --- a/docker/ElsaStudio.Dockerfile +++ b/docker/ElsaStudio.Dockerfile @@ -7,13 +7,12 @@ COPY ./NuGet.Config ./ COPY *.props ./ # restore packages. -RUN dotnet restore "./src/apps/ElsaStudioWebAssembly/ElsaStudioWebAssembly.csproj" -RUN dotnet restore "./src/apps/Elsa.Studio.Web/Elsa.Studio.Web.csproj" +RUN dotnet restore "./src/apps/Elsa.ModularServer.Web/Elsa.ModularServer.Web.csproj" # build and publish (UseAppHost=false creates platform independent binaries). -WORKDIR /source/src/apps/Elsa.Studio.Web -RUN dotnet build "Elsa.Studio.Web.csproj" -c Release -o /app/build -RUN dotnet publish "Elsa.Studio.Web.csproj" -c Release -o /app/publish /p:UseAppHost=false --no-restore -f net10.0 +WORKDIR /source/src/apps/Elsa.ModularServer.Web +RUN dotnet build "Elsa.ModularServer.Web.csproj" -c Release -o /app/build +RUN dotnet publish "Elsa.ModularServer.Web.csproj" -c Release -o /app/publish /p:UseAppHost=false --no-restore -f net10.0 # move binaries into smaller base image. FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base @@ -32,4 +31,4 @@ RUN chmod +x /entrypoint.sh EXPOSE 8080/tcp EXPOSE 443/tcp ENTRYPOINT ["/entrypoint.sh"] -CMD ["dotnet", "Elsa.Studio.Web.dll"] +CMD ["dotnet", "Elsa.ModularServer.Web.dll"] diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 356daf467..2df206496 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -75,6 +75,16 @@ services: - ASPNETCORE_URLS=http://+:80 - Logging__LogLevel__Default=Information + aspire-dashboard: + image: mcr.microsoft.com/dotnet/aspire-dashboard:latest + container_name: aspire-dashboard + ports: + - "18888:18888" # Dashboard UI + - "4317:18889" # OTLP/gRPC + - "4318:18890" # OTLP/HTTP + environment: + ASPIRE_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS: "true" + volumes: sqlserver_data: postgres-data: diff --git a/scripts/test-ca-trust.sh b/scripts/test-ca-trust.sh index 7c078606b..42f0bcdf7 100755 --- a/scripts/test-ca-trust.sh +++ b/scripts/test-ca-trust.sh @@ -54,40 +54,48 @@ CERTEXT fi sleep 0.2 done +} - echo "$CERT_WORKDIR" +cleanup_local_ca_server() { + if [ -n "${SERVER_PID:-}" ]; then + kill "$SERVER_PID" >/dev/null 2>&1 || true + wait "$SERVER_PID" 2>/dev/null || true + SERVER_PID= + fi + + if [ -n "${CERT_WORKDIR:-}" ]; then + rm -rf "$CERT_WORKDIR" + CERT_WORKDIR= + fi } run_extra_ca_test() { - local cert_dir - cert_dir=$(start_local_ca_server) - trap "kill ${SERVER_PID:-0} >/dev/null 2>&1 || true; rm -rf '$cert_dir'" EXIT + start_local_ca_server + trap cleanup_local_ca_server EXIT echo "[CA] Validating EXTRA_CA_CERT flow against local CA" >&2 run_smoke "https://host.docker.internal:${LOCAL_PORT}" \ --add-host host.docker.internal:host-gateway \ - -v "${cert_dir}:/certs:ro" \ + -v "${CERT_WORKDIR}:/certs:ro" \ -e EXTRA_CA_CERT=/certs/ca.crt echo "[CA] Validating SSL_CERT_FILE fallback" >&2 run_smoke "https://host.docker.internal:${LOCAL_PORT}" \ --add-host host.docker.internal:host-gateway \ - -v "${cert_dir}:/certs:ro" \ + -v "${CERT_WORKDIR}:/certs:ro" \ -e SSL_CERT_FILE=/certs/ca.crt - mkdir -p "$cert_dir/dir" - cp "$cert_dir/ca.crt" "$cert_dir/dir/custom-ca.crt" - openssl rehash "$cert_dir/dir" >/dev/null 2>&1 + mkdir -p "$CERT_WORKDIR/dir" + cp "$CERT_WORKDIR/ca.crt" "$CERT_WORKDIR/dir/custom-ca.crt" + openssl rehash "$CERT_WORKDIR/dir" >/dev/null 2>&1 echo "[CA] Validating SSL_CERT_DIR fallback" >&2 run_smoke "https://host.docker.internal:${LOCAL_PORT}" \ --add-host host.docker.internal:host-gateway \ - -v "${cert_dir}:/certs:ro" \ + -v "${CERT_WORKDIR}:/certs:ro" \ -e SSL_CERT_DIR=/certs/dir - kill "${SERVER_PID:-0}" >/dev/null 2>&1 || true - wait "${SERVER_PID:-0}" 2>/dev/null || true - rm -rf "$cert_dir" + cleanup_local_ca_server trap - EXIT } diff --git a/specs/008-diagnostics-otel/checklists/requirements.md b/specs/008-diagnostics-otel/checklists/requirements.md new file mode 100644 index 000000000..de04485bb --- /dev/null +++ b/specs/008-diagnostics-otel/checklists/requirements.md @@ -0,0 +1,31 @@ +# Specification Quality Checklist: Diagnostics OpenTelemetry + +**Purpose**: Validate Core specification completeness before implementation +**Created**: 2026-05-25 +**Feature**: [spec.md](../spec.md) + +## Content Quality + +- [x] No implementation details in product requirements beyond Core system boundaries +- [x] Focused on user value and backend diagnostics needs +- [x] All mandatory sections completed + +## Requirement Completeness + +- [x] No [NEEDS CLARIFICATION] markers remain +- [x] Requirements are testable and unambiguous +- [x] Success criteria are measurable +- [x] Acceptance scenarios are defined +- [x] Edge cases are identified +- [x] Scope is clearly bounded +- [x] Dependencies and assumptions identified + +## Feature Readiness + +- [x] Functional requirements have clear acceptance criteria +- [x] User scenarios cover primary Core flows +- [x] Technical plan identifies Core module boundaries + +## Notes + +- Studio UI work is intentionally tracked in `elsa-studio/specs/008-diagnostics-otel`. diff --git a/specs/008-diagnostics-otel/contracts/otlp-ingest.md b/specs/008-diagnostics-otel/contracts/otlp-ingest.md new file mode 100644 index 000000000..e6b3913ec --- /dev/null +++ b/specs/008-diagnostics-otel/contracts/otlp-ingest.md @@ -0,0 +1,50 @@ +# Contract: OTLP Ingestion + +## HTTP/protobuf + +Default base path: + +```text +/elsa/otlp/v1 +``` + +Supported paths: + +```text +POST /elsa/otlp/v1/traces +POST /elsa/otlp/v1/metrics +POST /elsa/otlp/v1/logs +``` + +Requests use OTLP protobuf bodies. Accepted payloads return `200 OK`; unauthorized requests return `401 Unauthorized`; malformed protobuf payloads return `400 Bad Request`; payloads over the configured request body limit return `413 Payload Too Large`. The current collector does not emit OTLP partial-success response bodies. + +## gRPC + +When enabled, Core exposes OTLP gRPC services: + +```text +opentelemetry.proto.collector.trace.v1.TraceService/Export +opentelemetry.proto.collector.metrics.v1.MetricsService/Export +opentelemetry.proto.collector.logs.v1.LogsService/Export +``` + +When gRPC is disabled, collector configuration must return `GrpcEnabled = false` and no endpoint. + +## Security + +- Loopback-only development ingestion may run without an API key only when the request remote address is loopback and the advertised collector binding is loopback. +- Non-loopback requests and non-loopback collector bindings must require a configured header such as `x-otlp-api-key`. +- Secret header values are configured server-side, compared without exposing the configured value, and omitted from collector configuration responses. +- Accepted telemetry is redacted before storage and live streaming. +- OTLP sender auth is separate from diagnostics API user auth. + +## Internal Contract + +```csharp +public interface IOpenTelemetryIngestor +{ + ValueTask IngestAsync(OpenTelemetryBatch batch, CancellationToken cancellationToken = default); +} +``` + +Transport-specific code parses payloads; shared ingestion normalizes, redacts, stores, and publishes live updates. diff --git a/specs/008-diagnostics-otel/contracts/provider-contract.md b/specs/008-diagnostics-otel/contracts/provider-contract.md new file mode 100644 index 000000000..7b0f974ff --- /dev/null +++ b/specs/008-diagnostics-otel/contracts/provider-contract.md @@ -0,0 +1,48 @@ +# Contract: Provider and Store + +## Provider Facade + +```csharp +public interface IOpenTelemetryProvider +{ + ValueTask SearchResourcesAsync(TelemetryResourceFilter filter, CancellationToken cancellationToken = default); + ValueTask SearchTracesAsync(TelemetryTraceFilter filter, CancellationToken cancellationToken = default); + ValueTask GetTraceAsync(string traceId, CancellationToken cancellationToken = default); + ValueTask SearchMetricsAsync(TelemetryMetricFilter filter, CancellationToken cancellationToken = default); + ValueTask SearchLogsAsync(OtlpLogFilter filter, CancellationToken cancellationToken = default); + ValueTask GetStorageDiagnosticsAsync(CancellationToken cancellationToken = default); +} +``` + +## Store + +```csharp +public interface IOpenTelemetryStore +{ + ValueTask WriteTracesAsync(IReadOnlyCollection spans, CancellationToken cancellationToken = default); + ValueTask WriteMetricsAsync(IReadOnlyCollection metrics, CancellationToken cancellationToken = default); + ValueTask WriteLogsAsync(IReadOnlyCollection logs, CancellationToken cancellationToken = default); +} +``` + +The concrete in-memory implementation also supports provider queries. A later durable provider may split write/query responsibilities if needed. + +Search methods return bounded results using server-capped limits. Search ordering is newest receive time first. Trace detail ordering is parent/child chronological so Studio can render a waterfall without reassembling hierarchy from arbitrary span order. + +## Redaction + +```csharp +public interface IOpenTelemetryRedactor +{ + TelemetryResource Redact(TelemetryResource resource); + TelemetrySpan Redact(TelemetrySpan span); + MetricPoint Redact(MetricPoint point); + OtlpLogRecord Redact(OtlpLogRecord logRecord); +} +``` + +Redaction occurs before store writes and live publishing. + +## Capacity + +The default in-memory provider uses configurable per-signal limits with drop-oldest overflow. Defaults must be at least 500 resources, 2,000 traces, 10,000 spans, 20,000 metric points, 10,000 OTLP log records, and 1,000 queued live updates per subscriber. diff --git a/specs/008-diagnostics-otel/contracts/rest-api.md b/specs/008-diagnostics-otel/contracts/rest-api.md new file mode 100644 index 000000000..66c128a48 --- /dev/null +++ b/specs/008-diagnostics-otel/contracts/rest-api.md @@ -0,0 +1,67 @@ +# Contract: REST API + +Base path: + +```text +/diagnostics/opentelemetry +``` + +All endpoints require the OpenTelemetry diagnostics view permission. + +Search endpoints accept a caller-provided limit capped by server options. Trace, metric, and log search results return the latest matching window in ascending chronological order. Resource search results are ordered by most recently seen first. Trace detail spans are returned in parent/child order with chronological ordering inside each sibling set. + +## Resources + +```text +POST /diagnostics/opentelemetry/resources/search +``` + +Filters by service name, status, and text. + +## Trace Search + +```text +POST /diagnostics/opentelemetry/traces/search +``` + +Filters by resource key, service name, trace ID, workflow instance ID, workflow definition ID, status, text, and time range. + +## Trace Detail + +```text +GET /diagnostics/opentelemetry/traces/{traceId} +``` + +Returns trace summary, ordered spans, related resources, and OTLP logs for the trace when available. + +## Metrics + +```text +POST /diagnostics/opentelemetry/metrics/search +``` + +Filters by resource, instrument name, attribute text, and time range. + +## OTLP Logs + +```text +POST /diagnostics/opentelemetry/logs/search +``` + +Filters by resource, trace ID, span ID, severity, text, and time range. + +## Collector Configuration + +```text +GET /diagnostics/opentelemetry/collector-configuration +``` + +Returns HTTP endpoint metadata, nullable/disabled gRPC metadata, required header names, loopback status, and recommended non-secret OTEL environment variables. + +## Storage Diagnostics + +```text +GET /diagnostics/opentelemetry/storage +``` + +Returns capacity, dropped counts, and current resource/trace/series counts. diff --git a/specs/008-diagnostics-otel/contracts/signalr-hub.md b/specs/008-diagnostics-otel/contracts/signalr-hub.md new file mode 100644 index 000000000..f788b4d96 --- /dev/null +++ b/specs/008-diagnostics-otel/contracts/signalr-hub.md @@ -0,0 +1,39 @@ +# Contract: SignalR Hub + +Hub path: + +```text +/elsa/hubs/diagnostics/opentelemetry +``` + +The hub requires the OpenTelemetry diagnostics view permission. + +## Client-to-Server Methods + +```text +SubscribeAsync(OpenTelemetryTraceFilter filter) +``` + +Filters support resource ID, service name, trace ID, workflow instance ID, workflow definition ID, status, text, and time range. Metric clients subscribe through the trace-filter-compatible live stream and apply metric-specific filtering client-side. + +## Server-to-Client Events + +```text +ReceiveAsync(OpenTelemetryStreamItem item) +``` + +`OpenTelemetryStreamItem` variants: + +- `Resource` +- `Trace` +- `MetricPoint` +- `Log` +- `DroppedItems` + +## Lifecycle + +- Subscriptions are bounded by server-side per-connection subscriber capacity. +- Filter changes are represented by starting a new subscription. +- Disconnected clients release subscriber resources. +- When a subscriber queue is full, live updates are dropped and reported through `DroppedItems` summaries. +- Subscriber overflow must not disconnect the client unless the connection itself is unhealthy or unauthorized. diff --git a/specs/008-diagnostics-otel/data-model.md b/specs/008-diagnostics-otel/data-model.md new file mode 100644 index 000000000..f1c72d262 --- /dev/null +++ b/specs/008-diagnostics-otel/data-model.md @@ -0,0 +1,104 @@ +# Data Model: Diagnostics OpenTelemetry + +## Telemetry Resource + +| Field | Notes | +|-------|-------| +| `ResourceKey` | Stable key derived from service name, instance ID, and resource attributes. | +| `ServiceName` | From `service.name` or `OTEL_SERVICE_NAME`; fallback is `unknown_service`. | +| `ServiceInstanceId` | From `service.instance.id` when present. | +| `ServiceVersion` | From `service.version` when present. | +| `DeploymentEnvironment` | From `deployment.environment` when present. | +| `Attributes` | Redacted resource attributes. | +| `FirstSeen`, `LastSeen` | Backend receive timestamps. | +| `Status` | Active, stale, or disconnected. | + +## Telemetry Trace + +| Field | Notes | +|-------|-------| +| `TraceId` | Required trace identifier. | +| `RootSpanId` | Root span when known. | +| `Name` | Root span name or synthesized trace label. | +| `ResourceKeys` | Participating resources. | +| `StartTime`, `EndTime`, `Duration` | Derived from spans. | +| `Status` | Ok, error, unset, or mixed. | +| `SpanCount`, `ErrorCount` | Derived counters. | +| `WorkflowInstanceId`, `WorkflowDefinitionId` | Elsa span attributes when present. | +| `LastReceivedAt` | Backend receive timestamp. | + +## Telemetry Span + +| Field | Notes | +|-------|-------| +| `TraceId`, `SpanId`, `ParentSpanId` | Trace hierarchy. | +| `ResourceKey` | Emitting resource. | +| `Name`, `Kind` | OTEL span metadata. | +| `StartTime`, `EndTime`, `Duration` | Timing. | +| `StatusCode`, `StatusDescription` | OTEL status. | +| `Attributes` | Redacted span attributes. | +| `Events` | Redacted events. | +| `Links` | Span links. | +| `Workflow*`, `Activity*`, `TenantId`, `CorrelationId` | Existing `Elsa.Workflows` semantic attributes when present: `workflow.*`, `workflow.activity.*`, and `elsa.tenant.id`. | +| `ReceivedAt` | Backend receive timestamp. | + +## Metric Instrument and Point + +| Field | Notes | +|-------|-------| +| `Name`, `Description`, `Unit`, `Type` | Instrument metadata. | +| `ResourceKey` | Emitting resource. | +| `Series` | Bounded collection by attribute set. | +| `Timestamp`, `StartTimestamp` | Point timestamps. | +| `Attributes` | Redacted point attributes. | +| `Value` | Sum/gauge value. | +| `Count`, `Sum`, `Min`, `Max`, `Buckets` | Histogram fields when present. | +| `Temporality` | Cumulative or delta. | +| `DroppedPointCount` | Capacity drop count. | + +## OTLP Log Record + +| Field | Notes | +|-------|-------| +| `Id` | Backend assigned ID. | +| `Timestamp`, `ObservedTimestamp`, `ReceivedAt` | OTLP and backend timing. | +| `ResourceKey` | Emitting resource. | +| `SeverityText`, `SeverityNumber` | OTEL severity. | +| `Body` | Redacted body. | +| `TraceId`, `SpanId` | Correlation fields. | +| `Attributes` | Redacted log attributes. | + +## Collector Configuration + +| Field | Notes | +|-------|-------| +| `HttpEndpoint` | Base endpoint suitable for `OTEL_EXPORTER_OTLP_ENDPOINT` with HTTP/protobuf. | +| `GrpcEndpoint` | Endpoint suitable for gRPC when enabled; null when unavailable. | +| `GrpcEnabled` | Whether gRPC ingestion is enabled. | +| `GrpcDisabledReason` | Optional non-secret explanation when disabled. | +| `RequiredHeaders` | Required ingestion header names without secret values. | +| `RecommendedEnvironment` | Copyable non-secret OTEL environment variable values. | +| `IsLoopbackOnly` | Whether ingestion is restricted to loopback. | +| `RequiresApiKey` | Whether configured ingestion protection is required for advertised endpoints. | + +## Storage Diagnostics + +| Field | Notes | +|-------|-------| +| `DroppedSpanCount` | Spans dropped by store capacity. | +| `DroppedMetricPointCount` | Metric points dropped by capacity. | +| `DroppedLogRecordCount` | OTLP logs dropped by capacity. | +| `DroppedLiveUpdateCount` | Live updates dropped by subscriber capacity. | +| `ResourceCount`, `TraceCount`, `MetricSeriesCount` | Current counts. | + +## Storage Capacity Policy + +| Field | Notes | +|-------|-------| +| `MaxResources` | Default at least 500. | +| `MaxTraces` | Default at least 2,000. | +| `MaxSpans` | Default at least 10,000. | +| `MaxMetricPoints` | Default at least 20,000 across all metric series. | +| `MaxLogRecords` | Default at least 10,000. | +| `MaxLiveUpdatesPerSubscriber` | Default at least 1,000 queued updates per SignalR subscriber. | +| `OverflowPolicy` | Drop oldest item in the signal-specific buffer and increment the matching dropped counter. | diff --git a/specs/008-diagnostics-otel/plan.md b/specs/008-diagnostics-otel/plan.md new file mode 100644 index 000000000..0fd66f7df --- /dev/null +++ b/specs/008-diagnostics-otel/plan.md @@ -0,0 +1,149 @@ +# Implementation Plan: Diagnostics OpenTelemetry + +**Branch**: `008-diagnostics-otel` | **Date**: 2026-05-25 | **Spec**: [spec.md](./spec.md) +**Input**: Feature specification from `/specs/008-diagnostics-otel/spec.md` + +## Summary + +Add an opt-in `Elsa.Diagnostics.OpenTelemetry` Core diagnostics module that receives OTLP telemetry, normalizes it into Elsa diagnostics read models, redacts sensitive values before provider boundaries, stores recent telemetry in bounded memory, exposes authenticated REST APIs and SignalR live updates for Studio, and publishes collector configuration metadata for standard OTEL senders. + +The module is a collector/API backend, not producer-side workflow tracing middleware. Existing `Elsa.Workflows.Core` `ActivitySource` and `Meter` instrumentation remains the workflow telemetry producer. The historical `Elsa.OpenTelemetry` module from `elsa-extensions` is not ported in v1. + +## Technical Context + +**Language/Version**: C# latest, nullable reference types enabled, implicit usings enabled. +**Primary Dependencies**: OpenTelemetry SDK/proto contracts, ASP.NET Core endpoint patterns, optional gRPC services, SignalR, Elsa feature/module infrastructure, FastEndpoints through Elsa API endpoint patterns, Elsa shell feature infrastructure, existing Elsa identity/authorization patterns, current `Elsa.Workflows.Core` instrumentation. +**Storage**: Bounded in-memory telemetry repository for resources, traces, spans, metric instruments/points, OTLP log records, live subscribers, and dropped-count diagnostics. Defaults are configurable, drop oldest per signal on overflow, and start with at least 500 resources, 2,000 traces, 10,000 spans, 20,000 metric points, 10,000 OTLP log records, and 1,000 queued live updates per subscriber. No durable database schema in v1. +**Testing**: xUnit unit tests for normalization, redaction, resource identity, filtering, bounded storage, dropped counts, and collector configuration; integration tests for HTTP/protobuf OTLP ingestion, optional gRPC ingestion when enabled, permissions, SignalR, API contracts, and workflow export-to-collector timing. +**Target Platform**: ASP.NET Core Elsa Server on supported repository target frameworks. +**Project Type**: Modular .NET library inside the existing Elsa solution. +**Performance Goals**: Local workflow telemetry appears through diagnostics APIs within 2 seconds; trace detail handles 100 spans; metrics handle 20 instruments and 1,000 recent points; backend buffers remain bounded under overload. +**Constraints**: Do not merge with Structured Logs or Console Logs. Do not port historical producer middleware. Do not start workflow/activity spans in the diagnostics module or mutate `Activity.Current`. Do not add durable OTEL persistence, vendor exporters, Kubernetes/Docker APIs, or Studio UI in Core. Non-loopback OTLP ingestion requires explicit protection. +**Scale/Scope**: One Core module, unit/integration tests, docs/wiki quickstart updates, API/hub contracts, and sample host wiring if needed for verification. + +## Constitution Check + +Evaluated against `.specify/memory/constitution.md` v1.1.0: + +| Principle | Verdict | Evidence | +|-----------|---------|----------| +| I. Modular Architecture | PASS | Work is a focused module under `src/modules/Elsa.Diagnostics.OpenTelemetry` with contracts, services, endpoints, hub, options, permissions, and shell feature. | +| II. Composition & Extensibility | PASS | Ingestion, redaction, store, live feed, source registry, and collector configuration are explicit contracts/services. | +| III. Convention-Driven Design | PASS | Names follow Elsa module, endpoint, feature, permission, and test conventions with American English. | +| IV. Async & Pipeline Execution | PASS | Ingestion, provider queries, endpoints, live subscriptions, and shutdown paths are async/cancellation-aware. | +| V. Testing Discipline | PASS | Plan requires unit/integration coverage for ingestion, security, storage, API, SignalR, and workflow telemetry timing. | +| VI. Trunk-Based Development | PASS | Core backend module can land independently from Studio after API contracts stabilize. | +| VII. Simplicity, SRP, DRY & KISS | PASS | V1 uses bounded in-memory storage and excludes durable storage, vendor exporters, app launcher behavior, and producer middleware changes. | + +## Project Structure + +### Documentation (this feature) + +```text +specs/008-diagnostics-otel/ +├── spec.md +├── plan.md +├── research.md +├── data-model.md +├── quickstart.md +├── contracts/ +│ ├── rest-api.md +│ ├── otlp-ingest.md +│ ├── signalr-hub.md +│ └── provider-contract.md +├── checklists/ +│ └── requirements.md +└── tasks.md +``` + +### Source Code (repository root) + +```text +src/modules/ +└── Elsa.Diagnostics.OpenTelemetry/ + ├── Contracts/ + │ ├── IOpenTelemetryIngestor.cs + │ ├── IOpenTelemetryProvider.cs + │ ├── IOpenTelemetryRedactor.cs + │ ├── IOpenTelemetrySourceRegistry.cs + │ ├── IOpenTelemetryStore.cs + │ └── IOpenTelemetryLiveFeed.cs + ├── Endpoints/OpenTelemetry/ + │ ├── CollectorConfiguration/Endpoint.cs + │ ├── Logs/Endpoint.cs + │ ├── Metrics/Endpoint.cs + │ ├── Resources/Endpoint.cs + │ ├── Storage/Endpoint.cs + │ ├── Trace/Endpoint.cs + │ └── Traces/Endpoint.cs + ├── Extensions/ + ├── Features/OpenTelemetryFeature.cs + ├── Ingestion/ + │ ├── Grpc/ + │ └── HttpProtobuf/ + ├── Models/ + ├── Options/OpenTelemetryDiagnosticsOptions.cs + ├── Permissions/OpenTelemetryPermissions.cs + ├── Providers/InMemory/ + ├── RealTime/OpenTelemetryHub.cs + ├── Services/ + └── ShellFeatures/OpenTelemetryFeature.cs + +test/unit/ +└── Elsa.Diagnostics.OpenTelemetry.UnitTests/ + +test/integration/ +└── Elsa.Diagnostics.OpenTelemetry.IntegrationTests/ +``` + +**Structure Decision**: Add a new diagnostics module parallel to `Elsa.Diagnostics.StructuredLogs` and `Elsa.Diagnostics.ConsoleLogs`. The module owns collector, normalization, storage, APIs, and live contracts only. + +## Phase 0 Output + +See [research.md](./research.md). + +Resolved decisions: + +- Core module is the OTLP collector and diagnostics API boundary. +- Existing `Elsa.Workflows.Core` instrumentation remains the producer. +- Do not port historical `Elsa.OpenTelemetry` producer middleware from `elsa-extensions`. +- Support HTTP/protobuf as required; support gRPC when host/dependencies enable it and advertise disabled metadata otherwise. +- Use bounded in-memory storage in v1. +- Keep OTLP logs separate from `Elsa.Diagnostics.StructuredLogs`. +- Require protection for non-loopback ingestion. + +## Phase 1 Output + +- [data-model.md](./data-model.md) +- [contracts/rest-api.md](./contracts/rest-api.md) +- [contracts/otlp-ingest.md](./contracts/otlp-ingest.md) +- [contracts/signalr-hub.md](./contracts/signalr-hub.md) +- [contracts/provider-contract.md](./contracts/provider-contract.md) +- [quickstart.md](./quickstart.md) + +## Post-Design Constitution Re-Check + +| Principle | Verdict | Post-design evidence | +|-----------|---------|----------------------| +| I. Modular Architecture | PASS | Contracts and source tree keep all Core OpenTelemetry diagnostics behavior in one focused module. | +| II. Composition & Extensibility | PASS | Provider/store/live-feed/redactor/ingestor contracts isolate real variability points. | +| III. Convention-Driven Design | PASS | Endpoint and type names follow diagnostics module conventions. | +| IV. Async & Pipeline Execution | PASS | Provider, store, endpoint, and hub contracts are async/cancellation-aware. | +| V. Testing Discipline | PASS | Tasks include unit and integration tests for each buildable slice. | +| VI. Trunk-Based Development | PASS | Core slice remains independently reviewable from Studio. | +| VII. Simplicity, SRP, DRY & KISS | PASS | V1 avoids persistence and producer instrumentation rewrites. | + +## Phase 2 Handoff + +Use [tasks.md](./tasks.md) as the implementation backlog. Suggested order: + +1. Create module/test projects, solution entries, options, permissions, feature, and shell feature. +2. Add models and shared provider contracts. +3. Add HTTP/protobuf ingestion, normalization, redaction, resource registry, bounded store, and provider facade. +4. Add REST APIs, SignalR hub, collector configuration, and security checks. +5. Add optional gRPC wrappers and disabled metadata handling. +6. Add docs, sample host wiring if needed, and run targeted tests/builds. + +## Complexity Tracking + +No constitution violations identified. diff --git a/specs/008-diagnostics-otel/quickstart.md b/specs/008-diagnostics-otel/quickstart.md new file mode 100644 index 000000000..11ab69d79 --- /dev/null +++ b/specs/008-diagnostics-otel/quickstart.md @@ -0,0 +1,72 @@ +# Quickstart: Diagnostics OpenTelemetry + +## Enable Core Diagnostics + +```csharp +services.AddElsa(elsa => +{ + elsa.UseOpenTelemetryDiagnostics(options => + { + options.HttpEndpointPath = "/elsa/otlp/v1"; + options.ApiKey = builder.Configuration["Diagnostics:OpenTelemetry:ApiKey"]; + options.TraceCapacity = 2_000; + options.SpanCapacity = 10_000; + options.MetricPointCapacity = 20_000; + options.LogRecordCapacity = 10_000; + options.ResourceCapacity = 500; + options.SubscriberChannelCapacity = 1_000; + options.MaxHttpRequestBodySize = 10 * 1024 * 1024; + }); +}); +``` + +## Configure Elsa Workflow Telemetry Export + +```csharp +services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddSource("Elsa.Workflows") + .AddOtlpExporter()) + .WithMetrics(builder => builder + .AddMeter("Elsa.Workflows") + .AddOtlpExporter()); +``` + +Development HTTP/protobuf environment: + +```text +OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:5000/elsa/otlp/v1 +OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf +OTEL_SERVICE_NAME=elsa-api +OTEL_RESOURCE_ATTRIBUTES=service.instance.id=local-elsa-api,deployment.environment=development +OTEL_BSP_SCHEDULE_DELAY=1000 +OTEL_BLRP_SCHEDULE_DELAY=1000 +OTEL_METRIC_EXPORT_INTERVAL=1000 +``` + +When the collector is reachable from non-loopback addresses, configure the server-side API key and send only the configured header name/value through OTLP exporter headers. Collector configuration must advertise required header names but never secret values. + +gRPC senders should only use gRPC when collector configuration advertises a gRPC endpoint: + +```text +OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 +OTEL_EXPORTER_OTLP_PROTOCOL=grpc +``` + +## Verify + +```bash +dotnet test test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Elsa.Diagnostics.OpenTelemetry.UnitTests.csproj +dotnet test test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/Elsa.Diagnostics.OpenTelemetry.IntegrationTests.csproj +``` + +Manual checks: + +- Run a workflow and confirm a workflow trace appears through `/diagnostics/opentelemetry/traces/search` within 2 seconds. +- Query `/diagnostics/opentelemetry/traces/{traceId}` and confirm workflow/activity spans are parented and ordered. +- Query collector configuration and confirm HTTP metadata, nullable/disabled gRPC metadata, and required header names. +- Attempt non-loopback ingestion without the configured API key and confirm rejection. + +## Scope Boundaries + +This feature does not add durable OTEL persistence, vendor exporters, Studio UI, alerting, Kubernetes/Docker APIs, or historical `Elsa.OpenTelemetry` producer middleware. Production deployments should usually export to a standard OpenTelemetry Collector or observability platform unless Elsa collector capacity and security are deliberately configured. diff --git a/specs/008-diagnostics-otel/research.md b/specs/008-diagnostics-otel/research.md new file mode 100644 index 000000000..40d3ebb0e --- /dev/null +++ b/specs/008-diagnostics-otel/research.md @@ -0,0 +1,54 @@ +# Research: Diagnostics OpenTelemetry + +## Decision: Core owns the collector/API boundary + +**Rationale**: OTLP ingestion must happen in an ASP.NET Core backend, not in Studio. Core can authenticate diagnostics APIs, protect ingestion, normalize protobuf payloads, and stream live updates. + +**Alternatives considered**: + +- Studio collector: rejected because browser/Studio hosts cannot reliably expose OTLP endpoints. +- External collector only: rejected because this feature needs a first-party local diagnostics story. + +## Decision: Preserve existing workflow instrumentation + +**Rationale**: Current `Elsa.Workflows.Core` already emits `Elsa.Workflows` spans and metrics through `System.Diagnostics`. This module should consume/export that telemetry through OTLP rather than re-instrument workflow execution. + +**Alternatives considered**: + +- Port `elsa-extensions` `Elsa.OpenTelemetry`: rejected because it is producer-side middleware, overlaps current Core instrumentation, and includes trace-boundary behavior that mutates ambient `Activity.Current`. +- Move instrumentation into diagnostics: rejected because workflow instrumentation is valuable even when diagnostics collector is not installed. + +## Decision: HTTP/protobuf required, gRPC optional + +**Rationale**: HTTP/protobuf fits existing ASP.NET Core endpoint patterns and common deployment routes. gRPC is useful for SDK defaults but depends on host configuration and package choices, so it should be enabled when available and represented honestly in collector metadata. + +**Alternatives considered**: + +- gRPC only: rejected because it complicates proxying and local HTTP testing. +- Always return a gRPC endpoint: rejected because it misleads clients when the host does not expose gRPC. + +## Decision: Bounded in-memory v1 storage + +**Rationale**: Traces, metrics, and logs can be high volume. A bounded in-memory default matches the existing diagnostics modules and keeps v1 focused. + +**Alternatives considered**: + +- Durable storage now: rejected because trace and metric schemas need a deliberate follow-up provider design. +- Raw OTLP payload storage only: rejected because diagnostics clients need filtered, assembled trace and metric models. + +## Decision: OTLP logs stay separate from Structured Logs + +**Rationale**: OTLP logs can come from arbitrary resources and use OTEL schemas. `Elsa.Diagnostics.StructuredLogs` owns first-party `ILogger` capture. Correlation should use trace/span IDs, not shared storage. + +**Alternatives considered**: + +- Merge OTLP logs into Structured Logs: rejected because schemas, retention, permissions, and source semantics differ. + +## Decision: Explicit non-loopback protection + +**Rationale**: OTLP ingestion can expose sensitive application metadata and create high traffic. Loopback development can be low friction, but remote ingestion needs an API key header or equivalent configured protection. + +**Alternatives considered**: + +- No OTLP sender auth: rejected as unsafe. +- Require interactive user auth for OTLP senders: rejected because SDKs usually support headers, not browser auth. diff --git a/specs/008-diagnostics-otel/spec.md b/specs/008-diagnostics-otel/spec.md new file mode 100644 index 000000000..2c662a5ce --- /dev/null +++ b/specs/008-diagnostics-otel/spec.md @@ -0,0 +1,158 @@ +# Feature Specification: Diagnostics OpenTelemetry + +**Feature Branch**: `008-diagnostics-otel` +**Created**: 2026-05-25 +**Status**: Draft +**Input**: Core-owned specification for the backend side of the OpenTelemetry diagnostics PRD coordinated with `elsa-studio/specs/008-diagnostics-otel`. + +## Clarifications + +### Session 2026-05-25 + +- Q: What default capacity and overflow policy should the Core in-memory OTEL store use? -> A: Configurable bounded defaults with drop-oldest per signal. +- Q: How should Core decide when OTLP ingestion requires an API key? -> A: Require the configured header for any non-loopback request or non-loopback collector binding. +- Q: How should live SignalR subscriptions behave under backpressure? -> A: Use bounded per-connection queues, drop oldest updates, and report dropped counts. +- Q: Which workflow attributes are canonical for Elsa trace correlation? -> A: Preserve existing `Elsa.Workflows` semantic tags; do not add producer middleware or mutate ambient activity context. + +## User Scenarios & Testing *(mandatory)* + +### User Story 1 - Collect OpenTelemetry from Elsa services (Priority: P1) + +An operator enables OpenTelemetry diagnostics on an Elsa backend and receives workflow traces, activity spans, metrics, resources, and correlated OTLP logs through a first-party diagnostics backend. + +**Why this priority**: Studio cannot visualize telemetry until Core can collect, normalize, secure, and expose it. + +**Independent Test**: Enable the Core OpenTelemetry diagnostics feature, run a workflow with multiple activities, export telemetry to the local diagnostics collector, and verify recent resources, traces, spans, metrics, and logs through backend diagnostics APIs. + +**Acceptance Scenarios**: + +1. **Given** the diagnostics OpenTelemetry feature is enabled, **When** workflow execution emits spans and metrics from `Elsa.Workflows`, **Then** Core stores recent telemetry with resource identity, trace/span IDs, timing, status, and workflow metadata. +2. **Given** a standard OpenTelemetry SDK posts OTLP traces, metrics, or logs to the HTTP/protobuf collector endpoint, **When** the payload is accepted, **Then** Core normalizes the telemetry into queryable diagnostics models. +3. **Given** telemetry contains sensitive attributes matching configured redaction rules, **When** Core stores or streams it, **Then** sensitive values are redacted before provider boundaries. + +--- + +### User Story 2 - Serve Trace Investigation APIs (Priority: P1) + +Studio and other authenticated diagnostics clients can query recent traces and retrieve a trace detail model with ordered spans, resource metadata, OTLP logs, and storage diagnostics. + +**Why this priority**: Trace investigation is the main workflow troubleshooting path and must be backend-filtered before Studio renders a waterfall. + +**Independent Test**: Seed or ingest telemetry for a workflow trace and call the trace search/detail APIs with filters for service, resource, trace ID, workflow instance ID, status, text, and time range. + +**Acceptance Scenarios**: + +1. **Given** a trace contains workflow and activity spans, **When** a diagnostics client requests trace detail, **Then** Core returns parent/child span data ordered for a waterfall view. +2. **Given** filters include workflow instance ID or trace ID, **When** trace search is executed, **Then** only matching trace summaries are returned. +3. **Given** the caller lacks the OpenTelemetry diagnostics view permission, **When** the caller requests trace APIs or live updates, **Then** Core denies the request without exposing telemetry. + +--- + +### User Story 3 - Serve Metrics and OTLP Logs (Priority: P2) + +An authenticated diagnostics client can inspect recent OpenTelemetry metric instruments, bounded metric points, OTLP log records, and overflow diagnostics. + +**Why this priority**: Metrics and OTLP logs complement traces and validate that all OpenTelemetry signals are flowing. + +**Independent Test**: Ingest metrics and OTLP logs for multiple resources, query them by resource, instrument, severity, trace/span ID, text, and time range, and verify capacity diagnostics. + +**Acceptance Scenarios**: + +1. **Given** metrics are emitted by multiple services, **When** a client filters by resource or instrument, **Then** Core returns only matching bounded series. +2. **Given** a metric has high-cardinality attributes, **When** capacity is exceeded, **Then** Core drops according to configured policy and reports dropped point counts. +3. **Given** OTLP logs include trace/span IDs, **When** logs are queried by trace/span, **Then** Core returns correlated OTLP log records without merging them into `Elsa.Diagnostics.StructuredLogs`. + +--- + +### User Story 4 - Expose Collector Configuration and Secure Ingestion (Priority: P3) + +A developer can discover active collector endpoints and configure .NET or non-.NET senders using standard OTEL environment variables, while Core protects non-loopback ingestion. + +**Why this priority**: Elsa does not own an Aspire-style launcher, so Core must make active collector configuration discoverable and secure. + +**Independent Test**: Request collector configuration, verify HTTP metadata and nullable/disabled gRPC metadata, configure a sample sender, and verify non-loopback ingestion requires the configured API key header. + +**Acceptance Scenarios**: + +1. **Given** the collector is enabled, **When** a diagnostics client requests collector configuration, **Then** Core returns HTTP endpoint metadata, any enabled gRPC endpoint metadata, required header names, and recommended non-secret environment variables. +2. **Given** gRPC ingestion is unavailable, **When** configuration is requested, **Then** Core marks gRPC disabled instead of returning a misleading endpoint. +3. **Given** OTLP ingestion is exposed beyond loopback, **When** a sender omits the required API key header, **Then** Core rejects the request. + +### Edge Cases + +- OTLP payloads include unsupported future fields or incomplete resource attributes. +- Multiple services share `service.name` but have different `service.instance.id` values. +- A trace arrives out of span order. +- Metrics create more series or points than configured capacity allows. +- Backend restarts and loses in-memory telemetry. +- OTLP logs reference trace/span IDs for traces that have expired. +- gRPC support is not available in the hosting configuration. +- The caller has Studio access but not the OpenTelemetry diagnostics permission. +- A sender posts from loopback while the collector is configured for loopback-only development. +- A sender posts from a non-loopback address without the configured ingestion API key header. +- A live client subscribes with filters that receive more updates than its per-connection queue allows. +- The historical `Elsa.OpenTelemetry` extension package is present in another repository but must not be ported into this module. + +## Requirements *(mandatory)* + +### Functional Requirements + +- **FR-001**: Core MUST introduce an opt-in module under `src/modules/Elsa.Diagnostics.OpenTelemetry`. +- **FR-002**: The module MUST be separate from `Elsa.Diagnostics.StructuredLogs` and `Elsa.Diagnostics.ConsoleLogs`. +- **FR-003**: The module MUST use existing `Elsa.Workflows` `ActivitySource` and `Meter` instrumentation as the producer of Elsa workflow telemetry. +- **FR-004**: The module MUST NOT port the historical `Elsa.OpenTelemetry` producer-side middleware from `elsa-extensions` in v1. +- **FR-005**: The module MUST accept OTLP HTTP/protobuf traces, metrics, and logs. +- **FR-006**: The module SHOULD support OTLP gRPC ingestion when the host has gRPC support enabled; collector metadata MUST represent gRPC as disabled or null when unavailable. +- **FR-007**: HTTP and gRPC ingestion, when both are enabled, MUST feed one shared ingestion contract for normalization, redaction, storage, and live publishing. +- **FR-008**: The module MUST normalize telemetry into bounded queryable models for resources, traces, spans, metrics, and OTLP log records. +- **FR-009**: The default store MUST be bounded in memory and MUST report dropped telemetry counts. +- **FR-010**: Redaction MUST run before telemetry reaches provider storage or live subscribers. +- **FR-011**: Resource identity MUST use OpenTelemetry resource attributes, including service name and service instance ID when present. +- **FR-012**: Workflow and activity telemetry MUST preserve the existing `Elsa.Workflows` semantic attributes when present, including `workflow.instance.id`, `workflow.definition.id`, `workflow.definition.version`, `workflow.definition.version.id`, `workflow.status`, `workflow.substatus`, `workflow.faulted`, `workflow.parent.instance.id`, `workflow.correlation.id`, `workflow.activity.id`, `workflow.activity.name`, `workflow.activity.type`, `workflow.activity.version`, `workflow.activity.execution.id`, `workflow.activity.status`, `workflow.activity.outcome`, `workflow.activity.parent.execution.id`, `workflow.activity.scheduled.by.execution.id`, `workflow.activity.faulted`, `elsa.tenant.id`, and `exception.type`. +- **FR-013**: The module MUST expose authenticated diagnostics APIs for resources, trace search, trace detail, metrics, OTLP logs, storage diagnostics, and collector configuration. +- **FR-014**: The module MUST expose live updates through an authenticated SignalR hub. +- **FR-015**: The module MUST enforce an OpenTelemetry diagnostics view permission for all diagnostics APIs and live connections. +- **FR-016**: Loopback-only development ingestion MAY run without an API key only for loopback requests while the collector is bound to loopback; any non-loopback request or non-loopback collector binding MUST require an explicit API key header or equivalent configured protection. +- **FR-017**: Collector configuration MUST expose standard OTEL environment variable metadata without exposing secret values. +- **FR-018**: The module MUST document that production deployments should generally export to an external OpenTelemetry Collector or observability backend unless Elsa collector capacity and security are deliberately configured. +- **FR-019**: OTLP logs MUST remain separate from `Elsa.Diagnostics.StructuredLogs`; correlation uses trace/span IDs rather than shared storage. +- **FR-020**: The module MUST include tests for ingestion, normalization, redaction, bounded storage, permissions, live updates, collector configuration, and end-to-end workflow export-to-collector timing. +- **FR-021**: In-memory storage defaults MUST be configurable and MUST start with bounded development defaults of at least 500 resources, 2,000 traces, 10,000 spans, 20,000 metric points, 10,000 OTLP log records, and 1,000 queued live updates per subscriber; when a capacity is exceeded, the oldest item in that signal-specific buffer is dropped and the relevant dropped count is incremented. +- **FR-022**: Search APIs MUST return deterministic, bounded result sets with caller-specified limits capped by server options; default ordering is newest receive time first for searches and parent/child chronological ordering for trace detail spans. +- **FR-023**: Live SignalR subscriptions MUST use bounded per-connection queues, update filters in place, drop oldest queued updates on overflow, and publish dropped-update diagnostics without disconnecting healthy subscribers. +- **FR-024**: The diagnostics module MUST NOT start new workflow or activity spans itself and MUST NOT mutate `Activity.Current`; trace production remains owned by existing `Elsa.Workflows.Core` instrumentation. + +### Key Entities + +- **Telemetry Resource**: Resource/service identity derived from OTEL resource attributes. +- **Telemetry Trace**: Trace summary grouped by trace ID. +- **Telemetry Span**: Timed operation inside a trace with attributes, events, links, and status. +- **Metric Instrument**: Metric name, unit, description, type, resource, and bounded series. +- **Metric Point**: Recent data point for a metric series. +- **OTLP Log Record**: Log record received through OTLP and correlated by trace/span IDs. +- **Collector Configuration**: Active endpoint, protocol, security, and environment-variable metadata. +- **Storage Diagnostics**: Capacity and dropped telemetry counters. +- **Telemetry Subscription**: Live SignalR subscription with filters and connection state. +- **Storage Capacity Policy**: Configurable per-signal limits and drop-oldest overflow behavior for in-memory telemetry. + +## Success Criteria *(mandatory)* + +### Measurable Outcomes + +- **SC-001**: A local Core host with OpenTelemetry diagnostics enabled receives workflow trace spans and exposes them through diagnostics APIs within 2 seconds of workflow execution. +- **SC-002**: Core accepts representative OTLP HTTP/protobuf traces, metrics, and logs from standard SDK payloads and returns normalized diagnostics models. +- **SC-003**: Trace detail APIs return at least 100 ordered spans for one trace without unbounded memory growth. +- **SC-004**: Metric APIs return at least 20 instruments and 1,000 recent points while honoring configured capacity. +- **SC-005**: Unauthorized API and hub calls are denied without exposing telemetry. +- **SC-006**: Sensitive configured attribute names and text patterns are redacted before stored telemetry is returned. +- **SC-007**: Collector configuration reports HTTP metadata, nullable/disabled gRPC metadata, and required header names accurately. +- **SC-008**: Capacity tests prove each signal-specific buffer drops oldest telemetry, increments dropped counts, and keeps queries bounded when defaults are exceeded. +- **SC-009**: SignalR tests prove subscriber overflow drops oldest queued live updates, reports dropped-update counts, and keeps the connection usable. + +## Assumptions + +- `Elsa.Workflows.Core` keeps first-party workflow tracing and metrics instrumentation. +- Durable OpenTelemetry persistence is a later provider feature. +- The Studio feature has its own spec in `elsa-studio/specs/008-diagnostics-otel`. +- Core and Studio contracts should remain aligned, but Core is the source of truth for ingestion, permissions, normalization, and API behavior. +- Default in-memory capacities are development-friendly starting points, not production sizing guidance. diff --git a/specs/008-diagnostics-otel/tasks.md b/specs/008-diagnostics-otel/tasks.md new file mode 100644 index 000000000..ca6f798c0 --- /dev/null +++ b/specs/008-diagnostics-otel/tasks.md @@ -0,0 +1,123 @@ +# Tasks: Diagnostics OpenTelemetry + +**Input**: Design documents from `/specs/008-diagnostics-otel/` +**Prerequisites**: [plan.md](./plan.md), [spec.md](./spec.md), [research.md](./research.md), [data-model.md](./data-model.md), [contracts/](./contracts/), [quickstart.md](./quickstart.md) + +**Tests**: Required for ingestion, normalization, redaction, bounded storage, permissions, live updates, collector configuration, and workflow export-to-collector timing. + +## Phase 1: Setup + +- [X] T001 Create Core project skeleton at `src/modules/Elsa.Diagnostics.OpenTelemetry/Elsa.Diagnostics.OpenTelemetry.csproj` +- [X] T002 Create unit test project at `test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Elsa.Diagnostics.OpenTelemetry.UnitTests.csproj` +- [X] T003 Create integration test project at `test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/Elsa.Diagnostics.OpenTelemetry.IntegrationTests.csproj` +- [X] T004 Add project and test projects to `Elsa.sln` +- [X] T005 [P] Add initial module README at `src/modules/Elsa.Diagnostics.OpenTelemetry/README.md` + +--- + +## Phase 2: Foundational + +- [X] T006 Create telemetry resource/span/trace/metric/log/storage models in `src/modules/Elsa.Diagnostics.OpenTelemetry/Models` +- [X] T007 Create filter/result DTOs for resources, traces, metrics, logs, and collector configuration in `src/modules/Elsa.Diagnostics.OpenTelemetry/Models` +- [X] T008 Create provider, store, live feed, ingestor, redactor, and source registry contracts in `src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts` +- [X] T009 Create options in `src/modules/Elsa.Diagnostics.OpenTelemetry/Options/OpenTelemetryDiagnosticsOptions.cs` with configurable capacity defaults, ingestion security, and live subscriber queue settings +- [X] T010 Create permission constants in `src/modules/Elsa.Diagnostics.OpenTelemetry/Permissions/OpenTelemetryPermissions.cs` +- [X] T011 Create feature and shell feature in `src/modules/Elsa.Diagnostics.OpenTelemetry/Features/OpenTelemetryFeature.cs` and `src/modules/Elsa.Diagnostics.OpenTelemetry/ShellFeatures/OpenTelemetryFeature.cs` +- [X] T012 Create DI and endpoint mapping extensions in `src/modules/Elsa.Diagnostics.OpenTelemetry/Extensions` +- [X] T013 Add README note that historical `Elsa.OpenTelemetry` producer middleware is not ported in v1 in `src/modules/Elsa.Diagnostics.OpenTelemetry/README.md` + +--- + +## Phase 3: User Story 1 - Collect OpenTelemetry from Elsa services (Priority: P1) MVP + +**Goal**: Receive OTLP payloads, normalize, redact, store bounded telemetry, and expose basic diagnostics queries. + +**Independent Test**: Ingest OTLP traces/metrics/logs and run an Elsa workflow export-to-collector integration test. + +- [X] T014 [P] [US1] Add OTLP trace normalization tests in `test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Ingestion/OtlpTraceNormalizerTests.cs` +- [X] T015 [P] [US1] Add OTLP metric normalization tests in `test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Ingestion/OtlpMetricNormalizerTests.cs` +- [X] T016 [P] [US1] Add OTLP log normalization tests in `test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Ingestion/OtlpLogNormalizerTests.cs` +- [X] T017 [P] [US1] Add redaction tests in `test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Services/OpenTelemetryRedactorTests.cs` +- [X] T018 [P] [US1] Add bounded store/drop-count tests for default capacities, drop-oldest overflow, and deterministic query limits in `test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/InMemoryOpenTelemetryStoreTests.cs` +- [X] T019 [P] [US1] Add HTTP/protobuf ingestion and workflow export-to-collector timing tests that assert existing `Elsa.Workflows` tags are preserved in `test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/OtlpHttpIngestionTests.cs` +- [X] T020 [US1] Implement HTTP/protobuf request parsing in `src/modules/Elsa.Diagnostics.OpenTelemetry/Ingestion/HttpProtobuf` +- [X] T021 [US1] Implement shared OTLP normalization services in `src/modules/Elsa.Diagnostics.OpenTelemetry/Ingestion` +- [X] T022 [US1] Implement redactor in `src/modules/Elsa.Diagnostics.OpenTelemetry/Services/OpenTelemetryRedactor.cs` +- [X] T023 [US1] Implement source registry in `src/modules/Elsa.Diagnostics.OpenTelemetry/Services/OpenTelemetrySourceRegistry.cs` +- [X] T024 [US1] Implement bounded in-memory store in `src/modules/Elsa.Diagnostics.OpenTelemetry/Providers/InMemory/InMemoryOpenTelemetryStore.cs` +- [X] T025 [US1] Implement provider facade in `src/modules/Elsa.Diagnostics.OpenTelemetry/Services/DefaultOpenTelemetryProvider.cs` +- [X] T026 [US1] Implement HTTP/protobuf endpoint mapping in `src/modules/Elsa.Diagnostics.OpenTelemetry/Extensions/EndpointRouteBuilderExtensions.cs` + +--- + +## Phase 4: User Story 2 - Serve Trace Investigation APIs (Priority: P1) + +**Goal**: Provide authenticated trace search/detail APIs and live updates. + +**Independent Test**: Query traces by service/resource/trace/workflow/status/time and retrieve ordered span detail. + +- [X] T027 [P] [US2] Add trace search/detail provider tests in `test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/OpenTelemetryTraceQueryTests.cs` +- [X] T028 [P] [US2] Add API authorization tests in `test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/OpenTelemetryAuthorizationTests.cs` +- [X] T029 [P] [US2] Add SignalR hub tests for authorization, filter updates, per-subscriber queue overflow, drop-oldest behavior, and dropped-update diagnostics in `test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/OpenTelemetryHubTests.cs` +- [X] T030 [US2] Implement trace search and trace detail query logic in `src/modules/Elsa.Diagnostics.OpenTelemetry/Providers/InMemory/InMemoryOpenTelemetryStore.cs` +- [X] T031 [US2] Implement resource search endpoint in `src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Resources/Endpoint.cs` +- [X] T032 [US2] Implement trace search and detail endpoints in `src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Traces/Endpoint.cs` and `src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Trace/Endpoint.cs` +- [X] T033 [US2] Implement live feed in `src/modules/Elsa.Diagnostics.OpenTelemetry/Providers/InMemory/InMemoryOpenTelemetryLiveFeed.cs` +- [X] T034 [US2] Implement SignalR hub in `src/modules/Elsa.Diagnostics.OpenTelemetry/RealTime/OpenTelemetryHub.cs` + +--- + +## Phase 5: User Story 3 - Serve Metrics and OTLP Logs (Priority: P2) + +**Goal**: Provide bounded metric and OTLP log search APIs with overflow diagnostics. + +**Independent Test**: Ingest metrics/logs, query by filters, and verify dropped counts. + +- [X] T035 [P] [US3] Add metric query tests in `test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/OpenTelemetryMetricQueryTests.cs` +- [X] T036 [P] [US3] Add OTLP log query tests in `test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/OtlpLogQueryTests.cs` +- [X] T037 [US3] Implement metric instrument and point query support in `src/modules/Elsa.Diagnostics.OpenTelemetry/Providers/InMemory/InMemoryOpenTelemetryStore.cs` +- [X] T038 [US3] Implement OTLP log query support in `src/modules/Elsa.Diagnostics.OpenTelemetry/Providers/InMemory/InMemoryOpenTelemetryStore.cs` +- [X] T039 [US3] Implement metrics endpoint in `src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Metrics/Endpoint.cs` +- [X] T040 [US3] Implement OTLP logs endpoint in `src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Logs/Endpoint.cs` +- [X] T041 [US3] Implement storage diagnostics endpoint in `src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Storage/Endpoint.cs` + +--- + +## Phase 6: User Story 4 - Expose Collector Configuration and Secure Ingestion (Priority: P3) + +**Goal**: Provide collector configuration metadata and protect non-loopback ingestion. + +**Independent Test**: Query configuration and verify API key enforcement. + +- [X] T042 [P] [US4] Add collector configuration tests in `test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Services/CollectorConfigurationTests.cs` +- [X] T043 [P] [US4] Add ingestion security tests for loopback-only no-key development, non-loopback request rejection without API key, and non-secret collector metadata in `test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/OtlpIngestionSecurityTests.cs` +- [X] T044 [US4] Implement collector configuration provider in `src/modules/Elsa.Diagnostics.OpenTelemetry/Services/CollectorConfigurationProvider.cs` +- [X] T045 [US4] Implement collector configuration endpoint in `src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/CollectorConfiguration/Endpoint.cs` +- [X] T046 [US4] Implement API key header validation in `src/modules/Elsa.Diagnostics.OpenTelemetry/Ingestion` +- [X] T047 [US4] Add option-gated gRPC wrappers and disabled metadata handling in `src/modules/Elsa.Diagnostics.OpenTelemetry/Ingestion/Grpc` +- [X] T048 [US4] Update workflow OpenTelemetry docs in `doc/wiki/opentelemetry-workflows.md` + +--- + +## Phase 7: Polish and Verification + +- [X] T049 [P] Update module README with routes, permissions, security, scope boundaries, and historical extension decision in `src/modules/Elsa.Diagnostics.OpenTelemetry/README.md` +- [X] T050 [P] Verify no production code references historical producer middleware by running `rg "Elsa.OpenTelemetry|UseWorkflowExecutionTracing|UseActivityExecutionTracing" src test` +- [X] T051 Run `dotnet test test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Elsa.Diagnostics.OpenTelemetry.UnitTests.csproj` +- [X] T052 Run `dotnet test test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/Elsa.Diagnostics.OpenTelemetry.IntegrationTests.csproj` +- [X] T053 Run `dotnet build Elsa.sln` + +## Dependencies + +- Phase 1 precedes all work. +- Phase 2 blocks all user stories. +- US1 is the MVP backend collector slice. +- US2 can begin after Phase 2 with seeded store data; full validation depends on US1. +- US3 depends on US1 storage and normalization. +- US4 depends on endpoint mapping from US1. + +## Notes + +- Keep Studio UI tasks in `elsa-studio/specs/008-diagnostics-otel/tasks.md`. +- Do not port historical `Elsa.OpenTelemetry` middleware in this feature. +- Durable OTEL persistence and vendor exporters are out of scope. diff --git a/specs/010-workflow-json-hardening/checklists/requirements.md b/specs/010-workflow-json-hardening/checklists/requirements.md new file mode 100644 index 000000000..9a990910a --- /dev/null +++ b/specs/010-workflow-json-hardening/checklists/requirements.md @@ -0,0 +1,34 @@ +# Specification Quality Checklist: Workflow JSON Type Hardening + +**Purpose**: Validate specification completeness and quality before proceeding to planning +**Created**: 2026-05-29 +**Feature**: [spec.md](../spec.md) + +## Content Quality + +- [x] No implementation details (languages, frameworks, APIs) +- [x] Focused on user value and business needs +- [x] Written for non-technical stakeholders +- [x] All mandatory sections completed + +## Requirement Completeness + +- [x] No [NEEDS CLARIFICATION] markers remain +- [x] Requirements are testable and unambiguous +- [x] Success criteria are measurable +- [x] Success criteria are technology-agnostic (no implementation details) +- [x] All acceptance scenarios are defined +- [x] Edge cases are identified +- [x] Scope is clearly bounded +- [x] Dependencies and assumptions identified + +## Feature Readiness + +- [x] All functional requirements have clear acceptance criteria +- [x] User scenarios cover primary flows +- [x] Feature meets measurable outcomes defined in Success Criteria +- [x] No implementation details leak into specification + +## Notes + +- Validation passed. The issue explicitly requires a dedicated workflow serialization type registry or resolver; the specification names this capability as a required product behavior while deferring implementation details to planning. diff --git a/specs/010-workflow-json-hardening/contracts/workflow-json-type-identifiers.md b/specs/010-workflow-json-hardening/contracts/workflow-json-type-identifiers.md new file mode 100644 index 000000000..2e39ff815 --- /dev/null +++ b/specs/010-workflow-json-hardening/contracts/workflow-json-type-identifiers.md @@ -0,0 +1,15 @@ +# Contract: Workflow JSON Type Identifiers + +## Identifier Rules + +- New workflow JSON writes aliases when a type is registered with a workflow JSON alias. +- Compatibility reads accept registered aliases and registered legacy names. +- Unknown CLR names are rejected. +- Abstract, interface, open generic, and inappropriate collection targets are rejected for polymorphic object materialization. +- Supported collection aliases are limited to known collection wrappers closed over registered element types. + +## Incident Strategy Descriptor + +`GET /descriptors/incident-strategies` returns `typeName` values from the shared serialization type registry. + +Clients should persist or submit returned `typeName` values unchanged. During the compatibility window, existing CLR names registered as legacy identifiers remain accepted when workflow JSON is read. diff --git a/specs/010-workflow-json-hardening/data-model.md b/specs/010-workflow-json-hardening/data-model.md new file mode 100644 index 000000000..1782d97ec --- /dev/null +++ b/specs/010-workflow-json-hardening/data-model.md @@ -0,0 +1,20 @@ +# Data Model: Workflow JSON Type Hardening + +## SerializationTypeOptions + +- Stores workflow JSON aliases mapped to concrete types. +- Stores optional legacy names mapped to the same concrete types. +- Provides default primitive and JSON island aliases needed by workflow payloads. +- Lives in `Elsa.Common` so non-workflow serialization layers can share the same trust boundary. + +## SerializationTypeRegistry + +- Runtime registry built from `SerializationTypeOptions`. +- Resolves aliases and registered legacy names to types. +- Lists registered types for compatibility resolution. +- Returns preferred aliases for writing new workflow JSON and public descriptor values. + +## Workflow Type Identifier + +- Alias: preferred stable identifier for new workflow JSON. +- Legacy name: supported compatibility identifier for previously persisted workflow JSON or older clients. diff --git a/specs/010-workflow-json-hardening/plan.md b/specs/010-workflow-json-hardening/plan.md new file mode 100644 index 000000000..d68f63df0 --- /dev/null +++ b/specs/010-workflow-json-hardening/plan.md @@ -0,0 +1,88 @@ +# Implementation Plan: Workflow JSON Type Hardening + +**Branch**: `codex/7541-workflow-json-hardening` | **Date**: 2026-05-29 | **Spec**: [spec.md](spec.md) +**Input**: Feature specification from `/specs/010-workflow-json-hardening/spec.md` + +**Note**: This template is filled in by the `/speckit-plan` command. See `.specify/templates/plan-template.md` for the execution workflow. + +## Summary + +Reintroduce workflow JSON hardening through a workflow-specific type registry and resolver. Existing registered legacy CLR names remain readable, new workflow JSON emits aliases when available, and public descriptor APIs use the same identifier contract they accept. + +## Technical Context + + + +**Language/Version**: C# latest with nullable reference types, multi-targeting through existing project settings +**Primary Dependencies**: System.Text.Json, Elsa feature/module infrastructure, existing expression registry for expression-only behavior +**Storage**: Existing workflow JSON payloads only; no schema changes +**Testing**: Targeted `dotnet test` for workflow core/runtime/api test projects +**Target Platform**: Elsa server/library consumers on supported .NET target frameworks +**Project Type**: Modular .NET library and API modules +**Performance Goals**: Type lookup remains dictionary-based and does not add reflection scans to normal serialization +**Constraints**: No arbitrary CLR type loading; compatibility only for explicitly registered workflow JSON legacy names +**Scale/Scope**: Workflow definitions, workflow state, trigger/bookmark payloads, incident strategy descriptor contract, and module/extension registrations + +## Constitution Check + +*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* + +PASS. The change stays inside existing workflow modules, adds one explicit extensibility point for serialization trust, preserves public compatibility, and includes focused tests. No new persistence provider or unrelated module is introduced. + +## Project Structure + +### Documentation (this feature) + +```text +specs/[###-feature]/ +├── plan.md # This file (/speckit-plan command output) +├── research.md # Phase 0 output (/speckit-plan command) +├── data-model.md # Phase 1 output (/speckit-plan command) +├── quickstart.md # Phase 1 output (/speckit-plan command) +├── contracts/ # Phase 1 output (/speckit-plan command) +└── tasks.md # Phase 2 output (/speckit-tasks command - NOT created by /speckit-plan) +``` + +### Source Code (repository root) + + +```text +src/modules/Elsa.Workflows.Core/ +├── Contracts/ +├── Extensions/ +├── Options/ +├── Serialization/ +└── Features/ + +src/modules/Elsa.Workflows.Runtime/ +├── Features/ +├── ShellFeatures/ +└── Services/ + +src/modules/Elsa.Workflows.Api/ +└── Endpoints/IncidentStrategies/ + +test/unit/Elsa.Workflows.Core.UnitTests/ +test/unit/Elsa.Workflows.Runtime.UnitTests/ +test/integration/Elsa.Workflows.IntegrationTests/ +``` + +**Structure Decision**: Extend the existing workflow core serialization surface and update runtime/API registrations in place. Tests stay in the nearest existing workflow test projects. + +## Complexity Tracking + +> **Fill ONLY if Constitution Check has violations that must be justified** + +| Violation | Why Needed | Simpler Alternative Rejected Because | +|-----------|------------|-------------------------------------| +| [e.g., 4th project] | [current need] | [why 3 projects insufficient] | +| [e.g., Repository pattern] | [specific problem] | [why direct DB access insufficient] | diff --git a/specs/010-workflow-json-hardening/quickstart.md b/specs/010-workflow-json-hardening/quickstart.md new file mode 100644 index 000000000..9ea443ee7 --- /dev/null +++ b/specs/010-workflow-json-hardening/quickstart.md @@ -0,0 +1,11 @@ +# Quickstart: Workflow JSON Type Hardening + +1. Register built-in workflow JSON aliases through workflow features. +2. Register module payload aliases through each module that serializes workflow payloads. +3. Verify `TypeJsonConverter` and `PolymorphicObjectConverter` use the shared serialization registry, not expression options. +4. Run targeted tests: + +```sh +dotnet test test/unit/Elsa.Workflows.Core.UnitTests/Elsa.Workflows.Core.UnitTests.csproj --filter SerializationTypeResolverTests +dotnet test test/unit/Elsa.Workflows.Runtime.UnitTests/Elsa.Workflows.Runtime.UnitTests.csproj --filter WorkflowRuntimeFeatureTests +``` diff --git a/specs/010-workflow-json-hardening/research.md b/specs/010-workflow-json-hardening/research.md new file mode 100644 index 000000000..03c83d02f --- /dev/null +++ b/specs/010-workflow-json-hardening/research.md @@ -0,0 +1,25 @@ +# Research: Workflow JSON Type Hardening + +## Decision: Dedicated Workflow JSON Registry + +Use a workflow-specific registry and options object for `TypeJsonConverter`, `PolymorphicObjectConverter`, workflow state serialization, bookmark payload serialization, trigger comparison, hashing, and descriptor contracts. + +**Rationale**: The issue explicitly rejects using `ExpressionOptions` as the workflow JSON trust boundary. A dedicated registry makes the allowed workflow JSON surface explicit while leaving expression aliases available for expression evaluation and designer variable metadata. + +**Alternatives considered**: Reusing `IWellKnownTypeRegistry` was rejected because it is fed by `ExpressionOptions`. Direct `Type.GetType` fallback was rejected because it can load arbitrary CLR names. + +## Decision: Explicit Legacy Compatibility Names + +Compatibility reads accept aliases and registered legacy names, including simple assembly-qualified names, full assembly-qualified names for registered types, and supported collection wrappers over registered element types. + +**Rationale**: Existing persisted workflows may contain CLR names, but the trust boundary must be the registration list, not assembly probing. + +**Alternatives considered**: A broad assembly allow-list was rejected for this slice because it is harder to reason about and can accidentally expose unrelated types from trusted assemblies. + +## Decision: Alias-First Public Descriptor Contract + +Incident strategy descriptors should emit the workflow JSON alias for registered strategies while keeping legacy CLR names readable on input during the compatibility window. + +**Rationale**: The reported dropdown failure came from descriptors returning CLR names while hardened reads expected aliases. Emitting aliases aligns new clients with hardened serialization without breaking old payloads. + +**Alternatives considered**: Keeping CLR names in descriptors was rejected because it perpetuates the inconsistent contract. diff --git a/specs/010-workflow-json-hardening/spec.md b/specs/010-workflow-json-hardening/spec.md new file mode 100644 index 000000000..01ecff726 --- /dev/null +++ b/specs/010-workflow-json-hardening/spec.md @@ -0,0 +1,103 @@ +# Feature Specification: Workflow JSON Type Hardening + +**Feature Branch**: `codex/7541-workflow-json-hardening` +**Created**: 2026-05-29 +**Status**: Draft +**Input**: User description: "GitHub issue #7541: Redo workflow JSON type hardening with dedicated alias design" + +## User Scenarios & Testing *(mandatory)* + +### User Story 1 - Load Existing Workflows Safely (Priority: P1) + +Operators can upgrade Elsa without losing access to persisted workflows whose JSON contains existing type identifiers, including CLR type names emitted by earlier versions. + +**Why this priority**: Backward compatibility is required before hardening can be reintroduced without breaking production workflows. + +**Independent Test**: Load representative persisted workflow JSON that contains legacy type names and verify the workflow can be read while unknown or unsafe type identifiers are rejected. + +**Acceptance Scenarios**: + +1. **Given** a persisted workflow that references a known legacy type name, **When** the workflow is deserialized after upgrade, **Then** the workflow loads successfully. +2. **Given** a persisted workflow that references an unknown or untrusted type name, **When** the workflow is deserialized, **Then** the workflow is rejected with a clear failure instead of resolving arbitrary types. +3. **Given** a persisted workflow that contains abstract, interface, open generic, or collection type identifiers where a concrete workflow type is required, **When** the workflow is deserialized, **Then** the identifier is rejected. + +--- + +### User Story 2 - Use Consistent Type Identifiers in APIs (Priority: P2) + +API consumers receive consistent type identifiers for workflow-facing options such as incident handling strategies and can submit those identifiers back without relying on implementation-specific names. + +**Why this priority**: The reported incident strategy dropdown failure came from inconsistent contracts between API descriptors and hardened workflow JSON reads. + +**Independent Test**: Request descriptor data for incident strategies, select a returned option, and verify a workflow or workflow definition using that option can be accepted and read. + +**Acceptance Scenarios**: + +1. **Given** API descriptor data for incident handling strategies, **When** the options are returned, **Then** every option uses the documented workflow type identifier contract. +2. **Given** a client submits a supported incident strategy identifier from the descriptor payload, **When** the workflow payload is processed, **Then** the identifier resolves to the intended strategy. +3. **Given** older clients submit legacy CLR identifiers during the compatibility window, **When** the workflow payload is processed, **Then** supported legacy identifiers continue to resolve. + +--- + +### User Story 3 - Register Workflow-Serializable Types Explicitly (Priority: P3) + +Module and extension authors can explicitly register the types and legacy names that are valid in workflow serialization payloads without using expression configuration as the trust boundary. + +**Why this priority**: Hardening must be extensible for built-in modules, custom workflow types, runtime payloads, and third-party extensions. + +**Independent Test**: Register a custom workflow-facing type and legacy identifier, then verify alias-based payloads and supported legacy payloads resolve while unrelated types do not. + +**Acceptance Scenarios**: + +1. **Given** a module registers a workflow-serializable type with an alias, **When** workflow JSON references the alias, **Then** the type resolves successfully. +2. **Given** a module registers a supported legacy name for a workflow-serializable type, **When** compatibility JSON references the legacy name, **Then** the type resolves successfully. +3. **Given** a type is registered only for expression use, **When** workflow JSON references it, **Then** workflow JSON resolution does not accept it unless it is also registered for workflow serialization. + +### Edge Cases + +- Legacy JSON references a CLR type moved between assemblies or renamed after earlier persistence. +- Payloads reference unknown, untrusted, abstract, interface, open generic, array, dictionary, or collection types. +- JSON islands contain values that resemble type metadata but should remain normal JSON data. +- Runtime trigger and bookmark payloads include polymorphic values that need the same trust model as workflow definitions. +- Custom workflow types are registered by host applications or extensions after core services are configured. + +## Requirements *(mandatory)* + +### Functional Requirements + +- **FR-001**: The system MUST keep workflow JSON type resolution separate from expression type alias configuration. +- **FR-002**: The system MUST provide a dedicated registry or resolver for workflow-serializable type identifiers. +- **FR-003**: The system MUST allow built-in modules, extensions, and host applications to register workflow-serializable aliases. +- **FR-004**: The system MUST allow supported legacy type names to be registered for backward-compatible reads. +- **FR-005**: The system MUST document which legacy identifiers remain readable during the compatibility window and how unsupported identifiers fail. +- **FR-006**: The system MUST reject unknown, untrusted, abstract, open generic, interface, and inappropriate collection type identifiers when resolving workflow JSON types. +- **FR-007**: The system MUST continue loading existing workflows that reference supported CLR type names during the compatibility window. +- **FR-008**: The system MUST serialize new workflow-facing payloads with the documented type identifier contract where the payload belongs to that contract. +- **FR-009**: The system MUST keep public API payloads that expose workflow type identifiers internally consistent for request and response flows. +- **FR-010**: The system MUST cover the incident handling strategy option flow with a regression test. +- **FR-011**: The system MUST cover persisted workflow JSON, alias JSON, runtime trigger or bookmark payloads, JSON islands, and custom workflow types with tests. +- **FR-012**: The system MUST document the security model, trust boundaries, and migration behavior before hardened resolution is reintroduced. + +### Key Entities *(include if feature involves data)* + +- **Workflow Type Identifier**: A stable value used in workflow-facing JSON or API payloads to identify an allowed type. +- **Workflow-Serializable Type Registration**: A trusted registration that maps a workflow type identifier and optional legacy names to a concrete allowed type. +- **Compatibility Window**: The supported period or mode in which selected legacy CLR type names remain readable. +- **Public Type Identifier Contract**: The documented request and response behavior for API payloads that expose workflow type identifiers. + +## Success Criteria *(mandatory)* + +### Measurable Outcomes + +- **SC-001**: All representative legacy workflow JSON fixtures covered by tests load successfully when they use supported legacy identifiers. +- **SC-002**: Tests demonstrate rejection for unknown, untrusted, abstract, interface, open generic, and inappropriate collection type identifiers. +- **SC-003**: Incident strategy descriptor and submit flows pass a regression test that uses the same identifier contract in both directions. +- **SC-004**: New workflow JSON hardening tests run without depending on expression type alias configuration. +- **SC-005**: Documentation explains the trust model and compatibility behavior clearly enough for module authors to register workflow-serializable types without reading implementation code. + +## Assumptions + +- The compatibility window accepts known Elsa workflow-related CLR type names and explicitly registered host or extension legacy names, not arbitrary CLR resolution. +- Public API type identifier changes can be transitional: aliases are preferred for new payloads while supported legacy values remain readable. +- Existing workflow JSON fixtures are sufficient to represent persisted workflow compatibility risks, with new fixtures added where gaps are found. +- Cloud vault, external migration tooling, and data store schema changes are outside this feature unless existing tests prove they are required. diff --git a/specs/010-workflow-json-hardening/tasks.md b/specs/010-workflow-json-hardening/tasks.md new file mode 100644 index 000000000..00ec64244 --- /dev/null +++ b/specs/010-workflow-json-hardening/tasks.md @@ -0,0 +1,125 @@ +# Tasks: Workflow JSON Type Hardening + +**Input**: Design documents from `/specs/010-workflow-json-hardening/` +**Prerequisites**: plan.md, spec.md, research.md, data-model.md, contracts/ + +**Tests**: Required by the feature specification for compatibility, rejection behavior, incident strategies, runtime payloads, JSON islands, and custom workflow types. + +## Phase 1: Setup (Shared Infrastructure) + +**Purpose**: Confirm the clean worktree and documentation context. + +- [x] T001 Verify the dedicated worktree status in `/Users/sipke/Projects/Elsa/elsa-core-7541` +- [x] T002 Update Spec Kit agent context in `/Users/sipke/Projects/Elsa/elsa-core-7541/AGENTS.md` + +--- + +## Phase 2: Foundational (Blocking Prerequisites) + +**Purpose**: Add the dedicated workflow JSON trust boundary before changing user-facing behavior. + +- [x] T003 Add serialization type registry contracts in `src/modules/Elsa.Common/Serialization/ISerializationTypeRegistry.cs` +- [x] T004 Add serialization type options in `src/modules/Elsa.Common/Serialization/SerializationTypeOptions.cs` +- [x] T005 Add serialization type registry implementation in `src/modules/Elsa.Common/Serialization/SerializationTypeRegistry.cs` +- [x] T006 Add workflow JSON registration extensions in `src/modules/Elsa.Common/Extensions/SerializationTypeOptionsExtensions.cs` +- [x] T007 Update workflow JSON resolver to use the dedicated registry in `src/modules/Elsa.Common/Serialization/SerializationTypeResolver.cs` +- [x] T008 Update workflow type converters to use the dedicated registry in `src/modules/Elsa.Workflows.Core/Serialization/Converters/TypeJsonConverter.cs`, `src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicObjectConverter.cs`, `src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicObjectConverterFactory.cs`, and `src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicDictionaryConverter.cs` + +**Checkpoint**: Workflow JSON converters no longer depend on `ExpressionOptions`. + +--- + +## Phase 3: User Story 1 - Load Existing Workflows Safely (Priority: P1) MVP + +**Goal**: Existing registered CLR type names remain readable while unsafe names fail. + +**Independent Test**: Deserialize legacy workflow JSON/type payloads with registered names and verify unsafe identifiers are rejected. + +### Tests for User Story 1 + +- [x] T009 [US1] Update resolver tests for dedicated registry compatibility in `test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/SerializationTypeResolverTests.cs` +- [x] T010 [US1] Add regression coverage for expression-only aliases not being accepted by workflow JSON in `test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/SerializationTypeResolverTests.cs` + +### Implementation for User Story 1 + +- [x] T011 [US1] Register core workflow JSON aliases and legacy names in `src/modules/Elsa.Workflows.Core/Features/WorkflowsFeature.cs` and `src/modules/Elsa.Workflows.Core/ShellFeatures/WorkflowsFeature.cs` +- [x] T012 [US1] Update workflow serializers and hashing to consume `ISerializationTypeRegistry` in `src/modules/Elsa.Workflows.Core/Serialization/Serializers/JsonWorkflowStateSerializer.cs`, `src/modules/Elsa.Workflows.Core/Serialization/Serializers/SafeSerializer.cs`, `src/modules/Elsa.Workflows.Core/Serialization/Serializers/BookmarkPayloadSerializer.cs`, and `src/modules/Elsa.Workflows.Core/Services/Hasher.cs` + +**Checkpoint**: User Story 1 can be validated independently. + +--- + +## Phase 4: User Story 2 - Use Consistent Type Identifiers in APIs (Priority: P2) + +**Goal**: Incident strategy descriptors emit the same workflow type identifiers that workflow JSON accepts. + +**Independent Test**: Descriptor output for incident strategies returns aliases and supported legacy identifiers remain readable. + +### Tests for User Story 2 + +- [x] T013 [US2] Add incident strategy descriptor regression tests in `test/unit/Elsa.Workflows.Api.UnitTests/Endpoints/IncidentStrategies/ListTests.cs` + +### Implementation for User Story 2 + +- [x] T014 [US2] Register incident strategy aliases and legacy names in `src/modules/Elsa.Workflows.Core/Features/WorkflowsFeature.cs` and `src/modules/Elsa.Workflows.Core/ShellFeatures/WorkflowsFeature.cs` +- [x] T015 [US2] Emit workflow JSON aliases from incident strategy descriptors in `src/modules/Elsa.Workflows.Api/Endpoints/IncidentStrategies/List/Endpoint.cs` +- [x] T016 [US2] Update client model documentation for identifier semantics in `src/clients/Elsa.Api.Client/Resources/IncidentStrategies/Models/IncidentStrategyDescriptor.cs` + +**Checkpoint**: User Story 2 can be validated independently. + +--- + +## Phase 5: User Story 3 - Register Workflow-Serializable Types Explicitly (Priority: P3) + +**Goal**: Modules and host applications register workflow JSON types without using expression options. + +**Independent Test**: Runtime and extension payloads resolve from workflow JSON registrations while expression-only aliases do not. + +### Tests for User Story 3 + +- [x] T017 [US3] Update runtime feature tests for workflow JSON registrations in `test/unit/Elsa.Workflows.Runtime.UnitTests/Features/WorkflowRuntimeFeatureTests.cs` +- [x] T018 [US3] Update runtime trigger comparer tests for the dedicated registry in `test/unit/Elsa.Workflows.Runtime.UnitTests/Comparers/WorkflowTriggerEqualityComparerTests.cs` + +### Implementation for User Story 3 + +- [x] T019 [US3] Move runtime workflow payload registration to workflow JSON options in `src/modules/Elsa.Workflows.Runtime/WorkflowRuntimeTypeAliasRegistrar.cs`, `src/modules/Elsa.Workflows.Runtime/Features/WorkflowRuntimeFeature.cs`, and `src/modules/Elsa.Workflows.Runtime/ShellFeatures/WorkflowRuntimeFeature.cs` +- [x] T020 [US3] Move module payload registrations to workflow JSON options in `src/modules/Elsa.Http/Features/HttpFeature.cs`, `src/modules/Elsa.Http/ShellFeatures/HttpFeature.cs`, `src/modules/Elsa.Scheduling/Features/SchedulingFeature.cs`, `src/modules/Elsa.Resilience/Features/ResilienceFeature.cs`, `src/modules/Elsa.Resilience/ShellFeatures/ResilienceFeature.cs`, `src/modules/Elsa.Alterations/Features/AlterationsFeature.cs`, `src/modules/Elsa.Persistence.EFCore/Modules/Management/WorkflowDefinitionPersistenceFeature.cs`, and `src/modules/Elsa.Workflows.Management/Features/WorkflowManagementFeature.cs` +- [x] T021 [US3] Update runtime trigger comparison to use `ISerializationTypeRegistry` in `src/modules/Elsa.Workflows.Runtime/Comparers/WorkflowTriggerEqualityComparer.cs` and `src/modules/Elsa.Workflows.Runtime/Services/TriggerIndexer.cs` + +**Checkpoint**: User Story 3 can be validated independently. + +--- + +## Phase 6: Polish & Cross-Cutting Concerns + +**Purpose**: Documentation and validation. + +- [x] T022 Add workflow JSON hardening documentation in `doc/wiki/workflow-core.md` +- [x] T023 Run targeted workflow core unit tests with `dotnet test test/unit/Elsa.Workflows.Core.UnitTests/Elsa.Workflows.Core.UnitTests.csproj --filter SerializationTypeResolverTests` +- [x] T024 Run targeted workflow runtime unit tests with `dotnet test test/unit/Elsa.Workflows.Runtime.UnitTests/Elsa.Workflows.Runtime.UnitTests.csproj --filter WorkflowRuntimeFeatureTests` +- [x] T025 Review changed files and ensure `.specify/feature.json` and Spec Kit artifacts are correct + +--- + +## Dependencies & Execution Order + +- **Setup**: T001-T002 first. +- **Foundational**: T003-T008 block all user stories. +- **US1**: T009-T012 produces the MVP compatibility slice. +- **US2**: T013-T016 depends on the registry from Foundational and may run after US1. +- **US3**: T017-T021 depends on the registry from Foundational and may run after US1. +- **Polish**: T022-T025 after implementation. + +## Parallel Opportunities + +- Test updates in T009, T013, T017, and T018 can be developed in parallel after T003-T008. +- Module registration moves in T020 can be parallelized by module after the extension API exists. +- Documentation T022 can run after the contract behavior is finalized. + +## Implementation Strategy + +1. Establish the dedicated registry and switch converters. +2. Preserve legacy compatibility for existing workflow JSON. +3. Align incident strategy API descriptors with the registry. +4. Move runtime/module payload registrations off expression options. +5. Validate with targeted tests and documentation. diff --git a/src/apps/Elsa.ModularServer.Web/Elsa.ModularServer.Web.csproj b/src/apps/Elsa.ModularServer.Web/Elsa.ModularServer.Web.csproj index ae9991352..cbb44d3ba 100644 --- a/src/apps/Elsa.ModularServer.Web/Elsa.ModularServer.Web.csproj +++ b/src/apps/Elsa.ModularServer.Web/Elsa.ModularServer.Web.csproj @@ -5,9 +5,14 @@ + + + + + diff --git a/src/apps/Elsa.ModularServer.Web/Program.cs b/src/apps/Elsa.ModularServer.Web/Program.cs index 981f34116..f27fae972 100644 --- a/src/apps/Elsa.ModularServer.Web/Program.cs +++ b/src/apps/Elsa.ModularServer.Web/Program.cs @@ -2,8 +2,6 @@ using ConsoleLogStreaming.Core.Capture; using CShells.AspNetCore.Configuration; using CShells.AspNetCore.Extensions; using CShells.DependencyInjection; -using Elsa.Diagnostics.ConsoleLogs.Extensions; -using Elsa.Diagnostics.ConsoleLogs.Services; using Elsa.ModularServer.Web; using Elsa.ModularServer.Web.Catalog; using Elsa.ShellFeatures; @@ -12,23 +10,44 @@ using Elsa.Workflows.Management.ShellFeatures; using Elsa.Workflows.Runtime.Distributed.ShellFeatures; using Elsa.Workflows.Runtime.ShellFeatures; using Elsa.Workflows.ShellFeatures; +using Elsa.Workflows.Telemetry; using Nuplane; using Nuplane.Loading.Hosting.Builder; using Nuplane.Sources.Directory.Configuration; +using OpenTelemetry.Exporter; +using OpenTelemetry.Logs; +using OpenTelemetry.Metrics; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; -// Install the console stream tee as early as possible — before WebApplication.CreateBuilder and -// any logger provider construction — so that downstream loggers (Microsoft.Extensions.Logging.Console, -// Kestrel/Hosting loggers, etc.) capture our tee writer instead of the raw Console.Out / Console.Error. ConsoleStreamHook.Install(); var builder = WebApplication.CreateBuilder(args); var services = builder.Services; var configuration = builder.Configuration; +var serviceVersion = typeof(Program).Assembly.GetName().Version?.ToString(); -// Console output is a single process-wide resource; the capture pipeline is owned by the root host so -// every shell's diagnostics endpoints (REST + SignalR) read from the same in-memory ring buffer. -services.AddConsoleLogsHost(); +builder.Logging.AddOpenTelemetry(logging => +{ + logging.IncludeFormattedMessage = true; + logging.IncludeScopes = true; + logging.ParseStateValues = true; + logging.SetResourceBuilder(CreateOpenTelemetryResource(builder.Environment.ApplicationName, serviceVersion)); + logging.AddOtlpExporter(options => ConfigureDiagnosticsOtlpExporter(options, configuration, "logs")); +}); +services.AddOpenTelemetry() + .ConfigureResource(resource => resource.AddService(builder.Environment.ApplicationName, serviceVersion: serviceVersion)) + .WithTracing(tracing => tracing + .AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation() + .AddSource(WorkflowInstrumentation.ActivitySourceName) + .AddOtlpExporter(options => ConfigureDiagnosticsOtlpExporter(options, configuration, "traces"))) + .WithMetrics(metrics => metrics + .AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation() + .AddMeter(WorkflowInstrumentation.MeterName) + .AddOtlpExporter(options => ConfigureDiagnosticsOtlpExporter(options, configuration, "metrics"))); var nuplaneConfiguration = configuration.GetSection("Nuplane"); services.AddNuplane(nuplaneConfiguration, nuplane => @@ -71,3 +90,39 @@ app.UseAuthentication(); app.UseAuthorization(); app.MapSampleCatalog(); app.Run(); + +static ResourceBuilder CreateOpenTelemetryResource(string serviceName, string? serviceVersion) +{ + return ResourceBuilder.CreateDefault().AddService(serviceName, serviceVersion: serviceVersion); +} + +static void ConfigureDiagnosticsOtlpExporter(OtlpExporterOptions options, IConfiguration configuration, string signal) +{ + var protocol = configuration["Diagnostics:OpenTelemetry:Exporter:Protocol"]; + options.Protocol = protocol?.Trim().ToLowerInvariant() switch + { + "grpc" => OtlpExportProtocol.Grpc, + "http/protobuf" or "httpprotobuf" => OtlpExportProtocol.HttpProtobuf, + _ => options.Protocol + }; + + var endpoint = configuration["Diagnostics:OpenTelemetry:Exporter:Endpoint"]; + if (!string.IsNullOrWhiteSpace(endpoint)) + options.Endpoint = new Uri(GetSignalEndpoint(endpoint, signal, options.Protocol), UriKind.Absolute); +} + +static string GetSignalEndpoint(string endpoint, string signal, OtlpExportProtocol protocol) +{ + if (protocol != OtlpExportProtocol.HttpProtobuf) + return endpoint; + + var trimmed = endpoint.TrimEnd('/'); + + if (trimmed.EndsWith($"/v1/{signal}", StringComparison.OrdinalIgnoreCase)) + return trimmed; + + if (trimmed.EndsWith("/v1", StringComparison.OrdinalIgnoreCase)) + return $"{trimmed}/{signal}"; + + return $"{trimmed}/v1/{signal}"; +} diff --git a/src/apps/Elsa.ModularServer.Web/Properties/launchSettings.json b/src/apps/Elsa.ModularServer.Web/Properties/launchSettings.json index 2d8d243e8..cb36e8242 100644 --- a/src/apps/Elsa.ModularServer.Web/Properties/launchSettings.json +++ b/src/apps/Elsa.ModularServer.Web/Properties/launchSettings.json @@ -7,7 +7,10 @@ "launchBrowser": true, "applicationUrl": "http://localhost:5002", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" + "ASPNETCORE_ENVIRONMENT": "Development", + "OTEL_SERVICE_NAME": "Elsa.ModularServer.Web", + "Diagnostics__OpenTelemetry__Exporter__Endpoint": "http://localhost:5002/elsa/otlp", + "Diagnostics__OpenTelemetry__Exporter__Protocol": "http/protobuf" } }, "https": { @@ -16,7 +19,34 @@ "launchBrowser": true, "applicationUrl": "https://localhost:7294;http://localhost:5002", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" + "ASPNETCORE_ENVIRONMENT": "Development", + "OTEL_SERVICE_NAME": "Elsa.ModularServer.Web", + "Diagnostics__OpenTelemetry__Exporter__Endpoint": "https://localhost:7294/elsa/otlp", + "Diagnostics__OpenTelemetry__Exporter__Protocol": "http/protobuf" + } + }, + "http-aspire": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:5002", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "OTEL_SERVICE_NAME": "Elsa.ModularServer.Web", + "Diagnostics__OpenTelemetry__Exporter__Endpoint": "http://localhost:4317", + "Diagnostics__OpenTelemetry__Exporter__Protocol": "grpc" + } + }, + "https-aspire": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:7294;http://localhost:5002", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "OTEL_SERVICE_NAME": "Elsa.ModularServer.Web", + "Diagnostics__OpenTelemetry__Exporter__Endpoint": "http://localhost:4317", + "Diagnostics__OpenTelemetry__Exporter__Protocol": "grpc" } } } diff --git a/src/apps/Elsa.ModularServer.Web/appsettings.json b/src/apps/Elsa.ModularServer.Web/appsettings.json index 3b0d7ad3e..d7e3f4a0f 100644 --- a/src/apps/Elsa.ModularServer.Web/appsettings.json +++ b/src/apps/Elsa.ModularServer.Web/appsettings.json @@ -4,7 +4,8 @@ "Default": "Information", "Microsoft.AspNetCore": "Warning", "Microsoft.EntityFrameworkCore": "Warning", - "Nuplane": "Warning" + "Nuplane": "Warning", + "CShells": "Warning" }, "Console": { "FormatterOptions": { @@ -12,6 +13,14 @@ } } }, + "Diagnostics": { + "OpenTelemetry": { + "Exporter": { + "Endpoint": "http://localhost:5002/elsa/otlp", + "Protocol": "http/protobuf" + } + } + }, "AllowedHosts": "*", "CShells": { "Shells": { @@ -44,6 +53,11 @@ }, "StructuredLogs": {}, "ConsoleLogs": {}, + "OpenTelemetry": {}, + "Alterations": {}, + "SqliteAlterationsPersistence": { + "ConnectionString": "Data Source=elsa_workflows.db;Cache=Shared" + }, "SqliteStructuredLogPersistence": { "ConnectionString": "Data Source=elsa_logs.db;Cache=Shared" }, diff --git a/src/clients/Elsa.Api.Client/Resources/ActivityExecutions/Contracts/IActivityExecutionsApi.cs b/src/clients/Elsa.Api.Client/Resources/ActivityExecutions/Contracts/IActivityExecutionsApi.cs index 65266fb05..4535cebda 100644 --- a/src/clients/Elsa.Api.Client/Resources/ActivityExecutions/Contracts/IActivityExecutionsApi.cs +++ b/src/clients/Elsa.Api.Client/Resources/ActivityExecutions/Contracts/IActivityExecutionsApi.cs @@ -43,8 +43,8 @@ public interface IActivityExecutionsApi /// The ID of the activity execution. /// An optional cancellation token. /// The activity execution. - [Get("/activity-executions/{id}")] - Task GetAsync(string id, CancellationToken cancellationToken = default); + [Get("/activity-executions/by-id")] + Task GetAsync([Query] string id, CancellationToken cancellationToken = default); /// /// Gets the call stack (execution chain) for a given activity execution. diff --git a/src/clients/Elsa.Api.Client/Resources/IncidentStrategies/Models/IncidentStrategyDescriptor.cs b/src/clients/Elsa.Api.Client/Resources/IncidentStrategies/Models/IncidentStrategyDescriptor.cs index fc401f354..657396a88 100644 --- a/src/clients/Elsa.Api.Client/Resources/IncidentStrategies/Models/IncidentStrategyDescriptor.cs +++ b/src/clients/Elsa.Api.Client/Resources/IncidentStrategies/Models/IncidentStrategyDescriptor.cs @@ -3,7 +3,7 @@ namespace Elsa.Api.Client.Resources.IncidentStrategies.Models; /// /// Represents an incident strategy. /// -/// The .NET type name of the strategy. +/// The workflow JSON type identifier of the strategy. /// The display name of the strategy. /// The description of the strategy. -public record IncidentStrategyDescriptor(string TypeName, string DisplayName, string? Description); \ No newline at end of file +public record IncidentStrategyDescriptor(string TypeName, string DisplayName, string? Description); diff --git a/src/common/Elsa.Mediator/CommandStrategies/BackgroundStrategy.cs b/src/common/Elsa.Mediator/CommandStrategies/BackgroundStrategy.cs index 8d4210e05..860a72478 100644 --- a/src/common/Elsa.Mediator/CommandStrategies/BackgroundStrategy.cs +++ b/src/common/Elsa.Mediator/CommandStrategies/BackgroundStrategy.cs @@ -1,5 +1,6 @@ using Elsa.Mediator.Contexts; using Elsa.Mediator.Contracts; +using Elsa.Mediator.Middleware.Command; using Microsoft.Extensions.DependencyInjection; namespace Elsa.Mediator.CommandStrategies; @@ -13,7 +14,15 @@ public class BackgroundStrategy : ICommandStrategy public async Task ExecuteAsync(CommandStrategyContext context) { var commandsChannel = context.ServiceProvider.GetRequiredService(); - await commandsChannel.Writer.WriteAsync(context.CommandContext, context.CancellationToken); + var commandContext = context.CommandContext; + var queuedContext = new CommandContext( + commandContext.Command, + CommandStrategy.Default, + commandContext.ResultType, + commandContext.Headers, + commandContext.ServiceProvider, + CancellationToken.None); + await commandsChannel.Writer.WriteAsync(queuedContext, context.CancellationToken); return default!; } -} \ No newline at end of file +} diff --git a/src/common/Elsa.Mediator/Extensions/DependencyInjectionExtensions.cs b/src/common/Elsa.Mediator/Extensions/DependencyInjectionExtensions.cs index 68ea123d8..04f4f0ba9 100644 --- a/src/common/Elsa.Mediator/Extensions/DependencyInjectionExtensions.cs +++ b/src/common/Elsa.Mediator/Extensions/DependencyInjectionExtensions.cs @@ -48,15 +48,28 @@ public static class DependencyInjectionExtensions /// /// public static IServiceCollection AddMediatorHostedServices(this IServiceCollection services) + { + return services + .AddMediatorBackgroundChannels() + .AddHostedService() + .AddHostedService() + .AddHostedService(); + } + + /// + /// Adds mediator background processing channels to the . + /// + public static IServiceCollection AddMediatorBackgroundChannels(this IServiceCollection services) { return services .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() - .AddHostedService() - .AddHostedService() - .AddHostedService(); + .AddSingleton() + .AddSingleton() + .AddSingleton() + ; } /// @@ -225,4 +238,4 @@ public static class DependencyInjectionExtensions private static Channel CreateChannel() => Channel.CreateUnbounded(new UnboundedChannelOptions()); private static ChannelReader CreateChannelReader(IServiceProvider serviceProvider) => serviceProvider.GetRequiredService>().Reader; private static ChannelWriter CreateChannelWriter(IServiceProvider serviceProvider) => serviceProvider.GetRequiredService>().Writer; -} \ No newline at end of file +} diff --git a/src/common/Elsa.Mediator/HostedServices/BackgroundCommandSenderHostedService.cs b/src/common/Elsa.Mediator/HostedServices/BackgroundCommandSenderHostedService.cs index d8aa66be5..f75125a1c 100644 --- a/src/common/Elsa.Mediator/HostedServices/BackgroundCommandSenderHostedService.cs +++ b/src/common/Elsa.Mediator/HostedServices/BackgroundCommandSenderHostedService.cs @@ -1,103 +1,20 @@ -using System.Threading.Channels; -using Elsa.Mediator.Contracts; -using Elsa.Mediator.Middleware.Command; -using Elsa.Mediator.Options; -using Microsoft.Extensions.DependencyInjection; +using Elsa.Mediator.Services; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; namespace Elsa.Mediator.HostedServices; /// -/// Continuously reads from a channel to which commands can be sent, executing each received command. +/// Hosted service adapter for . /// -public class BackgroundCommandSenderHostedService : BackgroundService +public class BackgroundCommandSenderHostedService(BackgroundCommandProcessor processor) : BackgroundService { - private readonly int _workerCount; - private readonly ICommandsChannel _commandsChannel; - private readonly IServiceScopeFactory _scopeFactory; - private readonly List> _outputs; - private readonly ILogger _logger; - - /// - public BackgroundCommandSenderHostedService(IOptions options, ICommandsChannel commandsChannel, IServiceScopeFactory scopeFactory, ILogger logger) + /// + /// Initializes a new instance of the class. + /// + public BackgroundCommandSenderHostedService(BackgroundCommandProcessor processor, int workerCount) : this(processor) { - _workerCount = options.Value.CommandWorkerCount; - _commandsChannel = commandsChannel; // The shared input channel for all commands - _scopeFactory = scopeFactory; - _logger = logger; - _outputs = new(_workerCount); // Prepare a list to hold worker-specific channels } /// - protected override async Task ExecuteAsync(CancellationToken cancellationToken) - { - var index = 0; // Used for round-robin distribution of work - - // Set up worker channels and start background tasks for each worker - for (var i = 0; i < _workerCount; i++) - { - var output = Channel.CreateUnbounded(); - _outputs.Add(output); - // Start a background task that processes commands from this worker's channel - _ = ReadOutputAsync(output, cancellationToken); - } - - // Main dispatcher loop: read from the input channel and distribute to worker channels - try - { - await foreach (var commandContext in _commandsChannel.Reader.ReadAllAsync(cancellationToken)) - { - var output = _outputs[index]; - await output.Writer.WriteAsync(commandContext, cancellationToken); - // Round-robin distribution - move to next worker - index = (index + 1) % _workerCount; - } - } - catch (OperationCanceledException ex) - { - _logger.LogDebug(ex, "An operation was cancelled while processing the queue"); - } - - // If the input channel is completed, complete all worker channels - foreach (var output in _outputs) - output.Writer.Complete(); - } - - private async Task ReadOutputAsync(Channel output, CancellationToken cancellationToken) - { - // Worker task: process commands from the worker's channel - try - { - await foreach (var commandContext in output.Reader.ReadAllAsync(cancellationToken)) - { - try - { - // Create a fresh scope for each command to ensure proper service lifetime - using var scope = _scopeFactory.CreateScope(); - var commandSender = scope.ServiceProvider.GetRequiredService(); - - // Decouple from the caller's CancellationToken. - // We use only the service's cancellationToken (the background worker's lifetime) - // to ensure that dispatched workflows are processed even if the original - // HTTP request or triggering context has timed out. - await commandSender.SendAsync( - commandContext.Command, - CommandStrategy.Default, - commandContext.Headers, - cancellationToken); - } - catch (Exception e) - { - // Log errors but continue processing other commands - _logger.LogError(e, "An unhandled exception occurred while processing the queue"); - } - } - } - catch (OperationCanceledException ex) - { - _logger.LogDebug(ex, "An operation was cancelled while processing the queue"); - } - } -} \ No newline at end of file + protected override Task ExecuteAsync(CancellationToken stoppingToken) => processor.ExecuteAsync(stoppingToken); +} diff --git a/src/common/Elsa.Mediator/HostedServices/BackgroundEventPublisherHostedService.cs b/src/common/Elsa.Mediator/HostedServices/BackgroundEventPublisherHostedService.cs index 9bb516bdf..411039b69 100644 --- a/src/common/Elsa.Mediator/HostedServices/BackgroundEventPublisherHostedService.cs +++ b/src/common/Elsa.Mediator/HostedServices/BackgroundEventPublisherHostedService.cs @@ -1,111 +1,20 @@ -using System.Threading.Channels; -using Elsa.Mediator.Contracts; -using Elsa.Mediator.Middleware.Notification; -using Elsa.Mediator.Options; -using Microsoft.Extensions.DependencyInjection; +using Elsa.Mediator.Services; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; namespace Elsa.Mediator.HostedServices; /// -/// Continuously reads from a channel to which notifications can be sent, publishing each received notification. +/// Hosted service adapter for . /// -public class BackgroundEventPublisherHostedService : BackgroundService +public class BackgroundEventPublisherHostedService(BackgroundNotificationProcessor processor) : BackgroundService { - private readonly int _workerCount; - private readonly INotificationsChannel _notificationsChannel; - private readonly IServiceScopeFactory _scopeFactory; - private readonly List> _outputs; - private readonly ILogger _logger; - - /// - public BackgroundEventPublisherHostedService(IOptions options, INotificationsChannel notificationsChannel, IServiceScopeFactory scopeFactory, ILogger logger) - { - _workerCount = options.Value.NotificationWorkerCount; - _notificationsChannel = notificationsChannel; - _scopeFactory = scopeFactory; - _logger = logger; - _outputs = new(_workerCount); - } - - /// - protected override async Task ExecuteAsync(CancellationToken cancellationToken) - { - // Index to round-robin distribute notifications across worker channels - var index = 0; - - using var scope = _scopeFactory.CreateScope(); - var notificationSender = scope.ServiceProvider.GetRequiredService(); - - // Create multiple output channels and start worker tasks for parallel processing - for (var i = 0; i < _workerCount; i++) - { - var output = Channel.CreateUnbounded(); - _outputs.Add(output); - // Start a background task to process notifications from this output channel - _ = ReadOutputAsync(output, notificationSender, cancellationToken); - } - - var channelReader = _notificationsChannel.Reader; - - // Continuously read notifications from the input channel and distribute them to worker channels - // using round-robin distribution for load balancing - try - { - await foreach (var notification in channelReader.ReadAllAsync(cancellationToken)) - { - var output = _outputs[index]; - await output.Writer.WriteAsync(notification, cancellationToken); - // Move to the next worker in a circular fashion - index = (index + 1) % _workerCount; - } - } - catch (OperationCanceledException ex) - { - _logger.LogDebug(ex, "An operation was cancelled while processing the queue"); - } - - // When the input channel is completed, complete all output channels - foreach (var output in _outputs) - { - output.Writer.Complete(); - } - } - /// - /// Processes notifications from an output channel asynchronously. + /// Initializes a new instance of the class. /// - /// The channel to read notifications from - /// The service used to send notifications - /// Cancellation token from the hosted service - private async Task ReadOutputAsync(Channel output, INotificationSender notificationSender, CancellationToken cancellationToken) + public BackgroundEventPublisherHostedService(BackgroundNotificationProcessor processor, int workerCount) : this(processor) { - try - { - await foreach (var notificationContext in output.Reader.ReadAllAsync(cancellationToken)) - { - try - { - var notification = notificationContext.Notification; - // Link the cancellation tokens so that cancellation can happen from either source - using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, notificationContext.CancellationToken); - await notificationSender.SendAsync(notification, NotificationStrategy.Sequential, linkedTokenSource.Token); - } - catch (OperationCanceledException e) - { - _logger.LogDebug(e, "An operation was cancelled while processing the queue"); - } - catch (Exception e) - { - _logger.LogError(e, "An unhandled exception occurred while processing the queue"); - } - } - } - catch (OperationCanceledException ex) - { - _logger.LogDebug(ex, "An operation was cancelled while processing the queue"); - } } -} \ No newline at end of file + + /// + protected override Task ExecuteAsync(CancellationToken stoppingToken) => processor.ExecuteAsync(stoppingToken); +} diff --git a/src/common/Elsa.Mediator/HostedServices/JobRunnerHostedService.cs b/src/common/Elsa.Mediator/HostedServices/JobRunnerHostedService.cs index 14af18b4b..603f83f89 100644 --- a/src/common/Elsa.Mediator/HostedServices/JobRunnerHostedService.cs +++ b/src/common/Elsa.Mediator/HostedServices/JobRunnerHostedService.cs @@ -1,71 +1,13 @@ -using Elsa.Mediator.Contracts; -using Elsa.Mediator.Options; +using Elsa.Mediator.Services; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; namespace Elsa.Mediator.HostedServices; /// -/// A hosted service that runs jobs. +/// Hosted service adapter for . /// -public class JobRunnerHostedService : BackgroundService +public class JobRunnerHostedService(BackgroundJobProcessor processor) : BackgroundService { - private readonly int _workerCount; - private readonly IJobsChannel _jobsChannel; - private readonly ILogger _logger; - /// - public JobRunnerHostedService(IOptions options, IJobsChannel jobsChannel, ILogger logger) - { - _workerCount = options.Value.JobWorkerCount; - _jobsChannel = jobsChannel; - _logger = logger; - } - - /// - protected override async Task ExecuteAsync(CancellationToken stoppingToken) - { - // Create an array of worker tasks to process jobs in parallel - var workers = new Task[_workerCount]; - - // Start multiple workers (tasks) to process jobs concurrently - for (var i = 0; i < _workerCount; i++) - workers[i] = ProcessJobsAsync(stoppingToken); - - // Wait for all worker tasks to complete (typically when the application is shutting down) - await Task.WhenAll(workers); - } - - /// - /// Continuously processes jobs from the job channel until cancellation is requested. - /// - /// Cancellation token from the hosted service - private async Task ProcessJobsAsync(CancellationToken stoppingToken) - { - // Process all jobs from the channel until it's completed or cancellation is requested - await foreach (var jobItem in _jobsChannel.Reader.ReadAllAsync(stoppingToken)) - { - try - { - // Link the cancellation tokens so that cancellation can happen from either source - using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken, jobItem.CancellationTokenSource.Token); - await jobItem.Action(linkedTokenSource.Token); - _logger.LogInformation("Worker {CurrentTaskId} processed job {JobId}", Task.CurrentId, jobItem.JobId); - } - catch (OperationCanceledException) - { - _logger.LogInformation("Job {JobId} was canceled", jobItem.JobId); - } - catch (Exception ex) - { - _logger.LogError(ex, "Job {JobId} failed", jobItem.JobId); - } - finally - { - // Notify that the job has completed (whether successfully or not) - jobItem.OnJobCompleted(jobItem.JobId); - } - } - } -} \ No newline at end of file + protected override Task ExecuteAsync(CancellationToken stoppingToken) => processor.ExecuteAsync(stoppingToken); +} diff --git a/src/common/Elsa.Mediator/PublishingStrategies/BackgroundProcessingStrategy.cs b/src/common/Elsa.Mediator/PublishingStrategies/BackgroundProcessingStrategy.cs index e960050f5..c611415e5 100644 --- a/src/common/Elsa.Mediator/PublishingStrategies/BackgroundProcessingStrategy.cs +++ b/src/common/Elsa.Mediator/PublishingStrategies/BackgroundProcessingStrategy.cs @@ -1,5 +1,6 @@ using Elsa.Mediator.Contexts; using Elsa.Mediator.Contracts; +using Elsa.Mediator.Middleware.Notification; using Microsoft.Extensions.DependencyInjection; namespace Elsa.Mediator.PublishingStrategies; @@ -13,7 +14,13 @@ public class BackgroundProcessingStrategy : IEventPublishingStrategy public async Task PublishAsync(NotificationStrategyContext context) { var notificationsChannel = context.ServiceProvider.GetRequiredService(); + var notificationContext = context.NotificationContext; + var queuedContext = new NotificationContext( + notificationContext.Notification, + NotificationStrategy.Sequential, + notificationContext.ServiceProvider, + notificationContext.CancellationToken); - await notificationsChannel.Writer.WriteAsync(context.NotificationContext, context.CancellationToken); + await notificationsChannel.Writer.WriteAsync(queuedContext, context.CancellationToken); } -} \ No newline at end of file +} diff --git a/src/common/Elsa.Mediator/Services/BackgroundCommandProcessor.cs b/src/common/Elsa.Mediator/Services/BackgroundCommandProcessor.cs new file mode 100644 index 000000000..876bbd59a --- /dev/null +++ b/src/common/Elsa.Mediator/Services/BackgroundCommandProcessor.cs @@ -0,0 +1,101 @@ +using System.Threading.Channels; +using Elsa.Mediator.Contracts; +using Elsa.Mediator.Middleware.Command; +using Elsa.Mediator.Options; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Elsa.Mediator.Services; + +/// +/// Continuously reads from a channel to which commands can be sent, executing each received command. +/// +public class BackgroundCommandProcessor +{ + private readonly int _workerCount; + private readonly ICommandsChannel _commandsChannel; + private readonly IServiceScopeFactory _scopeFactory; + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + public BackgroundCommandProcessor(IOptions options, ICommandsChannel commandsChannel, IServiceScopeFactory scopeFactory, ILogger logger) + { + _workerCount = options.Value.CommandWorkerCount; + _commandsChannel = commandsChannel; + _scopeFactory = scopeFactory; + _logger = logger; + } + + /// + /// Runs the processor until cancellation is requested. + /// + public async Task ExecuteAsync(CancellationToken cancellationToken) + { + var index = 0; + var outputs = new List>(_workerCount); + var workers = new List(_workerCount); + + for (var i = 0; i < _workerCount; i++) + { + var output = Channel.CreateUnbounded(); + outputs.Add(output); + workers.Add(ReadOutputAsync(output, cancellationToken)); + } + + try + { + await foreach (var commandContext in _commandsChannel.Reader.ReadAllAsync(cancellationToken)) + { + var output = outputs[index]; + await output.Writer.WriteAsync(commandContext, cancellationToken); + index = (index + 1) % _workerCount; + } + } + catch (OperationCanceledException ex) when (cancellationToken.IsCancellationRequested) + { + _logger.LogDebug(ex, "An operation was cancelled while processing the command queue"); + } + + foreach (var output in outputs) + output.Writer.Complete(); + + await Task.WhenAll(workers); + } + + private async Task ReadOutputAsync(Channel output, CancellationToken cancellationToken) + { + try + { + await foreach (var commandContext in output.Reader.ReadAllAsync(cancellationToken)) + { + try + { + using var scope = _scopeFactory.CreateScope(); + var commandSender = scope.ServiceProvider.GetRequiredService(); + using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, commandContext.CancellationToken); + + await commandSender.SendAsync( + commandContext.Command, + commandContext.CommandStrategy, + commandContext.Headers, + linkedTokenSource.Token); + } + catch (OperationCanceledException e) + { + _logger.LogDebug(e, "An operation was cancelled while processing the command queue"); + } + catch (Exception e) + { + _logger.LogError(e, "An unhandled exception occurred while processing the command queue"); + } + } + } + catch (OperationCanceledException ex) when (cancellationToken.IsCancellationRequested) + { + _logger.LogDebug(ex, "An operation was cancelled while processing the command queue"); + } + } +} diff --git a/src/common/Elsa.Mediator/Services/BackgroundJobProcessor.cs b/src/common/Elsa.Mediator/Services/BackgroundJobProcessor.cs new file mode 100644 index 000000000..dee6867f3 --- /dev/null +++ b/src/common/Elsa.Mediator/Services/BackgroundJobProcessor.cs @@ -0,0 +1,71 @@ +using Elsa.Mediator.Contracts; +using Elsa.Mediator.Options; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Elsa.Mediator.Services; + +/// +/// Continuously reads from a channel to which jobs can be sent, executing each received job. +/// +public class BackgroundJobProcessor +{ + private readonly int _workerCount; + private readonly IJobsChannel _jobsChannel; + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + public BackgroundJobProcessor(IOptions options, IJobsChannel jobsChannel, ILogger logger) + { + _workerCount = options.Value.JobWorkerCount; + _jobsChannel = jobsChannel; + _logger = logger; + } + + /// + /// Runs the processor until cancellation is requested. + /// + public async Task ExecuteAsync(CancellationToken cancellationToken) + { + var workers = new Task[_workerCount]; + + for (var i = 0; i < _workerCount; i++) + workers[i] = ProcessJobsAsync(cancellationToken); + + await Task.WhenAll(workers); + } + + private async Task ProcessJobsAsync(CancellationToken cancellationToken) + { + try + { + await foreach (var jobItem in _jobsChannel.Reader.ReadAllAsync(cancellationToken)) + { + try + { + using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, jobItem.CancellationTokenSource.Token); + await jobItem.Action(linkedTokenSource.Token); + _logger.LogInformation("Worker {CurrentTaskId} processed job {JobId}", Task.CurrentId, jobItem.JobId); + } + catch (OperationCanceledException) + { + _logger.LogInformation("Job {JobId} was canceled", jobItem.JobId); + } + catch (Exception ex) + { + _logger.LogError(ex, "Job {JobId} failed", jobItem.JobId); + } + finally + { + jobItem.OnJobCompleted(jobItem.JobId); + } + } + } + catch (OperationCanceledException ex) when (cancellationToken.IsCancellationRequested) + { + _logger.LogDebug(ex, "An operation was cancelled while processing the job queue"); + } + } +} diff --git a/src/common/Elsa.Mediator/Services/BackgroundNotificationProcessor.cs b/src/common/Elsa.Mediator/Services/BackgroundNotificationProcessor.cs new file mode 100644 index 000000000..8e062287a --- /dev/null +++ b/src/common/Elsa.Mediator/Services/BackgroundNotificationProcessor.cs @@ -0,0 +1,98 @@ +using System.Threading.Channels; +using Elsa.Mediator.Contracts; +using Elsa.Mediator.Middleware.Notification; +using Elsa.Mediator.Options; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Elsa.Mediator.Services; + +/// +/// Continuously reads from a channel to which notifications can be sent, publishing each received notification. +/// +public class BackgroundNotificationProcessor +{ + private readonly int _workerCount; + private readonly INotificationsChannel _notificationsChannel; + private readonly IServiceScopeFactory _scopeFactory; + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + public BackgroundNotificationProcessor(IOptions options, INotificationsChannel notificationsChannel, IServiceScopeFactory scopeFactory, ILogger logger) + { + _workerCount = options.Value.NotificationWorkerCount; + _notificationsChannel = notificationsChannel; + _scopeFactory = scopeFactory; + _logger = logger; + } + + /// + /// Runs the processor until cancellation is requested. + /// + public async Task ExecuteAsync(CancellationToken cancellationToken) + { + var index = 0; + var outputs = new List>(_workerCount); + var workers = new List(_workerCount); + + for (var i = 0; i < _workerCount; i++) + { + var output = Channel.CreateUnbounded(); + outputs.Add(output); + workers.Add(ReadOutputAsync(output, cancellationToken)); + } + + try + { + await foreach (var notification in _notificationsChannel.Reader.ReadAllAsync(cancellationToken)) + { + var output = outputs[index]; + await output.Writer.WriteAsync(notification, cancellationToken); + index = (index + 1) % _workerCount; + } + } + catch (OperationCanceledException ex) when (cancellationToken.IsCancellationRequested) + { + _logger.LogDebug(ex, "An operation was cancelled while processing the notification queue"); + } + + foreach (var output in outputs) + output.Writer.Complete(); + + await Task.WhenAll(workers); + } + + private async Task ReadOutputAsync(Channel output, CancellationToken cancellationToken) + { + try + { + using var scope = _scopeFactory.CreateScope(); + var notificationSender = scope.ServiceProvider.GetRequiredService(); + + await foreach (var notificationContext in output.Reader.ReadAllAsync(cancellationToken)) + { + try + { + var notification = notificationContext.Notification; + using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, notificationContext.CancellationToken); + await notificationSender.SendAsync(notification, notificationContext.NotificationStrategy, linkedTokenSource.Token); + } + catch (OperationCanceledException e) + { + _logger.LogDebug(e, "An operation was cancelled while processing the notification queue"); + } + catch (Exception e) + { + _logger.LogError(e, "An unhandled exception occurred while processing the notification queue"); + } + } + } + catch (OperationCanceledException ex) when (cancellationToken.IsCancellationRequested) + { + _logger.LogDebug(ex, "An operation was cancelled while processing the notification queue"); + } + } +} diff --git a/src/modules/Elsa.Alterations/Features/AlterationsFeature.cs b/src/modules/Elsa.Alterations/Features/AlterationsFeature.cs index 947221322..6f9173636 100644 --- a/src/modules/Elsa.Alterations/Features/AlterationsFeature.cs +++ b/src/modules/Elsa.Alterations/Features/AlterationsFeature.cs @@ -6,11 +6,12 @@ using Elsa.Alterations.Core.Stores; using Elsa.Alterations.Extensions; using Elsa.Alterations.Services; using Elsa.Alterations.Workflows; -using Elsa.Expressions.Options; using Elsa.Extensions; using Elsa.Features.Abstractions; using Elsa.Features.Services; +using Elsa.Workflows.Options; using Microsoft.Extensions.DependencyInjection; +using Elsa.Common.Serialization; namespace Elsa.Alterations.Features; @@ -60,10 +61,10 @@ public class AlterationsFeature : FeatureBase /// public override void Apply() { - Services.Configure(options => + Services.Configure(options => { - options.RegisterTypeAlias(typeof(AlterationPlanParams), typeof(AlterationPlanParams).GetSimpleAssemblyQualifiedName()); options.RegisterTypeAlias(typeof(AlterationPlanParams), nameof(AlterationPlanParams)); + options.RegisterLegacySimpleAssemblyQualifiedName(typeof(AlterationPlanParams)); }); Services.AddScoped(); diff --git a/src/modules/Elsa.Alterations/ShellFeatures/AlterationsFeature.cs b/src/modules/Elsa.Alterations/ShellFeatures/AlterationsFeature.cs index cb8674b42..8721c3a9c 100644 --- a/src/modules/Elsa.Alterations/ShellFeatures/AlterationsFeature.cs +++ b/src/modules/Elsa.Alterations/ShellFeatures/AlterationsFeature.cs @@ -1,13 +1,18 @@ +using CShells.FastEndpoints.Features; using CShells.Features; using Elsa.Alterations.Core.Contracts; using Elsa.Alterations.Core.Entities; using Elsa.Alterations.Core.Extensions; +using Elsa.Alterations.Core.Models; using Elsa.Alterations.Core.Stores; using Elsa.Alterations.Extensions; using Elsa.Alterations.Services; +using Elsa.Alterations.Workflows; using Elsa.Extensions; +using Elsa.Workflows.Options; using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; +using Elsa.Common.Serialization; namespace Elsa.Alterations.ShellFeatures; @@ -16,9 +21,10 @@ namespace Elsa.Alterations.ShellFeatures; /// [ShellFeature( DisplayName = "Alterations", - Description = "Provides workflow alteration capabilities for modifying running workflow instances")] + Description = "Provides workflow alteration capabilities for modifying running workflow instances", + DependsOn = ["ElsaFastEndpoints", "WorkflowRuntime"])] [UsedImplicitly] -public class AlterationsFeature : IShellFeature +public class AlterationsFeature : IFastEndpointsShellFeature { /// /// Gets or sets the factory for the alteration plan store. @@ -37,6 +43,12 @@ public class AlterationsFeature : IShellFeature public void ConfigureServices(IServiceCollection services) { + services.Configure(options => + { + options.RegisterTypeAlias(typeof(AlterationPlanParams), nameof(AlterationPlanParams)); + options.RegisterLegacySimpleAssemblyQualifiedName(typeof(AlterationPlanParams)); + }); + services.AddScoped(); services.AddAlterations(); services.AddAlterationsCore(); @@ -51,6 +63,7 @@ public class AlterationsFeature : IShellFeature services.AddScoped(AlterationPlanStoreFactory); services.AddScoped(AlterationJobStoreFactory); services.AddScoped(AlterationJobDispatcherFactory); + + services.AddWorkflow(); } } - diff --git a/src/modules/Elsa.Common/Entities/OrderDefinition.cs b/src/modules/Elsa.Common/Entities/OrderDefinition.cs index 8a50560f5..18c1fa090 100644 --- a/src/modules/Elsa.Common/Entities/OrderDefinition.cs +++ b/src/modules/Elsa.Common/Entities/OrderDefinition.cs @@ -34,10 +34,4 @@ public class OrderDefinition /// [JsonIgnore] public Expression> KeySelector { get; set; } = null!; - - /// - /// A best-effort textual representation of the key selector for cache-key generation. - /// - [JsonIgnore] - public string? KeySelectorText => KeySelector?.ToString(); } diff --git a/src/modules/Elsa.Common/Extensions/SerializationTypeOptionsExtensions.cs b/src/modules/Elsa.Common/Extensions/SerializationTypeOptionsExtensions.cs new file mode 100644 index 000000000..fe257dbe3 --- /dev/null +++ b/src/modules/Elsa.Common/Extensions/SerializationTypeOptionsExtensions.cs @@ -0,0 +1,53 @@ +using Elsa.Common.Serialization; + +// ReSharper disable once CheckNamespace +namespace Elsa.Extensions; + +/// +/// Extends . +/// +public static class SerializationTypeOptionsExtensions +{ + /// + /// Registers a preferred serialization alias. + /// + public static SerializationTypeOptions AddTypeAlias(this SerializationTypeOptions options, string alias) => options.RegisterTypeAlias(typeof(T), alias); + + /// + /// Registers the type name as the preferred serialization alias. + /// + public static SerializationTypeOptions AddTypeAlias(this SerializationTypeOptions options) => options.RegisterTypeAlias(typeof(T), typeof(T).Name); + + /// + /// Registers a preferred serialization alias and the current simple assembly-qualified name as a legacy identifier. + /// + public static SerializationTypeOptions AddTypeAliasWithLegacyName(this SerializationTypeOptions options, Type type, string alias) + { + options.RegisterTypeAlias(type, alias); + options.RegisterLegacySimpleAssemblyQualifiedName(type); + return options; + } + + /// + /// Registers a preferred serialization alias and the current simple assembly-qualified name as a legacy identifier. + /// + public static SerializationTypeOptions AddTypeAliasWithLegacyName(this SerializationTypeOptions options, string alias) => options.AddTypeAliasWithLegacyName(typeof(T), alias); + + /// + /// Registers the current simple assembly-qualified name as a compatibility identifier. + /// + public static SerializationTypeOptions AddLegacySimpleAssemblyQualifiedName(this SerializationTypeOptions options) => options.RegisterLegacySimpleAssemblyQualifiedName(typeof(T)); + + /// + /// Registers the current simple assembly-qualified name as a compatibility identifier. + /// + public static SerializationTypeOptions AddLegacySimpleAssemblyQualifiedName(this SerializationTypeOptions options, Type type) => options.RegisterLegacySimpleAssemblyQualifiedName(type); + + /// + /// Registers the current simple assembly-qualified name as the preferred alias for compatibility-only types. + /// + public static SerializationTypeOptions AddSimpleAssemblyQualifiedTypeAlias(this SerializationTypeOptions options, Type type) + { + return options.RegisterTypeAlias(type, type.GetSimpleAssemblyQualifiedName()); + } +} diff --git a/src/modules/Elsa.Common/Extensions/TypeExtensions.cs b/src/modules/Elsa.Common/Extensions/TypeExtensions.cs index 863a2057b..588eda811 100644 --- a/src/modules/Elsa.Common/Extensions/TypeExtensions.cs +++ b/src/modules/Elsa.Common/Extensions/TypeExtensions.cs @@ -1,3 +1,5 @@ +using System.Collections.Concurrent; + // ReSharper disable once CheckNamespace namespace Elsa.Extensions; @@ -6,6 +8,17 @@ namespace Elsa.Extensions; /// public static class TypeExtensions { + private static readonly ConcurrentDictionary SimpleAssemblyQualifiedTypeNameCache = new(); + + /// + /// Gets the assembly-qualified name of the type, without version, culture, and public key token information. + /// + public static string GetSimpleAssemblyQualifiedName(this Type type) + { + if (type is null) throw new ArgumentNullException(nameof(type)); + return SimpleAssemblyQualifiedTypeNameCache.GetOrAdd(type, BuildSimplifiedName); + } + /// /// Returns true of the type is generic, false otherwise. /// @@ -54,4 +67,22 @@ public static class TypeExtensions { return type.IsPrimitive || type == typeof(decimal) || type == typeof(float) || type == typeof(double) || type == typeof(int) || type == typeof(long) || type == typeof(short) || type == typeof(byte) || type == typeof(uint) || type == typeof(ulong) || type == typeof(ushort) || type == typeof(sbyte); } -} \ No newline at end of file + + private static string BuildSimplifiedName(Type type) + { + var assemblyName = type.Assembly.GetName().Name; + + if (type.IsGenericType) + { + var genericTypeName = type.GetGenericTypeDefinition().FullName!; + var backtickIndex = genericTypeName.IndexOf('`'); + var typeNameWithoutArity = genericTypeName[..backtickIndex]; + var arity = genericTypeName[backtickIndex..]; + var simplifiedGenericArguments = type.GetGenericArguments().Select(BuildSimplifiedName); + + return $"{typeNameWithoutArity}{arity}[[{string.Join("],[", simplifiedGenericArguments)}]], {assemblyName}"; + } + + return $"{type.FullName}, {assemblyName}"; + } +} diff --git a/src/modules/Elsa.Common/Serialization/ISerializationTypeRegistry.cs b/src/modules/Elsa.Common/Serialization/ISerializationTypeRegistry.cs new file mode 100644 index 000000000..123963a1f --- /dev/null +++ b/src/modules/Elsa.Common/Serialization/ISerializationTypeRegistry.cs @@ -0,0 +1,27 @@ +namespace Elsa.Common.Serialization; + +/// +/// A registry of types that may be resolved from serialization type identifiers. +/// +public interface ISerializationTypeRegistry +{ + /// + /// Registers a type with an alias. + /// + void RegisterType(Type type, string alias); + + /// + /// Attempts to get the preferred alias for the specified type. + /// + bool TryGetAlias(Type type, out string alias); + + /// + /// Attempts to get the type associated with the specified alias or legacy name. + /// + bool TryGetType(string alias, out Type type); + + /// + /// Returns all registered types. + /// + IEnumerable ListTypes(); +} diff --git a/src/modules/Elsa.Common/Serialization/SerializationTypeOptions.cs b/src/modules/Elsa.Common/Serialization/SerializationTypeOptions.cs new file mode 100644 index 000000000..d252fd068 --- /dev/null +++ b/src/modules/Elsa.Common/Serialization/SerializationTypeOptions.cs @@ -0,0 +1,85 @@ +using System.Collections.ObjectModel; +using System.Dynamic; +using System.Text.Json; +using System.Text.Json.Nodes; +using Elsa.Extensions; + +namespace Elsa.Common.Serialization; + +/// +/// Options for serialization type identifiers. +/// +public class SerializationTypeOptions +{ + private readonly IDictionary _aliasTypeDictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); + private readonly IDictionary _typeAliasDictionary = new Dictionary(); + + /// + /// Initializes a new instance of the class. + /// + public SerializationTypeOptions() + { + AliasTypeDictionary = new ReadOnlyDictionary(_aliasTypeDictionary); + TypeAliasDictionary = new ReadOnlyDictionary(_typeAliasDictionary); + + RegisterTypeAlias(typeof(short), "Int16"); + RegisterTypeAlias(typeof(int), "Int32"); + RegisterTypeAlias(typeof(long), "Int64"); + RegisterLegacyTypeName(typeof(long), "Long"); + RegisterTypeAlias(typeof(float), "Single"); + RegisterTypeAlias(typeof(object), "Object"); + RegisterTypeAlias(typeof(string), "String"); + RegisterTypeAlias(typeof(bool), "Boolean"); + RegisterTypeAlias(typeof(decimal), "Decimal"); + RegisterTypeAlias(typeof(double), "Double"); + RegisterTypeAlias(typeof(byte[]), "ByteArray"); + RegisterTypeAlias(typeof(Guid), nameof(Guid)); + RegisterTypeAlias(typeof(DateTime), nameof(DateTime)); + RegisterTypeAlias(typeof(DateTimeOffset), nameof(DateTimeOffset)); + RegisterTypeAlias(typeof(TimeSpan), nameof(TimeSpan)); + RegisterTypeAlias(typeof(Stream), nameof(Stream)); + RegisterTypeAlias(typeof(ExpandoObject), "JSON"); + RegisterTypeAlias(typeof(JsonElement), nameof(JsonElement)); + RegisterTypeAlias(typeof(JsonNode), nameof(JsonNode)); + RegisterTypeAlias(typeof(JsonObject), nameof(JsonObject)); + RegisterTypeAlias(typeof(JsonArray), nameof(JsonArray)); + RegisterTypeAlias(typeof(IDictionary), "StringDictionary"); + RegisterTypeAlias(typeof(IDictionary), "ObjectDictionary"); + RegisterTypeAlias(typeof(Dictionary), "StringMap"); + RegisterTypeAlias(typeof(Dictionary), "ObjectMap"); + } + + /// + /// Gets aliases and legacy names keyed by identifier. + /// + public IDictionary AliasTypeDictionary { get; } + + /// + /// Gets preferred aliases keyed by type. + /// + public IDictionary TypeAliasDictionary { get; } + + /// + /// Registers a preferred serialization alias. + /// + public SerializationTypeOptions RegisterTypeAlias(Type type, string alias) + { + _aliasTypeDictionary[alias] = type; + _typeAliasDictionary[type] = alias; + return this; + } + + /// + /// Registers a legacy serialization identifier for compatibility reads. + /// + public SerializationTypeOptions RegisterLegacyTypeName(Type type, string typeName) + { + _aliasTypeDictionary[typeName] = type; + return this; + } + + /// + /// Registers the type's simple assembly-qualified name as a legacy serialization identifier. + /// + public SerializationTypeOptions RegisterLegacySimpleAssemblyQualifiedName(Type type) => RegisterLegacyTypeName(type, type.GetSimpleAssemblyQualifiedName()); +} diff --git a/src/modules/Elsa.Common/Serialization/SerializationTypeRegistry.cs b/src/modules/Elsa.Common/Serialization/SerializationTypeRegistry.cs new file mode 100644 index 000000000..9b02f2d61 --- /dev/null +++ b/src/modules/Elsa.Common/Serialization/SerializationTypeRegistry.cs @@ -0,0 +1,60 @@ +using Microsoft.Extensions.Options; + +namespace Elsa.Common.Serialization; + +/// +public class SerializationTypeRegistry : ISerializationTypeRegistry +{ + private readonly Dictionary _aliasTypeDictionary = new(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary _typeAliasDictionary = new(); + + /// + /// Creates a default registry. + /// + public static ISerializationTypeRegistry CreateDefault() + { + return new SerializationTypeRegistry(Microsoft.Extensions.Options.Options.Create(new SerializationTypeOptions())); + } + + /// + /// Initializes a new instance of the class. + /// + public SerializationTypeRegistry(IOptions options) + { + foreach (var entry in options.Value.AliasTypeDictionary) + RegisterTypeName(entry.Value, entry.Key); + + foreach (var entry in options.Value.TypeAliasDictionary) + RegisterType(entry.Key, entry.Value); + } + + /// + public void RegisterType(Type type, string alias) + { + _typeAliasDictionary[type] = alias; + RegisterTypeName(type, alias); + } + + /// + public bool TryGetAlias(Type type, out string alias) => _typeAliasDictionary.TryGetValue(type, out alias!); + + /// + public bool TryGetType(string alias, out Type type) => _aliasTypeDictionary.TryGetValue(alias, out type!); + + /// + public IEnumerable ListTypes() => _aliasTypeDictionary.Values.Distinct(); + + private void RegisterTypeName(Type type, string alias) + { + _aliasTypeDictionary[alias] = type; + + if (type.IsPrimitive || type.IsValueType && Nullable.GetUnderlyingType(type) == null) + { + var nullableType = typeof(Nullable<>).MakeGenericType(type); + _aliasTypeDictionary[$"{alias}?"] = nullableType; + + if (_typeAliasDictionary.ContainsKey(type)) + _typeAliasDictionary[nullableType] = $"{alias}?"; + } + } +} diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Helpers/WorkflowJsonTypeResolver.cs b/src/modules/Elsa.Common/Serialization/SerializationTypeResolver.cs similarity index 74% rename from src/modules/Elsa.Workflows.Core/Serialization/Helpers/WorkflowJsonTypeResolver.cs rename to src/modules/Elsa.Common/Serialization/SerializationTypeResolver.cs index 86771b0e8..250a25326 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/Helpers/WorkflowJsonTypeResolver.cs +++ b/src/modules/Elsa.Common/Serialization/SerializationTypeResolver.cs @@ -2,15 +2,14 @@ using System.Collections; using System.Collections.ObjectModel; using System.Reflection; using System.Text.Json; -using Elsa.Expressions.Contracts; using Elsa.Extensions; -namespace Elsa.Workflows.Serialization.Helpers; +namespace Elsa.Common.Serialization; /// -/// Resolves workflow JSON type aliases without loading arbitrary CLR type names. +/// Resolves serialization type aliases without loading arbitrary CLR type names. /// -public static class WorkflowJsonTypeResolver +public static class SerializationTypeResolver { private static readonly IDictionary GenericCollectionTypes = new Dictionary(StringComparer.Ordinal) { @@ -53,50 +52,50 @@ public static class WorkflowJsonTypeResolver }; /// - /// Resolves the specified workflow JSON type alias. + /// Resolves the specified serialization type alias. /// - public static Type ResolveType(IWellKnownTypeRegistry wellKnownTypeRegistry, string? typeAlias) + public static Type ResolveType(ISerializationTypeRegistry serializationTypeRegistry, string? typeAlias) { if (string.IsNullOrWhiteSpace(typeAlias)) - throw new JsonException("The workflow JSON type alias is missing."); + throw new JsonException("The serialization type alias is missing."); - if (TryResolveType(wellKnownTypeRegistry, typeAlias, out var type)) + if (TryResolveType(serializationTypeRegistry, typeAlias, out var type)) return type; throw new JsonException( - $"Unknown workflow JSON type alias '{typeAlias}'. Only registered aliases and supported compound aliases can be deserialized."); + $"Unknown serialization type alias '{typeAlias}'. Only registered aliases and supported compound aliases can be deserialized."); } /// - /// Attempts to resolve the specified workflow JSON type alias. + /// Attempts to resolve the specified serialization type alias. /// - public static bool TryResolveType(IWellKnownTypeRegistry wellKnownTypeRegistry, string typeAlias, out Type type) + public static bool TryResolveType(ISerializationTypeRegistry serializationTypeRegistry, string typeAlias, out Type type) { IReadOnlyList? registeredTypes = null; - return TryResolveType(wellKnownTypeRegistry, typeAlias, ref registeredTypes, out type); + return TryResolveType(serializationTypeRegistry, typeAlias, ref registeredTypes, out type); } - private static bool TryResolveType(IWellKnownTypeRegistry wellKnownTypeRegistry, string typeAlias, ref IReadOnlyList? registeredTypes, out Type type) + private static bool TryResolveType(ISerializationTypeRegistry serializationTypeRegistry, string typeAlias, ref IReadOnlyList? registeredTypes, out Type type) { - if (wellKnownTypeRegistry.TryGetType(typeAlias, out var registeredType)) + if (serializationTypeRegistry.TryGetType(typeAlias, out var registeredType)) { type = registeredType; return true; } - if (TryResolveArrayType(wellKnownTypeRegistry, typeAlias, ref registeredTypes, out var arrayType)) + if (TryResolveArrayType(serializationTypeRegistry, typeAlias, ref registeredTypes, out var arrayType)) { type = arrayType; return true; } - if (TryResolveGenericCollectionType(wellKnownTypeRegistry, typeAlias, ref registeredTypes, out var genericCollectionType)) + if (TryResolveGenericCollectionType(serializationTypeRegistry, typeAlias, ref registeredTypes, out var genericCollectionType)) { type = genericCollectionType; return true; } - if (TryResolveRegisteredLegacyTypeName(wellKnownTypeRegistry, typeAlias, ref registeredTypes, out var legacyType)) + if (TryResolveRegisteredLegacyTypeName(serializationTypeRegistry, typeAlias, ref registeredTypes, out var legacyType)) { type = legacyType; return true; @@ -107,18 +106,18 @@ public static class WorkflowJsonTypeResolver } /// - /// Attempts to return a workflow JSON type alias that this resolver can read back. + /// Attempts to return a serialization type alias that this resolver can read back. /// - public static bool TryGetAlias(IWellKnownTypeRegistry wellKnownTypeRegistry, Type type, out string alias) + public static bool TryGetAlias(ISerializationTypeRegistry serializationTypeRegistry, Type type, out string alias) { - if (wellKnownTypeRegistry.TryGetAlias(type, out alias!)) + if (serializationTypeRegistry.TryGetAlias(type, out alias!)) return true; if (type.IsArray) { var elementType = type.GetElementType()!; - if (TryGetAlias(wellKnownTypeRegistry, elementType, out var elementTypeAlias)) + if (TryGetAlias(serializationTypeRegistry, elementType, out var elementTypeAlias)) { alias = $"{elementTypeAlias}[]"; return true; @@ -130,7 +129,7 @@ public static class WorkflowJsonTypeResolver var genericTypeDefinition = type.GetGenericTypeDefinition(); if (TryGetWritableGenericCollectionAlias(genericTypeDefinition, out var genericTypeAlias) && - TryGetAlias(wellKnownTypeRegistry, type.GenericTypeArguments[0], out var elementTypeAlias)) + TryGetAlias(serializationTypeRegistry, type.GenericTypeArguments[0], out var elementTypeAlias)) { alias = $"{genericTypeAlias}<{elementTypeAlias}>"; return true; @@ -163,7 +162,7 @@ public static class WorkflowJsonTypeResolver return false; } - private static bool TryResolveArrayType(IWellKnownTypeRegistry wellKnownTypeRegistry, string typeAlias, ref IReadOnlyList? registeredTypes, out Type type) + private static bool TryResolveArrayType(ISerializationTypeRegistry serializationTypeRegistry, string typeAlias, ref IReadOnlyList? registeredTypes, out Type type) { type = null!; @@ -171,14 +170,14 @@ public static class WorkflowJsonTypeResolver return false; var elementTypeAlias = typeAlias[..^2]; - if (!TryResolveType(wellKnownTypeRegistry, elementTypeAlias, ref registeredTypes, out var elementType)) + if (!TryResolveType(serializationTypeRegistry, elementTypeAlias, ref registeredTypes, out var elementType)) return false; type = elementType.MakeArrayType(); return true; } - private static bool TryResolveGenericCollectionType(IWellKnownTypeRegistry wellKnownTypeRegistry, string typeAlias, ref IReadOnlyList? registeredTypes, out Type type) + private static bool TryResolveGenericCollectionType(ISerializationTypeRegistry serializationTypeRegistry, string typeAlias, ref IReadOnlyList? registeredTypes, out Type type) { type = null!; var genericStart = typeAlias.IndexOf('<', StringComparison.Ordinal); @@ -191,7 +190,7 @@ public static class WorkflowJsonTypeResolver return false; var elementTypeAlias = typeAlias[(genericStart + 1)..^1]; - if (!TryResolveType(wellKnownTypeRegistry, elementTypeAlias, ref registeredTypes, out var elementType)) + if (!TryResolveType(serializationTypeRegistry, elementTypeAlias, ref registeredTypes, out var elementType)) return false; type = genericTypeDefinition.MakeGenericType(elementType); @@ -213,15 +212,15 @@ public static class WorkflowJsonTypeResolver return false; } - private static bool TryResolveRegisteredLegacyTypeName(IWellKnownTypeRegistry wellKnownTypeRegistry, string typeAlias, ref IReadOnlyList? registeredTypes, out Type type) + private static bool TryResolveRegisteredLegacyTypeName(ISerializationTypeRegistry serializationTypeRegistry, string typeAlias, ref IReadOnlyList? registeredTypes, out Type type) { - registeredTypes ??= GetRegisteredTypes(wellKnownTypeRegistry); + registeredTypes ??= GetRegisteredTypes(serializationTypeRegistry); var registeredTypeSnapshot = registeredTypes; if (TryResolveRegisteredSimpleAssemblyQualifiedName(registeredTypeSnapshot, typeAlias, out type)) return true; - if (TryResolveLegacyGenericCollectionTypeName(wellKnownTypeRegistry, typeAlias, ref registeredTypes, out type)) + if (TryResolveLegacyGenericCollectionTypeName(serializationTypeRegistry, typeAlias, ref registeredTypes, out type)) return true; Type? resolvedType; @@ -243,9 +242,9 @@ public static class WorkflowJsonTypeResolver return resolvedType != null; } - private static IReadOnlyList GetRegisteredTypes(IWellKnownTypeRegistry wellKnownTypeRegistry) + private static IReadOnlyList GetRegisteredTypes(ISerializationTypeRegistry serializationTypeRegistry) { - return wellKnownTypeRegistry.ListTypes().ToArray(); + return serializationTypeRegistry.ListTypes().ToArray(); } private static bool TryResolveRegisteredSimpleAssemblyQualifiedName(IEnumerable registeredTypes, string typeAlias, out Type type) @@ -257,7 +256,7 @@ public static class WorkflowJsonTypeResolver return type != null; } - private static bool TryResolveLegacyGenericCollectionTypeName(IWellKnownTypeRegistry wellKnownTypeRegistry, string typeAlias, ref IReadOnlyList? registeredTypes, out Type type) + private static bool TryResolveLegacyGenericCollectionTypeName(ISerializationTypeRegistry serializationTypeRegistry, string typeAlias, ref IReadOnlyList? registeredTypes, out Type type) { type = null!; @@ -274,7 +273,7 @@ public static class WorkflowJsonTypeResolver continue; var elementTypeAlias = typeAlias[prefix.Length..separatorIndex]; - if (!TryResolveType(wellKnownTypeRegistry, elementTypeAlias, ref registeredTypes, out var elementType)) + if (!TryResolveType(serializationTypeRegistry, elementTypeAlias, ref registeredTypes, out var elementType)) return false; // The resolver only closes known collection definitions over registered element types. diff --git a/src/modules/Elsa.Common/ShellFeatures/MediatorFeature.cs b/src/modules/Elsa.Common/ShellFeatures/MediatorFeature.cs index e162e8d10..6808838c4 100644 --- a/src/modules/Elsa.Common/ShellFeatures/MediatorFeature.cs +++ b/src/modules/Elsa.Common/ShellFeatures/MediatorFeature.cs @@ -1,5 +1,8 @@ using CShells.Features; +using Elsa.Common.ShellHandlers; +using Elsa.Extensions; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; namespace Elsa.Common.ShellFeatures; @@ -9,13 +12,17 @@ namespace Elsa.Common.ShellFeatures; [ShellFeature( "Mediator", DisplayName = "Mediator", - Description = "Registers mediator services for in-process notifications and requests")] + Description = "Registers mediator services for in-process notifications and requests", + DependsOn = [typeof(MultitenancyFeature)])] public class MediatorFeature : IShellFeature { public void ConfigureServices(IServiceCollection services) { services .AddMediator() - .AddMediatorHostedServices(); + .AddMediatorBackgroundChannels(); + + services.TryAddSingleton(); + services.AddBackgroundTask(); } } diff --git a/src/modules/Elsa.Common/ShellHandlers/MediatorBackgroundProcessingCoordinator.cs b/src/modules/Elsa.Common/ShellHandlers/MediatorBackgroundProcessingCoordinator.cs new file mode 100644 index 000000000..702e438c7 --- /dev/null +++ b/src/modules/Elsa.Common/ShellHandlers/MediatorBackgroundProcessingCoordinator.cs @@ -0,0 +1,91 @@ +using Elsa.Mediator.Services; +using Microsoft.Extensions.Logging; + +namespace Elsa.Common.ShellHandlers; + +public sealed class MediatorBackgroundProcessingCoordinator( + BackgroundCommandProcessor commandProcessor, + BackgroundNotificationProcessor notificationProcessor, + BackgroundJobProcessor jobProcessor, + ILogger logger) : IAsyncDisposable +{ + private readonly SemaphoreSlim _lock = new(1, 1); + private CancellationTokenSource? _cancellationTokenSource; + private Task? _processingTask; + private int _referenceCount; + + public async Task StartAsync(CancellationToken cancellationToken = default) + { + await _lock.WaitAsync(cancellationToken); + try + { + if (_referenceCount++ > 0) + return; + + _cancellationTokenSource = new(); + _processingTask = Task.WhenAll( + commandProcessor.ExecuteAsync(_cancellationTokenSource.Token), + notificationProcessor.ExecuteAsync(_cancellationTokenSource.Token), + jobProcessor.ExecuteAsync(_cancellationTokenSource.Token)); + } + finally + { + _lock.Release(); + } + } + + public async Task StopAsync(CancellationToken cancellationToken = default) + { + Task? processingTask; + CancellationTokenSource? cancellationTokenSource; + + await _lock.WaitAsync(cancellationToken); + try + { + if (_referenceCount == 0) + return; + + if (--_referenceCount > 0) + return; + + processingTask = _processingTask; + cancellationTokenSource = _cancellationTokenSource; + _processingTask = null; + _cancellationTokenSource = null; + } + finally + { + _lock.Release(); + } + + if (cancellationTokenSource is null) + return; + + await cancellationTokenSource.CancelAsync(); + + if (processingTask is not null) + { + try + { + await processingTask.WaitAsync(cancellationToken); + } + catch (OperationCanceledException) when (cancellationTokenSource.IsCancellationRequested) + { + } + catch (Exception e) + { + logger.LogError(e, "An error occurred while stopping mediator background processing"); + throw; + } + } + + cancellationTokenSource.Dispose(); + } + + public async ValueTask DisposeAsync() + { + _referenceCount = 1; + await StopAsync(CancellationToken.None); + _lock.Dispose(); + } +} diff --git a/src/modules/Elsa.Common/ShellHandlers/MediatorBackgroundTask.cs b/src/modules/Elsa.Common/ShellHandlers/MediatorBackgroundTask.cs new file mode 100644 index 000000000..62756b83c --- /dev/null +++ b/src/modules/Elsa.Common/ShellHandlers/MediatorBackgroundTask.cs @@ -0,0 +1,10 @@ +using Elsa.Common; + +namespace Elsa.Common.ShellHandlers; + +public sealed class MediatorBackgroundTask(MediatorBackgroundProcessingCoordinator coordinator) : BackgroundTask +{ + public override Task StartAsync(CancellationToken cancellationToken) => coordinator.StartAsync(cancellationToken); + + public override Task StopAsync(CancellationToken cancellationToken) => coordinator.StopAsync(cancellationToken); +} diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/AssemblyInfo.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/AssemblyInfo.cs new file mode 100644 index 000000000..5b9f0622d --- /dev/null +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Elsa.Diagnostics.ConsoleLogs.UnitTests")] diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Contracts/ConsoleStreamJsonConverter.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Contracts/ConsoleStreamJsonConverter.cs new file mode 100644 index 000000000..d3274d5bb --- /dev/null +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Contracts/ConsoleStreamJsonConverter.cs @@ -0,0 +1,57 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using ConsoleLogStreaming.Core.Models; + +namespace Elsa.Diagnostics.ConsoleLogs.Contracts; + +/// +/// Converts the public console stream filter contract values. +/// +public sealed class ConsoleStreamJsonConverter : JsonConverter +{ + public override ConsoleStream? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return reader.TokenType switch + { + JsonTokenType.Null => null, + JsonTokenType.String => ReadString(reader.GetString()), + JsonTokenType.Number => ReadNumber(ref reader), + _ => throw new JsonException("The console log stream filter must be 'stdout', 'stderr', or null.") + }; + } + + public override void Write(Utf8JsonWriter writer, ConsoleStream? value, JsonSerializerOptions options) + { + if (value == null) + { + writer.WriteNullValue(); + return; + } + + writer.WriteStringValue(value.Value switch + { + ConsoleStream.Stdout => "stdout", + ConsoleStream.Stderr => "stderr", + _ => throw new JsonException($"Unsupported console stream value '{value}'.") + }); + } + + private static ConsoleStream? ReadString(string? value) + { + return value?.Trim().ToLowerInvariant() switch + { + null or "" or "all" => null, + "stdout" => ConsoleStream.Stdout, + "stderr" => ConsoleStream.Stderr, + _ => throw new JsonException("The console log stream filter must be 'stdout', 'stderr', or null.") + }; + } + + private static ConsoleStream ReadNumber(ref Utf8JsonReader reader) + { + if (!reader.TryGetInt32(out var value) || !Enum.IsDefined(typeof(ConsoleStream), value)) + throw new JsonException("The console log stream filter has an unsupported numeric value."); + + return (ConsoleStream)value; + } +} diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Contracts/ElsaConsoleLogFilter.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Contracts/ElsaConsoleLogFilter.cs index 8571ce119..3579ac646 100644 --- a/src/modules/Elsa.Diagnostics.ConsoleLogs/Contracts/ElsaConsoleLogFilter.cs +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Contracts/ElsaConsoleLogFilter.cs @@ -1,3 +1,5 @@ +using System.Text.Json.Serialization; + namespace Elsa.Diagnostics.ConsoleLogs.Contracts; /// @@ -6,7 +8,9 @@ namespace Elsa.Diagnostics.ConsoleLogs.Contracts; public sealed record ElsaConsoleLogFilter { public string? SourceId { get; init; } - public global::ConsoleLogStreaming.Contracts.ConsoleLogStreaming? Stream { get; init; } + + [JsonConverter(typeof(ConsoleStreamJsonConverter))] + public global::ConsoleLogStreaming.Core.Models.ConsoleStream? Stream { get; init; } public string? Query { get; init; } public string? WorkflowInstanceId { get; init; } public string? WorkflowDefinitionId { get; init; } @@ -18,4 +22,4 @@ public sealed record ElsaConsoleLogFilter public DateTimeOffset? From { get; init; } public DateTimeOffset? To { get; init; } public int? Limit { get; init; } -} +} \ No newline at end of file diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Elsa.Diagnostics.ConsoleLogs.csproj b/src/modules/Elsa.Diagnostics.ConsoleLogs/Elsa.Diagnostics.ConsoleLogs.csproj index 7bfb57e57..208c80ab4 100644 --- a/src/modules/Elsa.Diagnostics.ConsoleLogs/Elsa.Diagnostics.ConsoleLogs.csproj +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Elsa.Diagnostics.ConsoleLogs.csproj @@ -8,9 +8,10 @@ - + + diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Endpoints/ConsoleLogs/Recent/Endpoint.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Endpoints/ConsoleLogs/Recent/Endpoint.cs index 906218c13..6f51c3436 100644 --- a/src/modules/Elsa.Diagnostics.ConsoleLogs/Endpoints/ConsoleLogs/Recent/Endpoint.cs +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Endpoints/ConsoleLogs/Recent/Endpoint.cs @@ -1,15 +1,18 @@ +using System.Text.Json; using ConsoleLogStreaming.Core; using Elsa.Abstractions; -using Elsa.Diagnostics.ConsoleLogs.Contracts; using Elsa.Diagnostics.ConsoleLogs.Permissions; using Elsa.Diagnostics.ConsoleLogs.Services; using JetBrains.Annotations; +using Microsoft.AspNetCore.Http; namespace Elsa.Diagnostics.ConsoleLogs.Endpoints.ConsoleLogs.Recent; [PublicAPI] -internal class Endpoint(IConsoleLogProvider provider, IConsoleLogStreamingApiMapper mapper) : ElsaEndpoint +internal class Endpoint(IConsoleLogProvider provider) : ElsaEndpointWithoutRequest { + private static readonly JsonSerializerOptions JsonSerializerOptions = new(JsonSerializerDefaults.Web); + public override void Configure() { Verbs(FastEndpoints.Http.POST); @@ -17,9 +20,47 @@ internal class Endpoint(IConsoleLogProvider provider, IConsoleLogStreamingApiMap ConfigurePermissions(ConsoleLogsPermissions.Read); } - public override async Task ExecuteAsync(ElsaConsoleLogFilter request, CancellationToken cancellationToken) + public override async Task ExecuteAsync(CancellationToken cancellationToken) { - var result = await provider.GetRecentAsync(mapper.ToCore(ConsoleLogFilterMapper.ToStreamingFilter(request)), cancellationToken); - return mapper.ToApi(result); + var request = await ReadJsonBodyAsync(cancellationToken); + if (ValidationFailed) + { + await Send.ErrorsAsync(StatusCodes.Status400BadRequest, cancellationToken); + return new(); + } + + var result = await provider.GetRecentAsync(ConsoleLogFilterMapper.ToStreamingFilter(request ?? new()), cancellationToken); + return result; + } + + private async Task ReadJsonBodyAsync(CancellationToken cancellationToken) + { + if (HttpContext.Request.ContentLength is 0) + return null; + + if (!HttpContext.Request.HasJsonContentType()) + return null; + + using var body = new MemoryStream(); + await HttpContext.Request.Body.CopyToAsync(body, cancellationToken); + + if (body.Length == 0) + return null; + + body.Position = 0; + try + { + return await DeserializeJsonBodyAsync(body, cancellationToken); + } + catch (JsonException) + { + AddError("Invalid console log filter JSON."); + return null; + } + } + + internal static async ValueTask DeserializeJsonBodyAsync(Stream body, CancellationToken cancellationToken) + { + return await JsonSerializer.DeserializeAsync(body, JsonSerializerOptions, cancellationToken); } } diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Endpoints/ConsoleLogs/Sources/Endpoint.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Endpoints/ConsoleLogs/Sources/Endpoint.cs index 98e1ed557..39246d9b7 100644 --- a/src/modules/Elsa.Diagnostics.ConsoleLogs/Endpoints/ConsoleLogs/Sources/Endpoint.cs +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Endpoints/ConsoleLogs/Sources/Endpoint.cs @@ -2,11 +2,12 @@ using ConsoleLogStreaming.Core; using Elsa.Abstractions; using Elsa.Diagnostics.ConsoleLogs.Permissions; using JetBrains.Annotations; +using ConsoleLogSource = ConsoleLogStreaming.Core.Models.ConsoleLogSource; namespace Elsa.Diagnostics.ConsoleLogs.Endpoints.ConsoleLogs.Sources; [PublicAPI] -internal class Endpoint(IConsoleLogProvider provider, IConsoleLogStreamingApiMapper mapper) : ElsaEndpointWithoutRequest> +internal class Endpoint(IConsoleLogProvider provider) : ElsaEndpointWithoutRequest> { public override void Configure() { @@ -17,6 +18,6 @@ internal class Endpoint(IConsoleLogProvider provider, IConsoleLogStreamingApiMap public override async Task> ExecuteAsync(CancellationToken cancellationToken) { var sources = await provider.ListSourcesAsync(cancellationToken); - return sources.Select(mapper.ToApi).ToList(); + return sources.ToList(); } } diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/ConsoleLogContextServiceCollectionExtensions.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/ConsoleLogContextServiceCollectionExtensions.cs index 0463ef364..ac4bb466d 100644 --- a/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/ConsoleLogContextServiceCollectionExtensions.cs +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/ConsoleLogContextServiceCollectionExtensions.cs @@ -1,7 +1,4 @@ -using ConsoleLogStreaming.Core; -using Elsa.Diagnostics.ConsoleLogs.Contracts; using Elsa.Diagnostics.ConsoleLogs.Services; -using Elsa.Workflows; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -13,7 +10,7 @@ internal static class ConsoleLogContextServiceCollectionExtensions { services.TryAddSingleton(_ => ConsoleLogContextAccessor.Instance); services.TryAddSingleton(sp => sp.GetRequiredService()); - services.TryAddSingleton(sp => sp.GetRequiredService()); + services.TryAddSingleton(sp => sp.GetRequiredService()); services.TryAddEnumerable(ServiceDescriptor.Scoped()); services.TryAddEnumerable(ServiceDescriptor.Scoped()); return services; diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/ConsoleLogProviderServiceCollectionExtensions.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/ConsoleLogProviderServiceCollectionExtensions.cs new file mode 100644 index 000000000..b0efb30d7 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/ConsoleLogProviderServiceCollectionExtensions.cs @@ -0,0 +1,40 @@ +using ConsoleLogStreaming.Core; +using Elsa.Diagnostics.ConsoleLogs.Services; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace Elsa.Diagnostics.ConsoleLogs.Extensions; + +internal static class ConsoleLogProviderServiceCollectionExtensions +{ + public static void DecorateConsoleLogProvider(this IServiceCollection services) + { + var descriptor = services.LastOrDefault(x => x.ServiceType == typeof(IConsoleLogProvider)); + if (descriptor == null) + return; + + services.TryAddSingleton(); + services.Remove(descriptor); + services.Add(ServiceDescriptor.Describe( + typeof(IConsoleLogProvider), + sp => new ElsaConsoleLogProvider( + CreateProvider(sp, descriptor), + sp.GetRequiredService(), + sp.GetRequiredService()), + descriptor.Lifetime)); + } + + private static IConsoleLogProvider CreateProvider(IServiceProvider serviceProvider, ServiceDescriptor descriptor) + { + if (descriptor.ImplementationInstance is IConsoleLogProvider instance) + return instance; + + if (descriptor.ImplementationFactory != null) + return (IConsoleLogProvider)descriptor.ImplementationFactory(serviceProvider)!; + + if (descriptor.ImplementationType != null) + return (IConsoleLogProvider)ActivatorUtilities.CreateInstance(serviceProvider, descriptor.ImplementationType); + + throw new InvalidOperationException("The console log provider registration is invalid."); + } +} diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/EndpointRouteBuilderExtensions.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/EndpointRouteBuilderExtensions.cs index 6401544fb..666ee32a6 100644 --- a/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/EndpointRouteBuilderExtensions.cs +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/EndpointRouteBuilderExtensions.cs @@ -1,9 +1,6 @@ -using ConsoleLogStreaming.SignalR; using Elsa.Diagnostics.ConsoleLogs.RealTime; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; namespace Elsa.Diagnostics.ConsoleLogs.Extensions; @@ -13,12 +10,6 @@ public static class EndpointRouteBuilderExtensions public static void MapConsoleLogsHub(this IEndpointRouteBuilder endpoints) { - var options = endpoints.ServiceProvider.GetRequiredService>().Value; - var hub = endpoints.MapHub(options.HubPath); - - if (!string.IsNullOrWhiteSpace(options.AuthorizationPolicy)) - hub.RequireAuthorization(options.AuthorizationPolicy); - - options.ConfigureHubEndpoint?.Invoke(hub); + endpoints.MapHub(HubRoute); } } diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/HostServiceCollectionExtensions.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/HostServiceCollectionExtensions.cs index 93d996cc1..f6152bbfb 100644 --- a/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/HostServiceCollectionExtensions.cs +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/HostServiceCollectionExtensions.cs @@ -1,13 +1,10 @@ -using ConsoleLogStreaming.Contracts; -using ConsoleLogStreaming.Core; using ConsoleLogStreaming.Core.DependencyInjection; using ConsoleLogStreaming.Core.Options; -using ConsoleLogStreaming.SignalR; -using ConsoleLogStreaming.SignalR.DependencyInjection; using Elsa.Diagnostics.ConsoleLogs.RealTime; using Elsa.Diagnostics.ConsoleLogs.Services; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; namespace Elsa.Diagnostics.ConsoleLogs.Extensions; @@ -19,14 +16,16 @@ public static class HostServiceCollectionExtensions public static IServiceCollection AddConsoleLogsHost(this IServiceCollection services, Action? configure = null) { services.AddConsoleLogContextServices(); - services.AddConsoleLogStreamingHost(options => + services.AddConsoleLogStreaming(options => { ElsaConsoleLogOptions.ConfigureDefaults(options); configure?.Invoke(options); }); - services.AddConsoleLogStreamingSignalR(options => options.HubPath = EndpointRouteBuilderExtensions.HubRoute); - services.TryAddSingleton(); + services.AddSignalR(); + services.DecorateConsoleLogProvider(); + services.TryAddSingleton(); services.TryAddSingleton(); + services.TryAddEnumerable(ServiceDescriptor.Singleton()); return services; } } diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/ServiceCollectionExtensions.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/ServiceCollectionExtensions.cs index 4cf635467..c0dde3cac 100644 --- a/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/ServiceCollectionExtensions.cs +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/ServiceCollectionExtensions.cs @@ -1,9 +1,6 @@ -using ConsoleLogStreaming.Contracts; -using ConsoleLogStreaming.Core; using ConsoleLogStreaming.Core.DependencyInjection; using ConsoleLogStreaming.Core.Options; -using ConsoleLogStreaming.SignalR; -using ConsoleLogStreaming.SignalR.DependencyInjection; +using CShells.Lifecycle; using Elsa.Diagnostics.ConsoleLogs.RealTime; using Elsa.Diagnostics.ConsoleLogs.Services; using Microsoft.Extensions.DependencyInjection; @@ -19,14 +16,18 @@ public static class ServiceCollectionExtensions public static IServiceCollection AddConsoleLogsServices(this IServiceCollection services, Action? configureOptions = null) { services.AddConsoleLogContextServices(); - services.AddConsoleLogStreamingHost(options => + services.AddConsoleLogStreaming(options => { ElsaConsoleLogOptions.ConfigureDefaults(options); configureOptions?.Invoke(options); }); - services.AddConsoleLogStreamingSignalR(options => options.HubPath = EndpointRouteBuilderExtensions.HubRoute); - services.TryAddSingleton(); + services.AddSignalR(); + services.DecorateConsoleLogProvider(); + services.TryAddSingleton(); services.TryAddSingleton(); + services.TryAddScoped(); + services.TryAddEnumerable(ServiceDescriptor.Scoped()); + services.TryAddEnumerable(ServiceDescriptor.Scoped()); return services; } diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/README.md b/src/modules/Elsa.Diagnostics.ConsoleLogs/README.md index 96c3c6c13..dd8058740 100644 --- a/src/modules/Elsa.Diagnostics.ConsoleLogs/README.md +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/README.md @@ -69,7 +69,7 @@ tee, the capture publishes them verbatim, and the Studio renders them. Recent, source, and hub access all require the same permission. -Custom storage providers should implement `ConsoleLogStreaming.Core.IConsoleLogProvider` and use the core models. Elsa-specific values such as workflow instance IDs are represented as metadata internally and projected onto shared `ConsoleLogStreaming.Contracts` DTOs at the REST and SignalR boundaries. +Custom storage providers should implement `ConsoleLogStreaming.Core.IConsoleLogProvider` and use the core models. Elsa-specific values such as workflow instance IDs are represented as metadata internally and projected onto shared `ConsoleLogStreaming.Core.Models` DTOs at the REST and SignalR boundaries. ## Safety Boundaries diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/RealTime/ElsaConsoleLogSubscriptionManager.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/RealTime/ElsaConsoleLogSubscriptionManager.cs index ecc1237f2..723b31f48 100644 --- a/src/modules/Elsa.Diagnostics.ConsoleLogs/RealTime/ElsaConsoleLogSubscriptionManager.cs +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/RealTime/ElsaConsoleLogSubscriptionManager.cs @@ -1,13 +1,8 @@ using System.Collections.Concurrent; -using ConsoleLogStreaming.Contracts; using ConsoleLogStreaming.Core; -using ConsoleLogStreaming.SignalR; -using Elsa.Diagnostics.ConsoleLogs.Contracts; using Elsa.Diagnostics.ConsoleLogs.Services; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; -using CoreConsoleLogSource = ConsoleLogStreaming.Core.Models.ConsoleLogSource; - namespace Elsa.Diagnostics.ConsoleLogs.RealTime; /// @@ -18,8 +13,7 @@ public sealed class ElsaConsoleLogSubscriptionManager : IDisposable private readonly ConcurrentDictionary _subscriptions = new(StringComparer.Ordinal); private readonly IConsoleLogProvider _provider; private readonly IConsoleLogSourceRegistry _sourceRegistry; - private readonly IConsoleLogStreamingApiMapper _mapper; - private readonly IHubContext _hubContext; + private readonly IHubContext _hubContext; private readonly ILogger _logger; /// @@ -28,13 +22,11 @@ public sealed class ElsaConsoleLogSubscriptionManager : IDisposable public ElsaConsoleLogSubscriptionManager( IConsoleLogProvider provider, IConsoleLogSourceRegistry sourceRegistry, - IConsoleLogStreamingApiMapper mapper, - IHubContext hubContext, + IHubContext hubContext, ILogger logger) { _provider = provider; _sourceRegistry = sourceRegistry; - _mapper = mapper; _hubContext = hubContext; _logger = logger; _sourceRegistry.SourceChanged += OnSourceChanged; @@ -89,13 +81,24 @@ public sealed class ElsaConsoleLogSubscriptionManager : IDisposable { try { - await foreach (var item in _provider.SubscribeAsync(_mapper.ToCore(ConsoleLogFilterMapper.ToStreamingFilter(filter)), cancellationToken).ConfigureAwait(false)) + string? lastSourceSignature = null; + + await foreach (var item in _provider.SubscribeAsync(ConsoleLogFilterMapper.ToStreamingFilter(filter), cancellationToken).ConfigureAwait(false)) { if (item.Line != null) - await _hubContext.Clients.Client(connectionId).ReceiveConsoleLogLineAsync(_mapper.ToApi(item.Line), cancellationToken).ConfigureAwait(false); + { + await _hubContext.Clients.Client(connectionId).ReceiveConsoleLogLineAsync(item.Line, cancellationToken).ConfigureAwait(false); + + var sourceSignature = GetSourceSignature(item.Line.Source); + if (!string.Equals(sourceSignature, lastSourceSignature, StringComparison.Ordinal)) + { + lastSourceSignature = sourceSignature; + await _hubContext.Clients.Client(connectionId).ReceiveSourceChangedAsync(item.Line.Source, cancellationToken).ConfigureAwait(false); + } + } if (item.Dropped != null) - await _hubContext.Clients.Client(connectionId).ReceiveDroppedLinesAsync(_mapper.ToApi(item.Dropped), cancellationToken).ConfigureAwait(false); + await _hubContext.Clients.Client(connectionId).ReceiveDroppedLinesAsync(item.Dropped, cancellationToken).ConfigureAwait(false); } } catch (OperationCanceledException e) @@ -128,12 +131,12 @@ public sealed class ElsaConsoleLogSubscriptionManager : IDisposable subscription.CancellationTokenSource.Dispose(); } - private void OnSourceChanged(CoreConsoleLogSource source) + private void OnSourceChanged(ConsoleLogSource source) { _ = BroadcastSourceChangedAsync(source, _subscriptions.ToArray()); } - private async Task BroadcastSourceChangedAsync(CoreConsoleLogSource source, IReadOnlyCollection> subscriptions) + private async Task BroadcastSourceChangedAsync(ConsoleLogSource source, IReadOnlyCollection> subscriptions) { try { @@ -142,7 +145,7 @@ public sealed class ElsaConsoleLogSubscriptionManager : IDisposable if (!MatchesSource(source, subscription.Filter)) continue; - await _hubContext.Clients.Client(connectionId).ReceiveSourceChangedAsync(_mapper.ToApi(source), subscription.CancellationTokenSource.Token).ConfigureAwait(false); + await _hubContext.Clients.Client(connectionId).ReceiveSourceChangedAsync(source, subscription.CancellationTokenSource.Token).ConfigureAwait(false); } } catch (OperationCanceledException e) @@ -155,10 +158,27 @@ public sealed class ElsaConsoleLogSubscriptionManager : IDisposable } } - private static bool MatchesSource(CoreConsoleLogSource source, ElsaConsoleLogFilter filter) + private static bool MatchesSource(ConsoleLogSource source, ElsaConsoleLogFilter filter) { return string.IsNullOrWhiteSpace(filter.SourceId) || string.Equals(source.Id, filter.SourceId, StringComparison.OrdinalIgnoreCase); } + private static string GetSourceSignature(ConsoleLogSource source) + { + var metadata = source.Metadata + .OrderBy(x => x.Key, StringComparer.Ordinal) + .ThenBy(x => x.Value, StringComparer.Ordinal) + .Select(x => $"{x.Key}={x.Value}"); + + return string.Join('\u001f', + source.Id, + source.DisplayName, + source.ServiceName, + source.ProcessId?.ToString(), + source.MachineName, + source.Health.ToString(), + string.Join('\u001e', metadata)); + } + private sealed record ConsoleLogSubscription(ElsaConsoleLogFilter Filter, CancellationTokenSource CancellationTokenSource); } diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/RealTime/ElsaConsoleLogsHub.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/RealTime/ElsaConsoleLogsHub.cs index 592e619d1..a0fd23346 100644 --- a/src/modules/Elsa.Diagnostics.ConsoleLogs/RealTime/ElsaConsoleLogsHub.cs +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/RealTime/ElsaConsoleLogsHub.cs @@ -1,9 +1,6 @@ -using System.Runtime.CompilerServices; -using ConsoleLogStreaming.Contracts; using ConsoleLogStreaming.Core; -using ConsoleLogStreaming.SignalR; -using Elsa.Diagnostics.ConsoleLogs.Contracts; using Elsa.Diagnostics.ConsoleLogs.Services; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.SignalR; namespace Elsa.Diagnostics.ConsoleLogs.RealTime; @@ -11,11 +8,11 @@ namespace Elsa.Diagnostics.ConsoleLogs.RealTime; /// /// SignalR hub for live Elsa console log streaming. /// +[Authorize] public sealed class ElsaConsoleLogsHub( IConsoleLogProvider provider, - IConsoleLogStreamingApiMapper mapper, - IConsoleLogStreamingHubAuthorizer authorizer, - ElsaConsoleLogSubscriptionManager subscriptionManager) : Hub + IElsaConsoleLogHubAuthorizer authorizer, + ElsaConsoleLogSubscriptionManager subscriptionManager) : Hub { /// /// Streams matching console log items as a SignalR streaming method. @@ -27,8 +24,8 @@ public sealed class ElsaConsoleLogsHub( await EnsureCanReadAsync(cancellationToken).ConfigureAwait(false); filter = ValidateFilter(filter); - await foreach (var item in provider.SubscribeAsync(mapper.ToCore(ConsoleLogFilterMapper.ToStreamingFilter(filter)), cancellationToken).ConfigureAwait(false)) - yield return mapper.ToApi(item); + await foreach (var item in provider.SubscribeAsync(ConsoleLogFilterMapper.ToStreamingFilter(filter), cancellationToken).ConfigureAwait(false)) + yield return item; } /// @@ -80,3 +77,10 @@ public sealed class ElsaConsoleLogsHub( throw new HubException("Access denied."); } } + +public interface IElsaConsoleLogsClient +{ + Task ReceiveConsoleLogLineAsync(ConsoleLogLine line, CancellationToken cancellationToken = default); + Task ReceiveDroppedLinesAsync(ConsoleLogDroppedSummary summary, CancellationToken cancellationToken = default); + Task ReceiveSourceChangedAsync(ConsoleLogSource source, CancellationToken cancellationToken = default); +} diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogCaptureHostedService.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogCaptureHostedService.cs new file mode 100644 index 000000000..35d55f251 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogCaptureHostedService.cs @@ -0,0 +1,11 @@ +using ConsoleLogStreaming.Core; +using Microsoft.Extensions.Hosting; + +namespace Elsa.Diagnostics.ConsoleLogs.Services; + +internal sealed class ConsoleLogCaptureHostedService(IConsoleLogCapture capture) : IHostedService +{ + public Task StartAsync(CancellationToken cancellationToken) => capture.StartAsync(cancellationToken).AsTask(); + + public Task StopAsync(CancellationToken cancellationToken) => capture.StopAsync(cancellationToken).AsTask(); +} diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogCaptureShellLease.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogCaptureShellLease.cs new file mode 100644 index 000000000..e1464f6b1 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogCaptureShellLease.cs @@ -0,0 +1,69 @@ +using ConsoleLogStreaming.Core; +using ConsoleLogStreaming.Core.Capture; +using CShells.Lifecycle; +using Microsoft.Extensions.DependencyInjection; + +namespace Elsa.Diagnostics.ConsoleLogs.Services; + +public class ConsoleLogCaptureShellLease(IServiceProvider serviceProvider) +{ + private readonly SemaphoreSlim _lock = new(1, 1); + private bool _started; + + public async Task StartAsync(CancellationToken cancellationToken = default) + { + await _lock.WaitAsync(cancellationToken); + try + { + if (_started) + return; + + ConsoleLogStreamingHost.AddReference(); + var releaseReference = true; + + try + { + var capture = serviceProvider.GetRequiredService(); + await capture.StartAsync(cancellationToken); + _started = true; + releaseReference = false; + } + finally + { + if (releaseReference) + await ConsoleLogStreamingHost.ReleaseReferenceAsync(CancellationToken.None); + } + } + finally + { + _lock.Release(); + } + } + + public async Task StopAsync(CancellationToken cancellationToken = default) + { + await _lock.WaitAsync(cancellationToken); + try + { + if (!_started) + return; + + _started = false; + await ConsoleLogStreamingHost.ReleaseReferenceAsync(cancellationToken); + } + finally + { + _lock.Release(); + } + } +} + +public class ConsoleLogCaptureShellInitializer(ConsoleLogCaptureShellLease lease) : IShellInitializer +{ + public Task InitializeAsync(CancellationToken cancellationToken = default) => lease.StartAsync(cancellationToken); +} + +public class ConsoleLogCaptureShellDrainHandler(ConsoleLogCaptureShellLease lease) : IDrainHandler +{ + public Task DrainAsync(IDrainExtensionHandle extensionHandle, CancellationToken cancellationToken) => lease.StopAsync(cancellationToken); +} diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogContextAccessor.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogContextAccessor.cs index dbe4b7fb8..c78ce367d 100644 --- a/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogContextAccessor.cs +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogContextAccessor.cs @@ -1,12 +1,9 @@ -using ConsoleLogStreaming.Core; -using Elsa.Diagnostics.ConsoleLogs.Contracts; - namespace Elsa.Diagnostics.ConsoleLogs.Services; /// /// Ambient console log context backed by the current async execution context. /// -public sealed class ConsoleLogContextAccessor : IConsoleLogContextAccessor, IConsoleLogMetadataAccessor +public sealed class ConsoleLogContextAccessor : IConsoleLogContextAccessor, ConsoleLogStreaming.Core.IConsoleLogMetadataAccessor { private static readonly AsyncLocal CurrentFrame = new(); private static readonly IReadOnlyDictionary Empty = new Dictionary(); diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogContextAccessorExtensions.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogContextAccessorExtensions.cs index 7344aa62e..030f64b09 100644 --- a/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogContextAccessorExtensions.cs +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogContextAccessorExtensions.cs @@ -1,5 +1,3 @@ -using Elsa.Diagnostics.ConsoleLogs.Contracts; - namespace Elsa.Diagnostics.ConsoleLogs.Services; internal static class ConsoleLogContextAccessorExtensions diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogFilterMapper.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogFilterMapper.cs index b07cbe4ac..562022783 100644 --- a/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogFilterMapper.cs +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogFilterMapper.cs @@ -1,6 +1,3 @@ -using ConsoleLogStreaming.Contracts; -using Elsa.Diagnostics.ConsoleLogs.Contracts; - namespace Elsa.Diagnostics.ConsoleLogs.Services; internal static class ConsoleLogFilterMapper diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ElsaConsoleLogOptions.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ElsaConsoleLogOptions.cs index e9ac0fa91..7c9b7519b 100644 --- a/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ElsaConsoleLogOptions.cs +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ElsaConsoleLogOptions.cs @@ -13,12 +13,14 @@ internal static class ElsaConsoleLogOptions options.SourceDisplayName = !string.IsNullOrWhiteSpace(podName) ? podName : sourceId; options.ServiceName = Environment.GetEnvironmentVariable("OTEL_SERVICE_NAME") ?? AppDomain.CurrentDomain.FriendlyName; options.PreserveAnsi = true; + options.RecentCapacity = 2_000; + options.MaxRecentQuerySize = 250; - SetMetadata(options, ConsoleLogStreamingApiMetadataKeys.KubernetesPodName, podName); - SetMetadata(options, ConsoleLogStreamingApiMetadataKeys.KubernetesNamespace, Environment.GetEnvironmentVariable("POD_NAMESPACE")); - SetMetadata(options, ConsoleLogStreamingApiMetadataKeys.ContainerName, Environment.GetEnvironmentVariable("CONTAINER_NAME")); - SetMetadata(options, ConsoleLogStreamingApiMetadataKeys.KubernetesNodeName, Environment.GetEnvironmentVariable("NODE_NAME")); - SetMetadata(options, ConsoleLogStreamingApiMetadataKeys.ProcessStartedAt, DateTimeOffset.UtcNow.ToString("O")); + SetMetadata(options, "kubernetes.pod.name", podName); + SetMetadata(options, "kubernetes.namespace.name", Environment.GetEnvironmentVariable("POD_NAMESPACE")); + SetMetadata(options, "container.name", Environment.GetEnvironmentVariable("CONTAINER_NAME")); + SetMetadata(options, "kubernetes.node.name", Environment.GetEnvironmentVariable("NODE_NAME")); + SetMetadata(options, "process.started_at", DateTimeOffset.UtcNow.ToString("O")); } private static void SetMetadata(ConsoleLogOptions options, string key, string? value) diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ElsaConsoleLogProvider.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ElsaConsoleLogProvider.cs new file mode 100644 index 000000000..f36e3b1a8 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ElsaConsoleLogProvider.cs @@ -0,0 +1,110 @@ +using ConsoleLogStreaming.Core; + +namespace Elsa.Diagnostics.ConsoleLogs.Services; + +internal sealed class ElsaConsoleLogProvider( + IConsoleLogProvider inner, + IConsoleLogContextAccessor contextAccessor, + ElsaConsoleLogRecentBuffer recentBuffer) : IConsoleLogProvider, IDisposable, IAsyncDisposable +{ + private static readonly IReadOnlyDictionary EmptyMetadataFilter = new Dictionary(); + + public ValueTask PublishAsync(ConsoleLogLine line, CancellationToken cancellationToken = default) + { + var enrichedLine = Enrich(line); + recentBuffer.Add(enrichedLine); + return inner.PublishAsync(enrichedLine, cancellationToken); + } + + public async ValueTask GetRecentAsync(ConsoleLogFilter filter, CancellationToken cancellationToken = default) + { + if (!HasMetadataFilter(filter)) + return await inner.GetRecentAsync(filter, cancellationToken); + + var result = await inner.GetRecentAsync(filter with + { + Metadata = EmptyMetadataFilter + }, cancellationToken); + var items = recentBuffer.Query(filter); + + return result with { Items = items }; + } + + public async IAsyncEnumerable SubscribeAsync( + ConsoleLogFilter filter, + [EnumeratorCancellation] CancellationToken cancellationToken = default) + { + if (!HasMetadataFilter(filter)) + { + await foreach (var item in inner.SubscribeAsync(filter, cancellationToken).ConfigureAwait(false)) + yield return item; + + yield break; + } + + await foreach (var item in inner.SubscribeAsync(filter with { Metadata = EmptyMetadataFilter }, cancellationToken).ConfigureAwait(false)) + { + if (item.Line != null && !MatchesMetadata(item.Line, filter.Metadata)) + continue; + + yield return item; + } + } + + public ValueTask> ListSourcesAsync(CancellationToken cancellationToken = default) + { + return inner.ListSourcesAsync(cancellationToken); + } + + public void Dispose() + { + switch (inner) + { + case IDisposable disposable: + disposable.Dispose(); + break; + case IAsyncDisposable asyncDisposable: + asyncDisposable.DisposeAsync().AsTask().GetAwaiter().GetResult(); + break; + } + } + + public async ValueTask DisposeAsync() + { + switch (inner) + { + case IAsyncDisposable asyncDisposable: + await asyncDisposable.DisposeAsync(); + break; + case IDisposable disposable: + disposable.Dispose(); + break; + } + } + + private ConsoleLogLine Enrich(ConsoleLogLine line) + { + var ambientMetadata = contextAccessor.GetMetadata(); + if (ambientMetadata.Count == 0) + return line; + + var metadata = new Dictionary(line.Metadata, StringComparer.OrdinalIgnoreCase); + foreach (var item in ambientMetadata) + metadata[item.Key] = item.Value; + + return line with { Metadata = metadata }; + } + + private static bool HasMetadataFilter(ConsoleLogFilter filter) => filter.Metadata.Count > 0; + + private static bool MatchesMetadata(ConsoleLogLine line, IReadOnlyDictionary metadata) + { + foreach (var (key, value) in metadata) + { + if (!line.Metadata.TryGetValue(key, out var candidate) || !string.Equals(candidate, value, StringComparison.OrdinalIgnoreCase)) + return false; + } + + return true; + } +} diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ElsaConsoleLogRecentBuffer.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ElsaConsoleLogRecentBuffer.cs new file mode 100644 index 000000000..38f050765 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ElsaConsoleLogRecentBuffer.cs @@ -0,0 +1,69 @@ +using ConsoleLogStreaming.Core.Options; +using Microsoft.Extensions.Options; + +namespace Elsa.Diagnostics.ConsoleLogs.Services; + +internal sealed class ElsaConsoleLogRecentBuffer +{ + private readonly object _lock = new(); + private readonly Queue _lines = new(); + private readonly int _capacity; + private readonly int _maxQuerySize; + + public ElsaConsoleLogRecentBuffer(IOptions options) + { + _capacity = Math.Max(1, options.Value.RecentCapacity); + _maxQuerySize = Math.Max(1, options.Value.MaxRecentQuerySize); + } + + public void Add(ConsoleLogLine line) + { + lock (_lock) + { + _lines.Enqueue(line); + + while (_lines.Count > _capacity) + _lines.Dequeue(); + } + } + + public IReadOnlyList Query(ConsoleLogFilter filter) + { + ConsoleLogLine[] snapshot; + + lock (_lock) + snapshot = _lines.ToArray(); + + var limit = filter.Limit is > 0 ? Math.Min(filter.Limit.Value, _maxQuerySize) : _maxQuerySize; + return snapshot + .Where(line => Matches(line, filter)) + .TakeLast(limit) + .ToArray(); + } + + private static bool Matches(ConsoleLogLine line, ConsoleLogFilter filter) + { + if (!string.IsNullOrWhiteSpace(filter.SourceId) && !string.Equals(line.Source.Id, filter.SourceId, StringComparison.OrdinalIgnoreCase)) + return false; + + if (filter.Stream.HasValue && line.Stream != filter.Stream.Value) + return false; + + if (!string.IsNullOrWhiteSpace(filter.Query) && !line.Text.Contains(filter.Query, StringComparison.OrdinalIgnoreCase)) + return false; + + if (filter.From.HasValue && line.ReceivedAt < filter.From.Value) + return false; + + if (filter.To.HasValue && line.ReceivedAt > filter.To.Value) + return false; + + foreach (var (key, value) in filter.Metadata) + { + if (!line.Metadata.TryGetValue(key, out var candidate) || !string.Equals(candidate, value, StringComparison.OrdinalIgnoreCase)) + return false; + } + + return true; + } +} diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ElsaConsoleLogStreamHubAuthorizer.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ElsaConsoleLogStreamHubAuthorizer.cs index 2961c06a4..f08da4b89 100644 --- a/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ElsaConsoleLogStreamHubAuthorizer.cs +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ElsaConsoleLogStreamHubAuthorizer.cs @@ -1,11 +1,15 @@ -using ConsoleLogStreaming.SignalR; using Elsa.Diagnostics.ConsoleLogs.Permissions; using FastEndpoints.Security; using Microsoft.AspNetCore.SignalR; namespace Elsa.Diagnostics.ConsoleLogs.Services; -public sealed class ElsaConsoleLogStreamingHubAuthorizer : IConsoleLogStreamingHubAuthorizer +public interface IElsaConsoleLogHubAuthorizer +{ + ValueTask CanReadAsync(HubCallerContext context, CancellationToken cancellationToken = default); +} + +public sealed class ElsaConsoleLogStreamHubAuthorizer : IElsaConsoleLogHubAuthorizer { private const string ReadAllPermission = "read:*"; private static readonly string[] ReadPermissions = [PermissionNames.All, ReadAllPermission, ConsoleLogsPermissions.Read]; diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/ShellFeatures/ConsoleLogsFeature.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/ShellFeatures/ConsoleLogsFeature.cs index ada74e6f4..955c8ec42 100644 --- a/src/modules/Elsa.Diagnostics.ConsoleLogs/ShellFeatures/ConsoleLogsFeature.cs +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/ShellFeatures/ConsoleLogsFeature.cs @@ -24,14 +24,11 @@ public class ConsoleLogsFeature : IFastEndpointsShellFeature, IWebShellFeature public int RecentLogCapacity { get; set; } = DefaultOptions.RecentCapacity; public int SubscriberChannelCapacity { get; set; } = DefaultOptions.SubscriberCapacity; - public int CaptureChannelCapacity { get; set; } = DefaultOptions.CaptureChannelCapacity; public int MaxRecentQuerySize { get; set; } = DefaultOptions.MaxRecentQuerySize; public int MaxLineLength { get; set; } = DefaultOptions.MaxLineLength; public TimeSpan IdleFlushTimeout { get; set; } = DefaultOptions.IdleFlushTimeout; public bool StripAnsiEscapeSequences { get; set; } = !DefaultOptions.PreserveAnsi; - public TimeSpan SourceHeartbeatTimeout { get; set; } = DefaultOptions.SourceHeartbeatTimeout; - public string RedactionReplacement { get; set; } = DefaultOptions.RedactionReplacement; - public ICollection SensitiveNames { get; set; } = [..DefaultOptions.SensitiveNames]; + public string RedactionReplacement { get; set; } = "[Redacted]"; public ICollection SensitiveTextPatterns { get; set; } = [..DefaultOptions.RedactionRules.Select(x => x.Pattern)]; public void ConfigureServices(IServiceCollection services) @@ -48,14 +45,10 @@ public class ConsoleLogsFeature : IFastEndpointsShellFeature, IWebShellFeature { options.RecentCapacity = RecentLogCapacity; options.SubscriberCapacity = SubscriberChannelCapacity; - options.CaptureChannelCapacity = CaptureChannelCapacity; options.MaxRecentQuerySize = MaxRecentQuerySize; options.MaxLineLength = MaxLineLength; options.IdleFlushTimeout = IdleFlushTimeout; options.PreserveAnsi = !StripAnsiEscapeSequences; - options.SourceHeartbeatTimeout = SourceHeartbeatTimeout; - options.RedactionReplacement = RedactionReplacement; - options.SensitiveNames = [..SensitiveNames]; options.RedactionRules.Clear(); foreach (var pattern in SensitiveTextPatterns) { diff --git a/src/modules/Elsa.Diagnostics.ConsoleLogs/Usings.cs b/src/modules/Elsa.Diagnostics.ConsoleLogs/Usings.cs index 0fd2c0638..42fc132f3 100644 --- a/src/modules/Elsa.Diagnostics.ConsoleLogs/Usings.cs +++ b/src/modules/Elsa.Diagnostics.ConsoleLogs/Usings.cs @@ -1,5 +1,5 @@ global using System.Runtime.CompilerServices; -global using ConsoleLogStreaming.Contracts; +global using ConsoleLogStreaming.Core.Models; global using Elsa.Diagnostics.ConsoleLogs.Contracts; global using Elsa.Workflows; global using Elsa.Workflows.Pipelines.ActivityExecution; diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/AssemblyInfo.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/AssemblyInfo.cs new file mode 100644 index 000000000..479bbcf0f --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Elsa.Diagnostics.OpenTelemetry.UnitTests")] diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/ICollectorConfigurationProvider.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/ICollectorConfigurationProvider.cs new file mode 100644 index 000000000..82d810f19 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/ICollectorConfigurationProvider.cs @@ -0,0 +1,8 @@ +using Elsa.Diagnostics.OpenTelemetry.Models; + +namespace Elsa.Diagnostics.OpenTelemetry.Contracts; + +public interface ICollectorConfigurationProvider +{ + ValueTask GetAsync(CancellationToken cancellationToken = default); +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/IOpenTelemetryIngestor.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/IOpenTelemetryIngestor.cs new file mode 100644 index 000000000..ebe0b2037 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/IOpenTelemetryIngestor.cs @@ -0,0 +1,8 @@ +using Elsa.Diagnostics.OpenTelemetry.Models; + +namespace Elsa.Diagnostics.OpenTelemetry.Contracts; + +public interface IOpenTelemetryIngestor +{ + ValueTask IngestAsync(OpenTelemetryBatch batch, CancellationToken cancellationToken = default); +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/IOpenTelemetryLiveFeed.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/IOpenTelemetryLiveFeed.cs new file mode 100644 index 000000000..24148cdb1 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/IOpenTelemetryLiveFeed.cs @@ -0,0 +1,9 @@ +using Elsa.Diagnostics.OpenTelemetry.Models; + +namespace Elsa.Diagnostics.OpenTelemetry.Contracts; + +public interface IOpenTelemetryLiveFeed +{ + ValueTask PublishAsync(OpenTelemetryBatch batch, CancellationToken cancellationToken = default); + IAsyncEnumerable SubscribeAsync(OpenTelemetryTraceFilter filter, CancellationToken cancellationToken = default); +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/IOpenTelemetryProvider.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/IOpenTelemetryProvider.cs new file mode 100644 index 000000000..7a2e18b00 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/IOpenTelemetryProvider.cs @@ -0,0 +1,14 @@ +using Elsa.Diagnostics.OpenTelemetry.Models; + +namespace Elsa.Diagnostics.OpenTelemetry.Contracts; + +public interface IOpenTelemetryProvider +{ + ValueTask GetResourcesAsync(OpenTelemetryResourceFilter filter, CancellationToken cancellationToken = default); + ValueTask GetTracesAsync(OpenTelemetryTraceFilter filter, CancellationToken cancellationToken = default); + ValueTask GetTraceAsync(string traceId, CancellationToken cancellationToken = default); + ValueTask GetMetricsAsync(OpenTelemetryMetricFilter filter, CancellationToken cancellationToken = default); + ValueTask GetLogsAsync(OpenTelemetryLogFilter filter, CancellationToken cancellationToken = default); + ValueTask GetStorageDiagnosticsAsync(CancellationToken cancellationToken = default); + ValueTask GetCollectorConfigurationAsync(CancellationToken cancellationToken = default); +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/IOpenTelemetryRedactor.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/IOpenTelemetryRedactor.cs new file mode 100644 index 000000000..a97f6a04e --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/IOpenTelemetryRedactor.cs @@ -0,0 +1,8 @@ +using Elsa.Diagnostics.OpenTelemetry.Models; + +namespace Elsa.Diagnostics.OpenTelemetry.Contracts; + +public interface IOpenTelemetryRedactor +{ + OpenTelemetryBatch Redact(OpenTelemetryBatch batch); +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/IOpenTelemetrySourceRegistry.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/IOpenTelemetrySourceRegistry.cs new file mode 100644 index 000000000..9e314c138 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/IOpenTelemetrySourceRegistry.cs @@ -0,0 +1,10 @@ +using Elsa.Diagnostics.OpenTelemetry.Models; + +namespace Elsa.Diagnostics.OpenTelemetry.Contracts; + +public interface IOpenTelemetrySourceRegistry +{ + long DroppedCount { get; } + void MarkSeen(TelemetryResource resource); + IReadOnlyCollection List(); +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/IOpenTelemetryStore.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/IOpenTelemetryStore.cs new file mode 100644 index 000000000..2fac67706 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Contracts/IOpenTelemetryStore.cs @@ -0,0 +1,14 @@ +using Elsa.Diagnostics.OpenTelemetry.Models; + +namespace Elsa.Diagnostics.OpenTelemetry.Contracts; + +public interface IOpenTelemetryStore +{ + ValueTask WriteAsync(OpenTelemetryBatch batch, CancellationToken cancellationToken = default); + ValueTask QueryResourcesAsync(OpenTelemetryResourceFilter filter, CancellationToken cancellationToken = default); + ValueTask QueryTracesAsync(OpenTelemetryTraceFilter filter, CancellationToken cancellationToken = default); + ValueTask GetTraceAsync(string traceId, CancellationToken cancellationToken = default); + ValueTask QueryMetricsAsync(OpenTelemetryMetricFilter filter, CancellationToken cancellationToken = default); + ValueTask QueryLogsAsync(OpenTelemetryLogFilter filter, CancellationToken cancellationToken = default); + ValueTask GetDiagnosticsAsync(CancellationToken cancellationToken = default); +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Elsa.Diagnostics.OpenTelemetry.csproj b/src/modules/Elsa.Diagnostics.OpenTelemetry/Elsa.Diagnostics.OpenTelemetry.csproj new file mode 100644 index 000000000..5341fb4cf --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Elsa.Diagnostics.OpenTelemetry.csproj @@ -0,0 +1,16 @@ + + + + Provides OpenTelemetry diagnostics collection and query services for Elsa hosts. + elsa module diagnostics opentelemetry otel otlp signalr operations + + + + + + + + + + + diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/CollectorConfiguration/Endpoint.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/CollectorConfiguration/Endpoint.cs new file mode 100644 index 000000000..18816c5fa --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/CollectorConfiguration/Endpoint.cs @@ -0,0 +1,22 @@ +using Elsa.Abstractions; +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Permissions; +using JetBrains.Annotations; + +namespace Elsa.Diagnostics.OpenTelemetry.Endpoints.OpenTelemetry.CollectorConfiguration; + +[PublicAPI] +internal class Endpoint(IOpenTelemetryProvider provider) : ElsaEndpointWithoutRequest +{ + public override void Configure() + { + Get("/diagnostics/opentelemetry/collector-configuration"); + ConfigurePermissions(OpenTelemetryPermissions.Read); + } + + public override async Task ExecuteAsync(CancellationToken cancellationToken) + { + return await provider.GetCollectorConfigurationAsync(cancellationToken); + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Logs/Endpoint.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Logs/Endpoint.cs new file mode 100644 index 000000000..edb27a692 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Logs/Endpoint.cs @@ -0,0 +1,22 @@ +using Elsa.Abstractions; +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Permissions; +using JetBrains.Annotations; + +namespace Elsa.Diagnostics.OpenTelemetry.Endpoints.OpenTelemetry.Logs; + +[PublicAPI] +internal class Endpoint(IOpenTelemetryProvider provider) : ElsaEndpoint +{ + public override void Configure() + { + Post("/diagnostics/opentelemetry/logs/search"); + ConfigurePermissions(OpenTelemetryPermissions.Read); + } + + public override async Task ExecuteAsync(OpenTelemetryLogFilter request, CancellationToken cancellationToken) + { + return await provider.GetLogsAsync(request, cancellationToken); + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Metrics/Endpoint.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Metrics/Endpoint.cs new file mode 100644 index 000000000..ddf444163 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Metrics/Endpoint.cs @@ -0,0 +1,22 @@ +using Elsa.Abstractions; +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Permissions; +using JetBrains.Annotations; + +namespace Elsa.Diagnostics.OpenTelemetry.Endpoints.OpenTelemetry.Metrics; + +[PublicAPI] +internal class Endpoint(IOpenTelemetryProvider provider) : ElsaEndpoint +{ + public override void Configure() + { + Post("/diagnostics/opentelemetry/metrics/search"); + ConfigurePermissions(OpenTelemetryPermissions.Read); + } + + public override async Task ExecuteAsync(OpenTelemetryMetricFilter request, CancellationToken cancellationToken) + { + return await provider.GetMetricsAsync(request, cancellationToken); + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Resources/Endpoint.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Resources/Endpoint.cs new file mode 100644 index 000000000..a38052b04 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Resources/Endpoint.cs @@ -0,0 +1,22 @@ +using Elsa.Abstractions; +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Permissions; +using JetBrains.Annotations; + +namespace Elsa.Diagnostics.OpenTelemetry.Endpoints.OpenTelemetry.Resources; + +[PublicAPI] +internal class Endpoint(IOpenTelemetryProvider provider) : ElsaEndpoint +{ + public override void Configure() + { + Post("/diagnostics/opentelemetry/resources/search"); + ConfigurePermissions(OpenTelemetryPermissions.Read); + } + + public override async Task ExecuteAsync(OpenTelemetryResourceFilter request, CancellationToken cancellationToken) + { + return await provider.GetResourcesAsync(request, cancellationToken); + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Storage/Endpoint.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Storage/Endpoint.cs new file mode 100644 index 000000000..e946aebcf --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Storage/Endpoint.cs @@ -0,0 +1,22 @@ +using Elsa.Abstractions; +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Permissions; +using JetBrains.Annotations; + +namespace Elsa.Diagnostics.OpenTelemetry.Endpoints.OpenTelemetry.Storage; + +[PublicAPI] +internal class Endpoint(IOpenTelemetryProvider provider) : ElsaEndpointWithoutRequest +{ + public override void Configure() + { + Get("/diagnostics/opentelemetry/storage"); + ConfigurePermissions(OpenTelemetryPermissions.Read); + } + + public override async Task ExecuteAsync(CancellationToken cancellationToken) + { + return await provider.GetStorageDiagnosticsAsync(cancellationToken); + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Trace/Endpoint.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Trace/Endpoint.cs new file mode 100644 index 000000000..c919503a6 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Trace/Endpoint.cs @@ -0,0 +1,29 @@ +using Elsa.Abstractions; +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Permissions; +using JetBrains.Annotations; + +namespace Elsa.Diagnostics.OpenTelemetry.Endpoints.OpenTelemetry.Trace; + +[PublicAPI] +internal class Endpoint(IOpenTelemetryProvider provider) : ElsaEndpointWithoutRequest +{ + public override void Configure() + { + Get("/diagnostics/opentelemetry/traces/{traceId}"); + ConfigurePermissions(OpenTelemetryPermissions.Read); + } + + public override async Task HandleAsync(CancellationToken cancellationToken) + { + var trace = await provider.GetTraceAsync(Route("traceId")!, cancellationToken); + if (trace == null) + { + await Send.NotFoundAsync(cancellationToken); + return; + } + + await Send.OkAsync(trace, cancellationToken); + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Traces/Endpoint.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Traces/Endpoint.cs new file mode 100644 index 000000000..63056b4f0 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Endpoints/OpenTelemetry/Traces/Endpoint.cs @@ -0,0 +1,22 @@ +using Elsa.Abstractions; +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Permissions; +using JetBrains.Annotations; + +namespace Elsa.Diagnostics.OpenTelemetry.Endpoints.OpenTelemetry.Traces; + +[PublicAPI] +internal class Endpoint(IOpenTelemetryProvider provider) : ElsaEndpoint +{ + public override void Configure() + { + Post("/diagnostics/opentelemetry/traces/search"); + ConfigurePermissions(OpenTelemetryPermissions.Read); + } + + public override async Task ExecuteAsync(OpenTelemetryTraceFilter request, CancellationToken cancellationToken) + { + return await provider.GetTracesAsync(request, cancellationToken); + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Extensions/EndpointRouteBuilderExtensions.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Extensions/EndpointRouteBuilderExtensions.cs new file mode 100644 index 000000000..ba497335c --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Extensions/EndpointRouteBuilderExtensions.cs @@ -0,0 +1,114 @@ +using System.Buffers; +using Elsa.Diagnostics.OpenTelemetry.Options; +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Ingestion; +using Elsa.Diagnostics.OpenTelemetry.Ingestion.HttpProtobuf; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.RealTime; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace Elsa.Diagnostics.OpenTelemetry.Extensions; + +public static class EndpointRouteBuilderExtensions +{ + public const string DefaultHubRoute = "/elsa/hubs/diagnostics/opentelemetry"; + + public static void MapOpenTelemetryHub(this IEndpointRouteBuilder endpoints) + { + var options = endpoints.ServiceProvider.GetRequiredService>().Value; + endpoints.MapHub(string.IsNullOrWhiteSpace(options.HubRoute) ? DefaultHubRoute : options.HubRoute); + } + + public static void MapOpenTelemetryHttpProtobufCollector(this IEndpointRouteBuilder endpoints) + { + var options = endpoints.ServiceProvider.GetRequiredService>().Value; + var basePath = (string.IsNullOrWhiteSpace(options.HttpEndpointPath) ? "/elsa/otlp/v1" : options.HttpEndpointPath).TrimEnd('/'); + + endpoints.MapPost($"{basePath}/traces", static async (HttpContext httpContext, IOpenTelemetryIngestor ingestor, IOptions options, CancellationToken cancellationToken) => + { + return await IngestAsync(httpContext, ingestor, options, payload => OtlpHttpProtobufParser.ParseTraces(payload.Span), cancellationToken); + }); + + endpoints.MapPost($"{basePath}/metrics", static async (HttpContext httpContext, IOpenTelemetryIngestor ingestor, IOptions options, CancellationToken cancellationToken) => + { + return await IngestAsync(httpContext, ingestor, options, payload => OtlpHttpProtobufParser.ParseMetrics(payload.Span), cancellationToken); + }); + + endpoints.MapPost($"{basePath}/logs", static async (HttpContext httpContext, IOpenTelemetryIngestor ingestor, IOptions options, CancellationToken cancellationToken) => + { + return await IngestAsync(httpContext, ingestor, options, payload => OtlpHttpProtobufParser.ParseLogs(payload.Span), cancellationToken); + }); + } + + public static void MapOpenTelemetryGrpcCollector(this IEndpointRouteBuilder endpoints) + { + var options = endpoints.ServiceProvider.GetRequiredService>().Value; + + if (!options.EnableGrpc) + return; + + if (string.IsNullOrWhiteSpace(options.GrpcEndpointPath)) + throw new InvalidOperationException("OpenTelemetry gRPC ingestion is enabled, but no gRPC endpoint path was configured."); + + // The actual gRPC service binding is host-specific. This module exposes shared ingestion + // contracts and accurate collector metadata without forcing every host to reference gRPC. + } + + private static async Task IngestAsync( + HttpContext httpContext, + IOpenTelemetryIngestor ingestor, + IOptions options, + Func, OpenTelemetryBatch> parse, + CancellationToken cancellationToken) + { + if (!OtlpIngestionSecurity.IsAuthorized(httpContext, options.Value)) + return Results.Unauthorized(); + + try + { + var payload = await ReadBodyAsync(httpContext, options.Value.MaxHttpRequestBodySize, cancellationToken); + await ingestor.IngestAsync(parse(payload), cancellationToken); + return Results.Ok(); + } + catch (RequestBodyTooLargeException) + { + return Results.StatusCode(StatusCodes.Status413PayloadTooLarge); + } + catch (InvalidDataException) + { + return Results.BadRequest(); + } + } + + private static async Task> ReadBodyAsync(HttpContext httpContext, long maxBodySize, CancellationToken cancellationToken) + { + using var stream = new MemoryStream(); + var buffer = ArrayPool.Shared.Rent(81920); + var totalBytes = 0L; + + try + { + int read; + while ((read = await httpContext.Request.Body.ReadAsync(buffer.AsMemory(0, buffer.Length), cancellationToken)) > 0) + { + totalBytes += read; + if (totalBytes > maxBodySize) + throw new RequestBodyTooLargeException(); + + stream.Write(buffer, 0, read); + } + } + finally + { + ArrayPool.Shared.Return(buffer); + } + + return stream.ToArray(); + } + + private sealed class RequestBodyTooLargeException : Exception; +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Extensions/ModuleExtensions.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Extensions/ModuleExtensions.cs new file mode 100644 index 000000000..d36a113c2 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Extensions/ModuleExtensions.cs @@ -0,0 +1,14 @@ +using Elsa.Diagnostics.OpenTelemetry.Features; +using Elsa.Features.Services; + +// ReSharper disable once CheckNamespace +namespace Elsa.Extensions; + +public static class OpenTelemetryDiagnosticsModuleExtensions +{ + public static IModule UseOpenTelemetryDiagnostics(this IModule module, Action? configure = null) + { + module.Configure(configure); + return module; + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Extensions/ServiceCollectionExtensions.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..e2580549b --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,33 @@ +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Options; +using Elsa.Diagnostics.OpenTelemetry.Providers.InMemory; +using Elsa.Diagnostics.OpenTelemetry.RealTime; +using Elsa.Diagnostics.OpenTelemetry.Services; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace Elsa.Diagnostics.OpenTelemetry.Extensions; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddOpenTelemetryDiagnosticsServices(this IServiceCollection services, Action? configureOptions = null) + { + if (configureOptions != null) + services.Configure(configureOptions); + + services.AddSignalR(); + services.AddOptions(); + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(sp => sp.GetRequiredService()); + services.TryAddSingleton(); + services.TryAddSingleton(sp => sp.GetRequiredService()); + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); + + return services; + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Features/OpenTelemetryFeature.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Features/OpenTelemetryFeature.cs new file mode 100644 index 000000000..2356e7331 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Features/OpenTelemetryFeature.cs @@ -0,0 +1,23 @@ +using Elsa.Diagnostics.OpenTelemetry.Extensions; +using Elsa.Diagnostics.OpenTelemetry.Options; +using Elsa.Extensions; +using Elsa.Features.Abstractions; +using Elsa.Features.Services; + +namespace Elsa.Diagnostics.OpenTelemetry.Features; + +public class OpenTelemetryFeature(IModule module) : FeatureBase(module) +{ + public Action? ConfigureOptions { get; set; } + + public override void Configure() + { + Module.AddFastEndpointsAssembly(); + } + + public override void Apply() + { + Services.AddOpenTelemetryDiagnosticsServices(ConfigureOptions); + Module.AddFastEndpointsFromModule(); + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/FodyWeavers.xml b/src/modules/Elsa.Diagnostics.OpenTelemetry/FodyWeavers.xml new file mode 100644 index 000000000..535dce765 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/FodyWeavers.xml @@ -0,0 +1,4 @@ + + + + diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Ingestion/HttpProtobuf/OtlpHttpProtobufParser.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Ingestion/HttpProtobuf/OtlpHttpProtobufParser.cs new file mode 100644 index 000000000..7cffcebe4 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Ingestion/HttpProtobuf/OtlpHttpProtobufParser.cs @@ -0,0 +1,701 @@ +using System.Buffers.Binary; +using System.Globalization; +using System.Text; +using Elsa.Diagnostics.OpenTelemetry.Models; + +namespace Elsa.Diagnostics.OpenTelemetry.Ingestion.HttpProtobuf; + +internal static class OtlpHttpProtobufParser +{ + public static OpenTelemetryBatch ParseTraces(ReadOnlySpan payload) + { + var resources = new List(); + var spans = new List(); + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + if (field.Number != 1 || field.WireType != ProtobufWireType.LengthDelimited) + continue; + + var resourceSpans = ParseResourceSpans(field.Bytes); + resources.Add(resourceSpans.Resource); + spans.AddRange(resourceSpans.Spans); + } + + return CreateBatch(resources, spans, [], [], []); + } + + public static OpenTelemetryBatch ParseMetrics(ReadOnlySpan payload) + { + var resources = new List(); + var instruments = new Dictionary(StringComparer.OrdinalIgnoreCase); + var points = new List(); + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + if (field.Number != 1 || field.WireType != ProtobufWireType.LengthDelimited) + continue; + + var resourceMetrics = ParseResourceMetrics(field.Bytes); + resources.Add(resourceMetrics.Resource); + + foreach (var instrument in resourceMetrics.Instruments) + instruments[instrument.Id] = instrument; + + points.AddRange(resourceMetrics.Points); + } + + return CreateBatch(resources, [], instruments.Values.ToList(), points, []); + } + + public static OpenTelemetryBatch ParseLogs(ReadOnlySpan payload) + { + var resources = new List(); + var logs = new List(); + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + if (field.Number != 1 || field.WireType != ProtobufWireType.LengthDelimited) + continue; + + var resourceLogs = ParseResourceLogs(field.Bytes); + resources.Add(resourceLogs.Resource); + logs.AddRange(resourceLogs.Logs); + } + + return CreateBatch(resources, [], [], [], logs); + } + + private static (TelemetryResource Resource, List Spans) ParseResourceSpans(ReadOnlySpan payload) + { + var resource = CreateResource(new Dictionary()); + var spans = new List(); + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + if (field.WireType != ProtobufWireType.LengthDelimited) + continue; + + if (field.Number == 1) + resource = CreateResource(ParseResourceAttributes(field.Bytes)); + else if (field.Number == 2) + spans.AddRange(ParseScopeSpans(field.Bytes, resource.Id)); + } + + return (resource, spans); + } + + private static List ParseScopeSpans(ReadOnlySpan payload, string resourceId) + { + var spans = new List(); + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + if (field.Number == 2 && field.WireType == ProtobufWireType.LengthDelimited) + spans.Add(ParseSpan(field.Bytes, resourceId)); + } + + return spans; + } + + private static TelemetrySpan ParseSpan(ReadOnlySpan payload, string resourceId) + { + var traceId = ""; + var spanId = ""; + string? parentSpanId = null; + var name = ""; + var kind = "unspecified"; + var start = DateTimeOffset.UnixEpoch; + var end = DateTimeOffset.UnixEpoch; + var status = SpanStatus.Unset; + string? statusDescription = null; + var attributes = new Dictionary(StringComparer.OrdinalIgnoreCase); + var events = new List(); + var links = new List(); + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + switch (field.Number) + { + case 1 when field.WireType == ProtobufWireType.LengthDelimited: + traceId = ToHex(field.Bytes); + break; + case 2 when field.WireType == ProtobufWireType.LengthDelimited: + spanId = ToHex(field.Bytes); + break; + case 4 when field.WireType == ProtobufWireType.LengthDelimited: + parentSpanId = ToHex(field.Bytes); + break; + case 5 when field.WireType == ProtobufWireType.LengthDelimited: + name = field.StringValue(); + break; + case 6: + kind = SpanKindName(field.Varint); + break; + case 7: + start = FromUnixNanos(field.Varint); + break; + case 8: + end = FromUnixNanos(field.Varint); + break; + case 9 when field.WireType == ProtobufWireType.LengthDelimited: + AddAttribute(attributes, field.Bytes); + break; + case 11 when field.WireType == ProtobufWireType.LengthDelimited: + events.Add(ParseSpanEvent(field.Bytes)); + break; + case 12 when field.WireType == ProtobufWireType.LengthDelimited: + links.Add(ParseSpanLink(field.Bytes)); + break; + case 15 when field.WireType == ProtobufWireType.LengthDelimited: + (status, statusDescription) = ParseSpanStatus(field.Bytes); + break; + } + } + + if (end < start) + end = start; + + return new TelemetrySpan($"{traceId}:{spanId}", traceId, spanId, parentSpanId, resourceId, name, kind, start, end, status, statusDescription, attributes, events, links); + } + + private static TelemetrySpanEvent ParseSpanEvent(ReadOnlySpan payload) + { + var timestamp = DateTimeOffset.UnixEpoch; + var name = ""; + var attributes = new Dictionary(StringComparer.OrdinalIgnoreCase); + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + if (field.Number == 1) + timestamp = FromUnixNanos(field.Varint); + else if (field.Number == 2 && field.WireType == ProtobufWireType.LengthDelimited) + name = field.StringValue(); + else if (field.Number == 3 && field.WireType == ProtobufWireType.LengthDelimited) + AddAttribute(attributes, field.Bytes); + } + + return new TelemetrySpanEvent(name, timestamp, attributes); + } + + private static TelemetrySpanLink ParseSpanLink(ReadOnlySpan payload) + { + var traceId = ""; + var spanId = ""; + var attributes = new Dictionary(StringComparer.OrdinalIgnoreCase); + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + if (field.Number == 1 && field.WireType == ProtobufWireType.LengthDelimited) + traceId = ToHex(field.Bytes); + else if (field.Number == 2 && field.WireType == ProtobufWireType.LengthDelimited) + spanId = ToHex(field.Bytes); + else if (field.Number == 3 && field.WireType == ProtobufWireType.LengthDelimited) + AddAttribute(attributes, field.Bytes); + } + + return new TelemetrySpanLink(traceId, spanId, attributes); + } + + private static (SpanStatus Status, string? Description) ParseSpanStatus(ReadOnlySpan payload) + { + var status = SpanStatus.Unset; + string? description = null; + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + if (field.Number == 2 && field.WireType == ProtobufWireType.LengthDelimited) + description = field.StringValue(); + else if (field.Number == 3) + status = field.Varint switch + { + 1 => SpanStatus.Ok, + 2 => SpanStatus.Error, + _ => SpanStatus.Unset + }; + } + + return (status, description); + } + + private static (TelemetryResource Resource, List Instruments, List Points) ParseResourceMetrics(ReadOnlySpan payload) + { + var resource = CreateResource(new Dictionary()); + var instruments = new List(); + var points = new List(); + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + if (field.WireType != ProtobufWireType.LengthDelimited) + continue; + + if (field.Number == 1) + resource = CreateResource(ParseResourceAttributes(field.Bytes)); + else if (field.Number == 2) + ParseScopeMetrics(field.Bytes, resource.Id, instruments, points); + } + + return (resource, instruments, points); + } + + private static void ParseScopeMetrics(ReadOnlySpan payload, string resourceId, ICollection instruments, ICollection points) + { + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + if (field.Number != 2 || field.WireType != ProtobufWireType.LengthDelimited) + continue; + + var metric = ParseMetric(field.Bytes, resourceId); + instruments.Add(metric.Instrument); + + foreach (var point in metric.Points) + points.Add(point); + } + } + + private static (MetricInstrument Instrument, List Points) ParseMetric(ReadOnlySpan payload, string resourceId) + { + var name = ""; + string? description = null; + string? unit = null; + var kind = MetricKind.Gauge; + var points = new List(); + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + switch (field.Number) + { + case 1 when field.WireType == ProtobufWireType.LengthDelimited: + name = field.StringValue(); + break; + case 2 when field.WireType == ProtobufWireType.LengthDelimited: + description = field.StringValue(); + break; + case 3 when field.WireType == ProtobufWireType.LengthDelimited: + unit = field.StringValue(); + break; + case 5 when field.WireType == ProtobufWireType.LengthDelimited: + kind = MetricKind.Gauge; + points.AddRange(ParseNumberDataPoints(field.Bytes, resourceId, () => $"{resourceId}:{name}:gauge")); + break; + case 7 when field.WireType == ProtobufWireType.LengthDelimited: + kind = MetricKind.Sum; + points.AddRange(ParseNumberDataPoints(field.Bytes, resourceId, () => $"{resourceId}:{name}:sum")); + break; + case 9 when field.WireType == ProtobufWireType.LengthDelimited: + kind = MetricKind.Histogram; + points.AddRange(ParseHistogramDataPoints(field.Bytes, resourceId, () => $"{resourceId}:{name}:histogram")); + break; + } + } + + var instrumentId = $"{resourceId}:{name}:{kind.ToString().ToLowerInvariant()}"; + var instrument = new MetricInstrument(instrumentId, resourceId, name, unit, description, kind, new Dictionary()); + points = points.Select(x => x with { InstrumentId = instrumentId, InstrumentName = name }).ToList(); + return (instrument, points); + } + + private static List ParseNumberDataPoints(ReadOnlySpan payload, string resourceId, Func instrumentIdFactory) + { + var points = new List(); + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + if (field.Number == 1 && field.WireType == ProtobufWireType.LengthDelimited) + points.Add(ParseNumberDataPoint(field.Bytes, resourceId, instrumentIdFactory())); + } + + return points; + } + + private static MetricPoint ParseNumberDataPoint(ReadOnlySpan payload, string resourceId, string instrumentId) + { + var timestamp = DateTimeOffset.UnixEpoch; + double? value = null; + var attributes = new Dictionary(StringComparer.OrdinalIgnoreCase); + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + if (field.Number == 3) + timestamp = FromUnixNanos(field.Varint); + else if (field.Number == 4 && field.WireType == ProtobufWireType.Fixed64) + value = field.DoubleValue; + else if (field.Number == 6) + value = (long)field.Varint; + else if (field.Number == 7 && field.WireType == ProtobufWireType.LengthDelimited) + AddAttribute(attributes, field.Bytes); + } + + return new MetricPoint(Guid.NewGuid().ToString("N"), instrumentId, "", resourceId, timestamp, value, null, null, attributes, null, null); + } + + private static List ParseHistogramDataPoints(ReadOnlySpan payload, string resourceId, Func instrumentIdFactory) + { + var points = new List(); + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + if (field.Number == 1 && field.WireType == ProtobufWireType.LengthDelimited) + points.Add(ParseHistogramDataPoint(field.Bytes, resourceId, instrumentIdFactory())); + } + + return points; + } + + private static MetricPoint ParseHistogramDataPoint(ReadOnlySpan payload, string resourceId, string instrumentId) + { + var timestamp = DateTimeOffset.UnixEpoch; + long? count = null; + double? sum = null; + var attributes = new Dictionary(StringComparer.OrdinalIgnoreCase); + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + if (field.Number == 3) + timestamp = FromUnixNanos(field.Varint); + else if (field.Number == 4) + count = (long)field.Varint; + else if (field.Number == 5 && field.WireType == ProtobufWireType.Fixed64) + sum = field.DoubleValue; + else if (field.Number == 9 && field.WireType == ProtobufWireType.LengthDelimited) + AddAttribute(attributes, field.Bytes); + } + + return new MetricPoint(Guid.NewGuid().ToString("N"), instrumentId, "", resourceId, timestamp, null, sum, count, attributes, null, null); + } + + private static (TelemetryResource Resource, List Logs) ParseResourceLogs(ReadOnlySpan payload) + { + var resource = CreateResource(new Dictionary()); + var logs = new List(); + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + if (field.WireType != ProtobufWireType.LengthDelimited) + continue; + + if (field.Number == 1) + resource = CreateResource(ParseResourceAttributes(field.Bytes)); + else if (field.Number == 2) + logs.AddRange(ParseScopeLogs(field.Bytes, resource.Id)); + } + + return (resource, logs); + } + + private static List ParseScopeLogs(ReadOnlySpan payload, string resourceId) + { + var logs = new List(); + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + if (field.Number == 2 && field.WireType == ProtobufWireType.LengthDelimited) + logs.Add(ParseLogRecord(field.Bytes, resourceId)); + } + + return logs; + } + + private static OtlpLogRecord ParseLogRecord(ReadOnlySpan payload, string resourceId) + { + var timestamp = DateTimeOffset.UnixEpoch; + var severityText = ""; + int? severityNumber = null; + var body = ""; + string? traceId = null; + string? spanId = null; + var attributes = new Dictionary(StringComparer.OrdinalIgnoreCase); + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + switch (field.Number) + { + case 1: + timestamp = FromUnixNanos(field.Varint); + break; + case 2: + severityNumber = (int)field.Varint; + break; + case 3 when field.WireType == ProtobufWireType.LengthDelimited: + severityText = field.StringValue(); + break; + case 5 when field.WireType == ProtobufWireType.LengthDelimited: + body = ParseAnyValue(field.Bytes) ?? ""; + break; + case 6 when field.WireType == ProtobufWireType.LengthDelimited: + AddAttribute(attributes, field.Bytes); + break; + case 9 when field.WireType == ProtobufWireType.LengthDelimited: + traceId = ToHex(field.Bytes); + break; + case 10 when field.WireType == ProtobufWireType.LengthDelimited: + spanId = ToHex(field.Bytes); + break; + } + } + + if (string.IsNullOrWhiteSpace(severityText) && severityNumber != null) + severityText = SeverityName(severityNumber.Value); + + return new OtlpLogRecord(Guid.NewGuid().ToString("N"), resourceId, timestamp, severityText, severityNumber, body, traceId, spanId, attributes); + } + + private static Dictionary ParseResourceAttributes(ReadOnlySpan payload) + { + var attributes = new Dictionary(StringComparer.OrdinalIgnoreCase); + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + if (field.Number == 1 && field.WireType == ProtobufWireType.LengthDelimited) + AddAttribute(attributes, field.Bytes); + } + + return attributes; + } + + private static void AddAttribute(IDictionary attributes, ReadOnlySpan payload) + { + string? key = null; + string? value = null; + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + if (field.Number == 1 && field.WireType == ProtobufWireType.LengthDelimited) + key = field.StringValue(); + else if (field.Number == 2 && field.WireType == ProtobufWireType.LengthDelimited) + value = ParseAnyValue(field.Bytes); + } + + if (!string.IsNullOrWhiteSpace(key)) + attributes[key] = value; + } + + private static string? ParseAnyValue(ReadOnlySpan payload) + { + var reader = new ProtobufReader(payload); + + while (reader.TryReadField(out var field)) + { + return field.Number switch + { + 1 when field.WireType == ProtobufWireType.LengthDelimited => field.StringValue(), + 2 => field.Varint != 0 ? "true" : "false", + 3 => ((long)field.Varint).ToString(CultureInfo.InvariantCulture), + 4 when field.WireType == ProtobufWireType.Fixed64 => field.DoubleValue.ToString(CultureInfo.InvariantCulture), + 7 when field.WireType == ProtobufWireType.LengthDelimited => ToHex(field.Bytes), + _ => null + }; + } + + return null; + } + + private static TelemetryResource CreateResource(IDictionary attributes) + { + var serviceName = GetAttribute(attributes, "service.name") ?? "unknown_service"; + var instanceId = GetAttribute(attributes, "service.instance.id"); + var resourceId = string.IsNullOrWhiteSpace(instanceId) ? serviceName : $"{serviceName}:{instanceId}"; + return new TelemetryResource(resourceId, serviceName, instanceId, GetAttribute(attributes, "telemetry.sdk.language"), new Dictionary(attributes, StringComparer.OrdinalIgnoreCase), DateTimeOffset.UtcNow, TelemetryResourceStatus.Active); + } + + private static OpenTelemetryBatch CreateBatch( + IReadOnlyCollection resources, + IReadOnlyCollection spans, + IReadOnlyCollection instruments, + IReadOnlyCollection points, + IReadOnlyCollection logs) + { + var traces = spans + .GroupBy(x => x.TraceId, StringComparer.OrdinalIgnoreCase) + .Select(CreateTrace) + .ToList(); + + return new OpenTelemetryBatch(resources.DistinctBy(x => x.Id).ToList(), traces, spans.ToList(), instruments.ToList(), points.ToList(), logs.ToList()); + } + + private static TelemetryTrace CreateTrace(IGrouping spans) + { + var orderedSpans = spans.OrderBy(x => x.StartTime).ToList(); + var root = orderedSpans.FirstOrDefault(x => string.IsNullOrWhiteSpace(x.ParentSpanId)) ?? orderedSpans[0]; + var start = orderedSpans.Min(x => x.StartTime); + var end = orderedSpans.Max(x => x.EndTime); + var status = orderedSpans.Any(x => x.Status == SpanStatus.Error) ? SpanStatus.Error : orderedSpans.Any(x => x.Status == SpanStatus.Ok) ? SpanStatus.Ok : SpanStatus.Unset; + var workflowInstanceIds = orderedSpans + .Select(x => GetAttribute(x.Attributes, "workflow.instance.id")) + .Where(x => !string.IsNullOrWhiteSpace(x)) + .Select(x => x!) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + return new TelemetryTrace(spans.Key, root.SpanId, root.Name, start, end, end - start, status, orderedSpans.Select(x => x.ResourceId).Distinct(StringComparer.OrdinalIgnoreCase).ToList(), workflowInstanceIds, orderedSpans.Count); + } + + private static string? GetAttribute(IDictionary attributes, string key) => attributes.TryGetValue(key, out var value) ? value : null; + + private static DateTimeOffset FromUnixNanos(ulong value) + { + try + { + var ticks = checked((long)(value / 100)); + return DateTimeOffset.UnixEpoch.AddTicks(ticks); + } + catch (Exception e) when (e is OverflowException or ArgumentOutOfRangeException) + { + throw new InvalidDataException("The OTLP timestamp is outside the supported range.", e); + } + } + + private static string ToHex(ReadOnlySpan bytes) + { + return Convert.ToHexString(bytes).ToLowerInvariant(); + } + + private static string SpanKindName(ulong value) => value switch + { + 1 => "internal", + 2 => "server", + 3 => "client", + 4 => "producer", + 5 => "consumer", + _ => "unspecified" + }; + + private static string SeverityName(int value) => value switch + { + >= 21 => "Fatal", + >= 17 => "Error", + >= 13 => "Warning", + >= 9 => "Information", + >= 5 => "Debug", + >= 1 => "Trace", + _ => "Unspecified" + }; + + private enum ProtobufWireType + { + Varint = 0, + Fixed64 = 1, + LengthDelimited = 2, + Fixed32 = 5 + } + + private readonly ref struct ProtobufField + { + public ProtobufField(int number, ProtobufWireType wireType, ulong varint, ReadOnlySpan bytes, double doubleValue) + { + Number = number; + WireType = wireType; + Varint = varint; + Bytes = bytes; + DoubleValue = doubleValue; + } + + public int Number { get; } + public ProtobufWireType WireType { get; } + public ulong Varint { get; } + public ReadOnlySpan Bytes { get; } + public double DoubleValue { get; } + + public string StringValue() => Encoding.UTF8.GetString(Bytes); + } + + private ref struct ProtobufReader + { + private ReadOnlySpan _remaining; + + public ProtobufReader(ReadOnlySpan payload) + { + _remaining = payload; + } + + public bool TryReadField(out ProtobufField field) + { + field = default; + + if (_remaining.IsEmpty) + return false; + + var tag = ReadVarint(); + var number = (int)(tag >> 3); + var wireType = (ProtobufWireType)(tag & 7); + + switch (wireType) + { + case ProtobufWireType.Varint: + field = new ProtobufField(number, wireType, ReadVarint(), default, default); + return true; + case ProtobufWireType.Fixed64: + EnsureAvailable(8); + var fixed64 = BinaryPrimitives.ReadUInt64LittleEndian(_remaining[..8]); + _remaining = _remaining[8..]; + field = new ProtobufField(number, wireType, fixed64, default, BitConverter.Int64BitsToDouble((long)fixed64)); + return true; + case ProtobufWireType.LengthDelimited: + var length = checked((int)ReadVarint()); + EnsureAvailable(length); + var bytes = _remaining[..length]; + _remaining = _remaining[length..]; + field = new ProtobufField(number, wireType, default, bytes, default); + return true; + case ProtobufWireType.Fixed32: + EnsureAvailable(4); + _remaining = _remaining[4..]; + field = new ProtobufField(number, wireType, default, default, default); + return true; + default: + throw new InvalidDataException($"Unsupported protobuf wire type '{wireType}'."); + } + } + + private ulong ReadVarint() + { + ulong value = 0; + var shift = 0; + + for (var i = 0; i < 10; i++) + { + if (_remaining.IsEmpty) + throw new InvalidDataException("Unexpected end of protobuf payload."); + + var b = _remaining[0]; + _remaining = _remaining[1..]; + value |= (ulong)(b & 0x7f) << shift; + + if ((b & 0x80) == 0) + return value; + + shift += 7; + } + + throw new InvalidDataException("Invalid protobuf varint."); + } + + private readonly void EnsureAvailable(int byteCount) + { + if (_remaining.Length < byteCount) + throw new InvalidDataException("Unexpected end of protobuf payload."); + } + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Ingestion/OtlpIngestionSecurity.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Ingestion/OtlpIngestionSecurity.cs new file mode 100644 index 000000000..b8d13ddac --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Ingestion/OtlpIngestionSecurity.cs @@ -0,0 +1,44 @@ +using System.Net; +using System.Security.Cryptography; +using System.Text; +using Elsa.Diagnostics.OpenTelemetry.Options; +using Microsoft.AspNetCore.Http; + +namespace Elsa.Diagnostics.OpenTelemetry.Ingestion; + +public static class OtlpIngestionSecurity +{ + public static bool IsAuthorized(HttpContext httpContext, OpenTelemetryDiagnosticsOptions options) + { + if (string.IsNullOrWhiteSpace(options.ApiKey)) + return options.AllowUnauthenticatedLoopback && IsLoopback(httpContext); + + return httpContext.Request.Headers.TryGetValue(options.ApiKeyHeaderName, out var value) && ApiKeysMatch(value.ToString(), options.ApiKey); + } + + private static bool IsLoopback(HttpContext httpContext) + { + var remoteAddress = httpContext.Connection.RemoteIpAddress; + return remoteAddress != null && IPAddress.IsLoopback(remoteAddress); + } + + private static bool ApiKeysMatch(string providedApiKey, string expectedApiKey) + { + var providedBytes = Encoding.UTF8.GetBytes(providedApiKey); + var expectedBytes = Encoding.UTF8.GetBytes(expectedApiKey); + var providedHash = SHA256.HashData(providedBytes); + var expectedHash = SHA256.HashData(expectedBytes); + + try + { + return CryptographicOperations.FixedTimeEquals(providedHash, expectedHash); + } + finally + { + CryptographicOperations.ZeroMemory(providedBytes); + CryptographicOperations.ZeroMemory(expectedBytes); + CryptographicOperations.ZeroMemory(providedHash); + CryptographicOperations.ZeroMemory(expectedHash); + } + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Models/OpenTelemetryContracts.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Models/OpenTelemetryContracts.cs new file mode 100644 index 000000000..8f2d3dc77 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Models/OpenTelemetryContracts.cs @@ -0,0 +1,86 @@ +namespace Elsa.Diagnostics.OpenTelemetry.Models; + +public record OpenTelemetryResourceFilter +{ + public string? Search { get; init; } + public string? ServiceName { get; init; } + public TelemetryResourceStatus? Status { get; init; } + public int? Take { get; init; } +} + +public record OpenTelemetryTraceFilter +{ + public string? ResourceId { get; init; } + public string? ServiceName { get; init; } + public string? TraceId { get; init; } + public string? WorkflowInstanceId { get; init; } + public SpanStatus? Status { get; init; } + public DateTimeOffset? From { get; init; } + public DateTimeOffset? To { get; init; } + public string? Search { get; init; } + public int? Take { get; init; } +} + +public record OpenTelemetryMetricFilter +{ + public string? ResourceId { get; init; } + public string? ServiceName { get; init; } + public string? InstrumentName { get; init; } + public DateTimeOffset? From { get; init; } + public DateTimeOffset? To { get; init; } + public int? Take { get; init; } +} + +public record OpenTelemetryLogFilter +{ + public string? ResourceId { get; init; } + public string? ServiceName { get; init; } + public string? TraceId { get; init; } + public string? SpanId { get; init; } + public string? Severity { get; init; } + public DateTimeOffset? From { get; init; } + public DateTimeOffset? To { get; init; } + public string? Search { get; init; } + public int? Take { get; init; } +} + +public record OpenTelemetryResourceResult(IReadOnlyCollection Items, long DroppedCount); + +public record OpenTelemetryTraceResult(IReadOnlyCollection Items, long DroppedCount); + +public record OpenTelemetryTraceDetail( + TelemetryTrace Trace, + IReadOnlyCollection Spans, + IReadOnlyCollection Resources, + IReadOnlyCollection Logs); + +public record OpenTelemetryMetricResult(IReadOnlyCollection Instruments, IReadOnlyCollection Points, long DroppedCount); + +public record OpenTelemetryLogResult(IReadOnlyCollection Items, long DroppedCount); + +public record CollectorEndpointInfo(string Protocol, string? Endpoint, bool Enabled, string? DisabledReason); + +public record CollectorConfiguration( + CollectorEndpointInfo Http, + CollectorEndpointInfo Grpc, + string ServiceNameEnvironmentVariable, + string EndpointEnvironmentVariable, + string ProtocolEnvironmentVariable, + IReadOnlyDictionary RequiredHeaders); + +public record OpenTelemetryBatch( + IReadOnlyCollection Resources, + IReadOnlyCollection Traces, + IReadOnlyCollection Spans, + IReadOnlyCollection Instruments, + IReadOnlyCollection MetricPoints, + IReadOnlyCollection Logs); + +public record OpenTelemetryStreamItem +{ + public TelemetryResource? Resource { get; init; } + public TelemetryTrace? Trace { get; init; } + public MetricPoint? MetricPoint { get; init; } + public OtlpLogRecord? Log { get; init; } + public OpenTelemetryDroppedItemSummary? DroppedItems { get; init; } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Models/OpenTelemetryModels.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Models/OpenTelemetryModels.cs new file mode 100644 index 000000000..4e201fce8 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Models/OpenTelemetryModels.cs @@ -0,0 +1,127 @@ +namespace Elsa.Diagnostics.OpenTelemetry.Models; + +public enum OpenTelemetrySignalType +{ + Trace, + Metric, + Log +} + +public enum TelemetryResourceStatus +{ + Unknown, + Active, + Stale +} + +public enum SpanStatus +{ + Unset, + Ok, + Error +} + +public enum MetricKind +{ + Gauge, + Sum, + Histogram +} + +public record TelemetryResource( + string Id, + string ServiceName, + string? ServiceInstanceId, + string? TelemetrySdkLanguage, + IDictionary Attributes, + DateTimeOffset LastSeen, + TelemetryResourceStatus Status); + +public record TelemetrySpan( + string Id, + string TraceId, + string SpanId, + string? ParentSpanId, + string ResourceId, + string Name, + string Kind, + DateTimeOffset StartTime, + DateTimeOffset EndTime, + SpanStatus Status, + string? StatusDescription, + IDictionary Attributes, + IReadOnlyCollection Events, + IReadOnlyCollection Links); + +public record TelemetrySpanEvent( + string Name, + DateTimeOffset Timestamp, + IDictionary Attributes); + +public record TelemetrySpanLink( + string TraceId, + string SpanId, + IDictionary Attributes); + +public record TelemetryTrace( + string TraceId, + string? RootSpanId, + string? Name, + DateTimeOffset StartTime, + DateTimeOffset EndTime, + TimeSpan Duration, + SpanStatus Status, + IReadOnlyCollection ResourceIds, + IReadOnlyCollection WorkflowInstanceIds, + int SpanCount); + +public record MetricInstrument( + string Id, + string ResourceId, + string Name, + string? Unit, + string? Description, + MetricKind Kind, + IDictionary Attributes); + +public record MetricPoint( + string Id, + string InstrumentId, + string InstrumentName, + string ResourceId, + DateTimeOffset Timestamp, + double? Value, + double? Sum, + long? Count, + IDictionary Attributes, + string? TraceId, + string? SpanId); + +public record OtlpLogRecord( + string Id, + string ResourceId, + DateTimeOffset Timestamp, + string SeverityText, + int? SeverityNumber, + string Body, + string? TraceId, + string? SpanId, + IDictionary Attributes); + +public record OpenTelemetryDroppedItemSummary(OpenTelemetrySignalType SignalType, long Count, string Reason); + +public record OpenTelemetryStorageDiagnostics( + int TraceCapacity, + int SpanCapacity, + int MetricPointCapacity, + int LogRecordCapacity, + int ResourceCount, + int TraceCount, + int SpanCount, + int MetricInstrumentCount, + int MetricPointCount, + int LogRecordCount, + long DroppedTraceCount, + long DroppedSpanCount, + long DroppedMetricPointCount, + long DroppedLogRecordCount); diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Options/OpenTelemetryDiagnosticsOptions.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Options/OpenTelemetryDiagnosticsOptions.cs new file mode 100644 index 000000000..5d2d4b11a --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Options/OpenTelemetryDiagnosticsOptions.cs @@ -0,0 +1,43 @@ +namespace Elsa.Diagnostics.OpenTelemetry.Options; + +public class OpenTelemetryDiagnosticsOptions +{ + public int TraceCapacity { get; set; } = 5_000; + public int SpanCapacity { get; set; } = 25_000; + public int MetricPointCapacity { get; set; } = 25_000; + public int LogRecordCapacity { get; set; } = 10_000; + public int ResourceCapacity { get; set; } = 500; + public int SubscriberChannelCapacity { get; set; } = 1_000; + public int MaxQuerySize { get; set; } = 1_000; + public long MaxHttpRequestBodySize { get; set; } = 10 * 1024 * 1024; + public string HttpEndpointPath { get; set; } = "/elsa/otlp/v1"; + public string? GrpcEndpointPath { get; set; } + public string GrpcDisabledReason { get; set; } = "gRPC ingestion is not enabled for this host."; + public string HubRoute { get; set; } = "/elsa/hubs/diagnostics/opentelemetry"; + public bool EnableGrpc { get; set; } + public string? ApiKey { get; set; } + public string ApiKeyHeaderName { get; set; } = "x-otlp-api-key"; + public bool AllowUnauthenticatedLoopback { get; set; } = true; + + public ICollection SensitiveNames { get; set; } = + [ + "authorization", + "token", + "password", + "secret", + "api-key", + "apikey", + "cookie", + "connection-string", + "connectionstring" + ]; + + public ICollection SensitiveTextPatterns { get; set; } = + [ + "(?i)bearer\\s+[A-Za-z0-9._~+/=-]+", + "(?i)(password|secret|token|api[-_]?key)\\s*[=:]\\s*[^\\s,;]+", + "(?i)(AccountKey|SharedAccessKey)=([^;\\s]+)" + ]; + + public TimeSpan SensitiveTextPatternTimeout { get; set; } = TimeSpan.FromMilliseconds(100); +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Permissions/OpenTelemetryPermissions.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Permissions/OpenTelemetryPermissions.cs new file mode 100644 index 000000000..47bb415b5 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Permissions/OpenTelemetryPermissions.cs @@ -0,0 +1,7 @@ +namespace Elsa.Diagnostics.OpenTelemetry.Permissions; + +public static class OpenTelemetryPermissions +{ + public const string Read = "read:diagnostics:opentelemetry"; + public const string Ingest = "ingest:diagnostics:opentelemetry"; +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Providers/InMemory/InMemoryOpenTelemetryLiveFeed.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Providers/InMemory/InMemoryOpenTelemetryLiveFeed.cs new file mode 100644 index 000000000..ab48b6d3a --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Providers/InMemory/InMemoryOpenTelemetryLiveFeed.cs @@ -0,0 +1,293 @@ +using System.Runtime.CompilerServices; +using System.Threading.Channels; +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Options; +using Microsoft.Extensions.Options; + +namespace Elsa.Diagnostics.OpenTelemetry.Providers.InMemory; + +public class InMemoryOpenTelemetryLiveFeed(IOptions options) : IOpenTelemetryLiveFeed +{ + private readonly OpenTelemetryDiagnosticsOptions _options = options.Value; + private readonly object _subscribersLock = new(); + private readonly List _subscribers = []; + + public ValueTask PublishAsync(OpenTelemetryBatch batch, CancellationToken cancellationToken = default) + { + List subscribers; + lock (_subscribersLock) + subscribers = _subscribers.ToList(); + + foreach (var subscriber in subscribers) + subscriber.TryWrite(batch); + + return ValueTask.CompletedTask; + } + + public async IAsyncEnumerable SubscribeAsync(OpenTelemetryTraceFilter filter, [EnumeratorCancellation] CancellationToken cancellationToken = default) + { + var subscriber = new OpenTelemetrySubscriber(filter, _options.SubscriberChannelCapacity); + + lock (_subscribersLock) + _subscribers.Add(subscriber); + + try + { + await foreach (var item in subscriber.Channel.Reader.ReadAllAsync(cancellationToken)) + { + subscriber.MarkRead(item); + yield return item; + } + } + finally + { + lock (_subscribersLock) + _subscribers.Remove(subscriber); + } + } + + private sealed class OpenTelemetrySubscriber(OpenTelemetryTraceFilter filter, int channelCapacity) + { + private readonly object _lock = new(); + private readonly int _capacity = Math.Max(1, channelCapacity); + private int _pendingItemCount; + private readonly Dictionary _droppedSinceLastSummary = []; + + public Channel Channel { get; } = System.Threading.Channels.Channel.CreateBounded(new BoundedChannelOptions(Math.Max(1, channelCapacity)) + { + SingleReader = true, + SingleWriter = false, + FullMode = BoundedChannelFullMode.Wait + }); + + public void TryWrite(OpenTelemetryBatch batch) + { + var serviceResourceIds = ResolveServiceResourceIds(batch.Resources); + + foreach (var resource in batch.Resources.Where(MatchesResource)) + TryWrite(new OpenTelemetryStreamItem { Resource = resource }); + + foreach (var trace in batch.Traces.Where(trace => MatchesTrace(trace, serviceResourceIds))) + TryWrite(new OpenTelemetryStreamItem { Trace = trace }); + + foreach (var log in batch.Logs.Where(log => MatchesLog(log, serviceResourceIds))) + TryWrite(new OpenTelemetryStreamItem { Log = log }); + + foreach (var point in batch.MetricPoints.Where(point => MatchesMetricPoint(point, serviceResourceIds))) + TryWrite(new OpenTelemetryStreamItem { MetricPoint = point }); + } + + private void TryWrite(OpenTelemetryStreamItem item) + { + lock (_lock) + { + EnsureCapacityForWrite(); + if (Channel.Writer.TryWrite(item)) + _pendingItemCount++; + else + TrackDrop(item); + + TryWriteDroppedSummary(); + } + } + + public void MarkRead(OpenTelemetryStreamItem item) + { + lock (_lock) + { + _pendingItemCount = Math.Max(0, _pendingItemCount - 1); + + if (item.DroppedItems != null) + _droppedSinceLastSummary.Remove(item.DroppedItems.SignalType); + + TryWriteDroppedSummary(); + } + } + + private void EnsureCapacityForWrite() + { + if (_pendingItemCount < _capacity) + return; + + if (!Channel.Reader.TryRead(out var dropped)) + return; + + _pendingItemCount = Math.Max(0, _pendingItemCount - 1); + TrackDrop(dropped); + } + + private void TrackDrop(OpenTelemetryStreamItem item) + { + var signalType = GetSignalType(item); + if (signalType == null) + return; + + _droppedSinceLastSummary.TryGetValue(signalType.Value, out var count); + _droppedSinceLastSummary[signalType.Value] = count + (item.DroppedItems?.Count ?? 1); + } + + private void TryWriteDroppedSummary() + { + if (_droppedSinceLastSummary.Count == 0) + return; + + if (_pendingItemCount >= _capacity) + return; + + var dropped = _droppedSinceLastSummary.OrderBy(x => x.Key).First(); + if (Channel.Writer.TryWrite(new OpenTelemetryStreamItem { DroppedItems = new(dropped.Key, dropped.Value, "SubscriberQueueFull") })) + _pendingItemCount++; + } + + private static OpenTelemetrySignalType? GetSignalType(OpenTelemetryStreamItem item) + { + if (item.Trace != null) + return OpenTelemetrySignalType.Trace; + + if (item.MetricPoint != null) + return OpenTelemetrySignalType.Metric; + + if (item.Log != null) + return OpenTelemetrySignalType.Log; + + return item.DroppedItems?.SignalType; + } + + private bool MatchesResource(TelemetryResource resource) + { + if (!string.IsNullOrWhiteSpace(filter.TraceId)) + return false; + + if (!string.IsNullOrWhiteSpace(filter.WorkflowInstanceId)) + return false; + + if (filter.Status != null) + return false; + + if (!string.IsNullOrWhiteSpace(filter.ResourceId) && !EqualsIgnoreCase(resource.Id, filter.ResourceId)) + return false; + + if (!string.IsNullOrWhiteSpace(filter.ServiceName) && !EqualsIgnoreCase(resource.ServiceName, filter.ServiceName)) + return false; + + if (filter.From != null && resource.LastSeen < filter.From) + return false; + + if (filter.To != null && resource.LastSeen > filter.To) + return false; + + if (!string.IsNullOrWhiteSpace(filter.Search) && !Matches(resource.Id, filter.Search) && !Matches(resource.ServiceName, filter.Search)) + return false; + + return true; + } + + private bool MatchesTrace(TelemetryTrace trace, HashSet? serviceResourceIds) + { + if (!string.IsNullOrWhiteSpace(filter.TraceId) && !EqualsIgnoreCase(trace.TraceId, filter.TraceId)) + return false; + + if (filter.Status != null && trace.Status != filter.Status) + return false; + + if (filter.From != null && trace.StartTime < filter.From) + return false; + + if (filter.To != null && trace.StartTime > filter.To) + return false; + + if (!string.IsNullOrWhiteSpace(filter.WorkflowInstanceId) && !trace.WorkflowInstanceIds.Any(id => Matches(id, filter.WorkflowInstanceId))) + return false; + + if (!string.IsNullOrWhiteSpace(filter.ResourceId) && !trace.ResourceIds.Contains(filter.ResourceId, StringComparer.OrdinalIgnoreCase)) + return false; + + if (serviceResourceIds != null && !trace.ResourceIds.Any(serviceResourceIds.Contains)) + return false; + + if (!string.IsNullOrWhiteSpace(filter.Search) && !Matches(trace.TraceId, filter.Search) && !Matches(trace.Name, filter.Search)) + return false; + + return true; + } + + private bool MatchesLog(OtlpLogRecord log, HashSet? serviceResourceIds) + { + if (filter.Status != null) + return false; + + if (!string.IsNullOrWhiteSpace(filter.ResourceId) && !EqualsIgnoreCase(log.ResourceId, filter.ResourceId)) + return false; + + if (serviceResourceIds != null && !serviceResourceIds.Contains(log.ResourceId)) + return false; + + if (!string.IsNullOrWhiteSpace(filter.TraceId) && !EqualsIgnoreCase(log.TraceId, filter.TraceId)) + return false; + + if (!string.IsNullOrWhiteSpace(filter.WorkflowInstanceId) && !AttributeMatches(log.Attributes, "workflow.instance.id", filter.WorkflowInstanceId)) + return false; + + if (filter.From != null && log.Timestamp < filter.From) + return false; + + if (filter.To != null && log.Timestamp > filter.To) + return false; + + if (!string.IsNullOrWhiteSpace(filter.Search) && !Matches(log.Body, filter.Search)) + return false; + + return true; + } + + private bool MatchesMetricPoint(MetricPoint point, HashSet? serviceResourceIds) + { + if (filter.Status != null) + return false; + + if (!string.IsNullOrWhiteSpace(filter.ResourceId) && !EqualsIgnoreCase(point.ResourceId, filter.ResourceId)) + return false; + + if (serviceResourceIds != null && !serviceResourceIds.Contains(point.ResourceId)) + return false; + + if (!string.IsNullOrWhiteSpace(filter.TraceId) && !EqualsIgnoreCase(point.TraceId, filter.TraceId)) + return false; + + if (!string.IsNullOrWhiteSpace(filter.WorkflowInstanceId) && !AttributeMatches(point.Attributes, "workflow.instance.id", filter.WorkflowInstanceId)) + return false; + + if (filter.From != null && point.Timestamp < filter.From) + return false; + + if (filter.To != null && point.Timestamp > filter.To) + return false; + + if (!string.IsNullOrWhiteSpace(filter.Search) && !Matches(point.InstrumentName, filter.Search) && !Matches(point.InstrumentId, filter.Search)) + return false; + + return true; + } + + private HashSet? ResolveServiceResourceIds(IEnumerable resources) + { + if (string.IsNullOrWhiteSpace(filter.ServiceName)) + return null; + + return resources + .Where(x => EqualsIgnoreCase(x.ServiceName, filter.ServiceName)) + .Select(x => x.Id) + .ToHashSet(StringComparer.OrdinalIgnoreCase); + } + + private static bool AttributeMatches(IDictionary attributes, string key, string? search) + { + return attributes.TryGetValue(key, out var value) && Matches(value, search); + } + + private static bool EqualsIgnoreCase(string? candidate, string? search) => string.Equals(candidate, search, StringComparison.OrdinalIgnoreCase); + + private static bool Matches(string? candidate, string? search) => !string.IsNullOrEmpty(candidate) && !string.IsNullOrEmpty(search) && candidate.Contains(search, StringComparison.OrdinalIgnoreCase); + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Providers/InMemory/InMemoryOpenTelemetryStore.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Providers/InMemory/InMemoryOpenTelemetryStore.cs new file mode 100644 index 000000000..93ba58d27 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Providers/InMemory/InMemoryOpenTelemetryStore.cs @@ -0,0 +1,227 @@ +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Options; +using Microsoft.Extensions.Options; + +namespace Elsa.Diagnostics.OpenTelemetry.Providers.InMemory; + +public class InMemoryOpenTelemetryStore : IOpenTelemetryStore +{ + private readonly IOpenTelemetrySourceRegistry _sourceRegistry; + private readonly OpenTelemetryDiagnosticsOptions _options; + private readonly int _traceCapacity; + private readonly int _spanCapacity; + private readonly int _metricPointCapacity; + private readonly int _logRecordCapacity; + private readonly RingBuffer _traces; + private readonly RingBuffer _spans; + private readonly RingBuffer _metricPoints; + private readonly RingBuffer _logs; + private readonly object _instrumentLock = new(); + private readonly Dictionary _instruments = new(StringComparer.OrdinalIgnoreCase); + + public InMemoryOpenTelemetryStore(IOptions options, IOpenTelemetrySourceRegistry sourceRegistry) + { + _options = options.Value; + _sourceRegistry = sourceRegistry; + _traceCapacity = ClampCapacity(_options.TraceCapacity); + _spanCapacity = ClampCapacity(_options.SpanCapacity); + _metricPointCapacity = ClampCapacity(_options.MetricPointCapacity); + _logRecordCapacity = ClampCapacity(_options.LogRecordCapacity); + _traces = new(_traceCapacity); + _spans = new(_spanCapacity); + _metricPoints = new(_metricPointCapacity); + _logs = new(_logRecordCapacity); + } + + public ValueTask WriteAsync(OpenTelemetryBatch batch, CancellationToken cancellationToken = default) + { + foreach (var resource in batch.Resources) + _sourceRegistry.MarkSeen(resource); + + foreach (var trace in batch.Traces) + _traces.Add(trace); + + foreach (var span in batch.Spans) + _spans.Add(span); + + lock (_instrumentLock) + { + foreach (var instrument in batch.Instruments) + _instruments[instrument.Id] = instrument; + } + + foreach (var point in batch.MetricPoints) + _metricPoints.Add(point); + + foreach (var log in batch.Logs) + _logs.Add(log); + + return ValueTask.CompletedTask; + } + + public ValueTask QueryResourcesAsync(OpenTelemetryResourceFilter filter, CancellationToken cancellationToken = default) + { + var take = ClampTake(filter.Take); + var items = _sourceRegistry.List() + .Where(x => string.IsNullOrWhiteSpace(filter.ServiceName) || string.Equals(x.ServiceName, filter.ServiceName, StringComparison.OrdinalIgnoreCase)) + .Where(x => filter.Status == null || x.Status == filter.Status) + .Where(x => string.IsNullOrWhiteSpace(filter.Search) || Matches(x.ServiceName, filter.Search) || Matches(x.Id, filter.Search)) + .OrderByDescending(x => x.LastSeen) + .ThenBy(x => x.ServiceName, StringComparer.OrdinalIgnoreCase) + .Take(take) + .ToList(); + + return ValueTask.FromResult(new OpenTelemetryResourceResult(items, _sourceRegistry.DroppedCount)); + } + + public ValueTask QueryTracesAsync(OpenTelemetryTraceFilter filter, CancellationToken cancellationToken = default) + { + var take = ClampTake(filter.Take); + var serviceResourceIds = ResolveResourceIds(filter.ServiceName); + var items = _traces.Snapshot() + .Where(x => string.IsNullOrWhiteSpace(filter.TraceId) || Matches(x.TraceId, filter.TraceId)) + .Where(x => filter.Status == null || x.Status == filter.Status) + .Where(x => filter.From == null || x.StartTime >= filter.From) + .Where(x => filter.To == null || x.StartTime <= filter.To) + .Where(x => string.IsNullOrWhiteSpace(filter.WorkflowInstanceId) || x.WorkflowInstanceIds.Any(id => Matches(id, filter.WorkflowInstanceId))) + .Where(x => string.IsNullOrWhiteSpace(filter.ResourceId) || x.ResourceIds.Contains(filter.ResourceId, StringComparer.OrdinalIgnoreCase)) + .Where(x => serviceResourceIds == null || x.ResourceIds.Any(serviceResourceIds.Contains)) + .Where(x => string.IsNullOrWhiteSpace(filter.Search) || Matches(x.TraceId, filter.Search) || Matches(x.Name, filter.Search)) + .OrderBy(x => x.StartTime) + .GroupBy(x => x.TraceId, StringComparer.OrdinalIgnoreCase) + .Select(x => x.Last()) + .TakeLast(take) + .ToList(); + + return ValueTask.FromResult(new OpenTelemetryTraceResult(items, _traces.DroppedCount)); + } + + public ValueTask GetTraceAsync(string traceId, CancellationToken cancellationToken = default) + { + var trace = _traces.Snapshot().LastOrDefault(x => string.Equals(x.TraceId, traceId, StringComparison.OrdinalIgnoreCase)); + if (trace == null) + return ValueTask.FromResult(null); + + var spans = _spans.Snapshot() + .Where(x => string.Equals(x.TraceId, traceId, StringComparison.OrdinalIgnoreCase)) + .OrderBy(x => x.StartTime) + .ThenBy(x => x.SpanId, StringComparer.OrdinalIgnoreCase) + .ToList(); + var resourceIds = trace.ResourceIds.ToHashSet(StringComparer.OrdinalIgnoreCase); + var resources = _sourceRegistry.List() + .Where(x => resourceIds.Contains(x.Id)) + .OrderBy(x => x.ServiceName, StringComparer.OrdinalIgnoreCase) + .ThenBy(x => x.Id, StringComparer.OrdinalIgnoreCase) + .ToList(); + var logs = _logs.Snapshot() + .Where(x => string.Equals(x.TraceId, traceId, StringComparison.OrdinalIgnoreCase)) + .OrderBy(x => x.Timestamp) + .ThenBy(x => x.Id, StringComparer.OrdinalIgnoreCase) + .ToList(); + + return ValueTask.FromResult(new OpenTelemetryTraceDetail(trace, spans, resources, logs)); + } + + public ValueTask QueryMetricsAsync(OpenTelemetryMetricFilter filter, CancellationToken cancellationToken = default) + { + var take = ClampTake(filter.Take); + var serviceResourceIds = ResolveResourceIds(filter.ServiceName); + + Dictionary instruments; + lock (_instrumentLock) + instruments = new(_instruments, StringComparer.OrdinalIgnoreCase); + + var instrumentFilterIds = string.IsNullOrWhiteSpace(filter.InstrumentName) + ? null + : instruments.Values + .Where(x => Matches(x.Name, filter.InstrumentName)) + .Select(x => x.Id) + .ToHashSet(StringComparer.OrdinalIgnoreCase); + + var points = _metricPoints.Snapshot() + .Where(x => string.IsNullOrWhiteSpace(filter.ResourceId) || string.Equals(x.ResourceId, filter.ResourceId, StringComparison.OrdinalIgnoreCase)) + .Where(x => serviceResourceIds == null || serviceResourceIds.Contains(x.ResourceId)) + .Where(x => filter.From == null || x.Timestamp >= filter.From) + .Where(x => filter.To == null || x.Timestamp <= filter.To) + .Where(x => instrumentFilterIds == null || instrumentFilterIds.Contains(x.InstrumentId)) + .OrderBy(x => x.Timestamp) + .TakeLast(take) + .ToList(); + + var selectedInstruments = points + .Select(x => x.InstrumentId) + .Distinct(StringComparer.OrdinalIgnoreCase) + .Where(instruments.ContainsKey) + .Select(x => instruments[x]) + .ToList(); + + return ValueTask.FromResult(new OpenTelemetryMetricResult(selectedInstruments, points, _metricPoints.DroppedCount)); + } + + public ValueTask QueryLogsAsync(OpenTelemetryLogFilter filter, CancellationToken cancellationToken = default) + { + var take = ClampTake(filter.Take); + var serviceResourceIds = ResolveResourceIds(filter.ServiceName); + var logs = _logs.Snapshot() + .Where(x => string.IsNullOrWhiteSpace(filter.ResourceId) || string.Equals(x.ResourceId, filter.ResourceId, StringComparison.OrdinalIgnoreCase)) + .Where(x => serviceResourceIds == null || serviceResourceIds.Contains(x.ResourceId)) + .Where(x => string.IsNullOrWhiteSpace(filter.TraceId) || Matches(x.TraceId, filter.TraceId)) + .Where(x => string.IsNullOrWhiteSpace(filter.SpanId) || Matches(x.SpanId, filter.SpanId)) + .Where(x => string.IsNullOrWhiteSpace(filter.Severity) || Matches(x.SeverityText, filter.Severity)) + .Where(x => filter.From == null || x.Timestamp >= filter.From) + .Where(x => filter.To == null || x.Timestamp <= filter.To) + .Where(x => string.IsNullOrWhiteSpace(filter.Search) || Matches(x.Body, filter.Search)) + .OrderBy(x => x.Timestamp) + .TakeLast(take) + .ToList(); + + return ValueTask.FromResult(new OpenTelemetryLogResult(logs, _logs.DroppedCount)); + } + + public ValueTask GetDiagnosticsAsync(CancellationToken cancellationToken = default) + { + Dictionary instruments; + lock (_instrumentLock) + instruments = new(_instruments, StringComparer.OrdinalIgnoreCase); + + var traceSnapshot = _traces.Snapshot(); + var spanSnapshot = _spans.Snapshot(); + var metricPointSnapshot = _metricPoints.Snapshot(); + var logSnapshot = _logs.Snapshot(); + var diagnostics = new OpenTelemetryStorageDiagnostics( + _traceCapacity, + _spanCapacity, + _metricPointCapacity, + _logRecordCapacity, + _sourceRegistry.List().Count, + traceSnapshot.Count, + spanSnapshot.Count, + instruments.Count, + metricPointSnapshot.Count, + logSnapshot.Count, + _traces.DroppedCount, + _spans.DroppedCount, + _metricPoints.DroppedCount, + _logs.DroppedCount); + + return ValueTask.FromResult(diagnostics); + } + + private int ClampTake(int? take) => Math.Clamp(take ?? _options.MaxQuerySize, 0, _options.MaxQuerySize); + + private static int ClampCapacity(int capacity) => Math.Max(1, capacity); + + private HashSet? ResolveResourceIds(string? serviceName) + { + if (string.IsNullOrWhiteSpace(serviceName)) + return null; + + return _sourceRegistry.List() + .Where(x => string.Equals(x.ServiceName, serviceName, StringComparison.OrdinalIgnoreCase)) + .Select(x => x.Id) + .ToHashSet(StringComparer.OrdinalIgnoreCase); + } + + private static bool Matches(string? candidate, string? search) => !string.IsNullOrEmpty(candidate) && !string.IsNullOrEmpty(search) && candidate.Contains(search, StringComparison.OrdinalIgnoreCase); +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Providers/InMemory/RingBuffer.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Providers/InMemory/RingBuffer.cs new file mode 100644 index 000000000..cd9dc9cd9 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Providers/InMemory/RingBuffer.cs @@ -0,0 +1,46 @@ +namespace Elsa.Diagnostics.OpenTelemetry.Providers.InMemory; + +public class RingBuffer +{ + private readonly Queue _items = new(); + private readonly object _lock = new(); + private readonly int _capacity; + private long _droppedCount; + + public RingBuffer(int capacity) + { + if (capacity <= 0) + throw new ArgumentOutOfRangeException(nameof(capacity), "Capacity must be greater than zero."); + + _capacity = capacity; + } + + public long DroppedCount + { + get + { + lock (_lock) + return _droppedCount; + } + } + + public void Add(T item) + { + lock (_lock) + { + if (_items.Count == _capacity) + { + _items.Dequeue(); + _droppedCount++; + } + + _items.Enqueue(item); + } + } + + public IReadOnlyCollection Snapshot() + { + lock (_lock) + return _items.ToList(); + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/README.md b/src/modules/Elsa.Diagnostics.OpenTelemetry/README.md new file mode 100644 index 000000000..cf204accb --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/README.md @@ -0,0 +1,41 @@ +# Elsa Diagnostics OpenTelemetry + +Provides the OpenTelemetry diagnostics collector surface for Elsa hosts. + +This module owns the Core-side OTEL contracts, HTTP/protobuf ingestion, bounded in-memory diagnostics store, feature registration, permissions, read APIs, live update hub, and collector metadata that Studio consumes. + +## Scope + +`Elsa.Diagnostics.OpenTelemetry` is collector/read-side diagnostics infrastructure. It does not create workflow spans, mutate `Activity.Current`, export telemetry to vendors, or provide durable OpenTelemetry persistence. Workflow telemetry production remains owned by existing `Elsa.Workflows` `ActivitySource` and `Meter` instrumentation. + +The historical `Elsa.OpenTelemetry` module from `elsa-extensions` is intentionally not ported into this feature. It is producer-side workflow tracing middleware, duplicates current `Elsa.Workflows` instrumentation, and mutates `Activity.Current`; this module is collector/read-side diagnostics infrastructure. + +## Routes + +OTLP HTTP/protobuf ingestion is exposed under `OpenTelemetryDiagnosticsOptions.HttpEndpointPath`, which defaults to `/elsa/otlp/v1`: + +- `POST /elsa/otlp/v1/traces` +- `POST /elsa/otlp/v1/metrics` +- `POST /elsa/otlp/v1/logs` + +Diagnostics read APIs are exposed through Elsa API endpoints: + +- `POST /diagnostics/opentelemetry/resources/search` +- `POST /diagnostics/opentelemetry/traces/search` +- `GET /diagnostics/opentelemetry/traces/{traceId}` +- `POST /diagnostics/opentelemetry/metrics/search` +- `POST /diagnostics/opentelemetry/logs/search` +- `GET /diagnostics/opentelemetry/storage` +- `GET /diagnostics/opentelemetry/collector-configuration` + +Live updates are exposed through SignalR at `OpenTelemetryDiagnosticsOptions.HubRoute`, which defaults to `/elsa/hubs/diagnostics/opentelemetry`. + +## Security + +All diagnostics read APIs require the OpenTelemetry diagnostics read permission. OTLP ingestion allows unauthenticated loopback traffic by default for local development only when no API key is configured. When `OpenTelemetryDiagnosticsOptions.ApiKey` is set, every sender must provide the configured API key header, including loopback senders. + +Collector configuration returns endpoint and required-header names only. It never returns secret header values. + +## Storage + +The default provider is bounded in-memory storage. Capacity options cover traces, spans, metric points, OTLP log records, and live subscriber queues. When a buffer exceeds capacity, the oldest item for that signal is dropped and diagnostics counters are incremented. diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/RealTime/IOpenTelemetryClient.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/RealTime/IOpenTelemetryClient.cs new file mode 100644 index 000000000..e7242dbed --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/RealTime/IOpenTelemetryClient.cs @@ -0,0 +1,8 @@ +using Elsa.Diagnostics.OpenTelemetry.Models; + +namespace Elsa.Diagnostics.OpenTelemetry.RealTime; + +public interface IOpenTelemetryClient +{ + Task ReceiveAsync(OpenTelemetryStreamItem item); +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/RealTime/OpenTelemetryHub.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/RealTime/OpenTelemetryHub.cs new file mode 100644 index 000000000..eea15d662 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/RealTime/OpenTelemetryHub.cs @@ -0,0 +1,50 @@ +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Permissions; +using FastEndpoints.Security; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.SignalR; + +namespace Elsa.Diagnostics.OpenTelemetry.RealTime; + +[Authorize] +public class OpenTelemetryHub(OpenTelemetrySubscriptionManager subscriptionManager) : Hub +{ + private const string ReadAllPermission = "read:*"; + private static readonly string[] ReadPermissions = [PermissionNames.All, ReadAllPermission, OpenTelemetryPermissions.Read]; + + public Task SubscribeAsync(OpenTelemetryTraceFilter? filter) + { + EnsureCanReadOpenTelemetry(); + return subscriptionManager.SubscribeAsync(Context.ConnectionId, ValidateFilter(filter), Context.ConnectionAborted); + } + + public Task UnsubscribeAsync() + { + return subscriptionManager.UnsubscribeAsync(Context.ConnectionId); + } + + public override async Task OnDisconnectedAsync(Exception? exception) + { + await UnsubscribeAsync().ConfigureAwait(false); + await base.OnDisconnectedAsync(exception).ConfigureAwait(false); + } + + private static OpenTelemetryTraceFilter ValidateFilter(OpenTelemetryTraceFilter? filter) + { + filter ??= new(); + + if (filter.From is { } from && filter.To is { } to && from > to) + throw new HubException("The OpenTelemetry filter 'from' timestamp must be earlier than or equal to 'to'."); + + return filter; + } + + private void EnsureCanReadOpenTelemetry() + { + var user = Context.User; + + if (user?.Identity?.IsAuthenticated != true || !ReadPermissions.Any(user.HasPermission)) + throw new HubException("Access denied."); + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/RealTime/OpenTelemetrySubscriptionManager.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/RealTime/OpenTelemetrySubscriptionManager.cs new file mode 100644 index 000000000..c676e1ac3 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/RealTime/OpenTelemetrySubscriptionManager.cs @@ -0,0 +1,82 @@ +using System.Collections.Concurrent; +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging; + +namespace Elsa.Diagnostics.OpenTelemetry.RealTime; + +public sealed class OpenTelemetrySubscriptionManager( + IOpenTelemetryLiveFeed liveFeed, + IHubContext hubContext, + ILogger logger) : IDisposable +{ + private readonly ConcurrentDictionary _subscriptions = new(StringComparer.Ordinal); + + public Task SubscribeAsync(string connectionId, OpenTelemetryTraceFilter filter, CancellationToken cancellationToken) + { + Unsubscribe(connectionId); + var subscriptionCancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + var subscription = new OpenTelemetrySubscription(filter, subscriptionCancellation); + _subscriptions[connectionId] = subscription; + + _ = StreamAsync(connectionId, filter, subscription, subscriptionCancellation.Token); + return Task.CompletedTask; + } + + public Task UnsubscribeAsync(string connectionId) + { + Unsubscribe(connectionId); + return Task.CompletedTask; + } + + public void Dispose() + { + foreach (var subscription in _subscriptions.Values) + { + subscription.CancellationTokenSource.Cancel(); + subscription.CancellationTokenSource.Dispose(); + } + + _subscriptions.Clear(); + } + + private async Task StreamAsync(string connectionId, OpenTelemetryTraceFilter filter, OpenTelemetrySubscription subscription, CancellationToken cancellationToken) + { + try + { + await foreach (var item in liveFeed.SubscribeAsync(filter, cancellationToken).ConfigureAwait(false)) + await hubContext.Clients.Client(connectionId).ReceiveAsync(item).ConfigureAwait(false); + } + catch (OperationCanceledException e) + { + logger.LogDebug(e, "OpenTelemetry subscription for connection {ConnectionId} was canceled", connectionId); + } + catch (Exception e) when (e is not OperationCanceledException) + { + logger.LogWarning(e, "OpenTelemetry subscription for connection {ConnectionId} stopped unexpectedly", connectionId); + } + finally + { + Remove(connectionId, subscription); + } + } + + private void Unsubscribe(string connectionId) + { + if (!_subscriptions.TryRemove(connectionId, out var subscription)) + return; + + subscription.CancellationTokenSource.Cancel(); + subscription.CancellationTokenSource.Dispose(); + } + + private void Remove(string connectionId, OpenTelemetrySubscription subscription) + { + var entry = new KeyValuePair(connectionId, subscription); + if (((ICollection>)_subscriptions).Remove(entry)) + subscription.CancellationTokenSource.Dispose(); + } + + private sealed record OpenTelemetrySubscription(OpenTelemetryTraceFilter Filter, CancellationTokenSource CancellationTokenSource); +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Services/CollectorConfigurationProvider.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Services/CollectorConfigurationProvider.cs new file mode 100644 index 000000000..8001aadda --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Services/CollectorConfigurationProvider.cs @@ -0,0 +1,34 @@ +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Options; +using Microsoft.Extensions.Options; + +namespace Elsa.Diagnostics.OpenTelemetry.Services; + +public class CollectorConfigurationProvider(IOptions options) : ICollectorConfigurationProvider +{ + private readonly OpenTelemetryDiagnosticsOptions _options = options.Value; + + public ValueTask GetAsync(CancellationToken cancellationToken = default) + { + var headers = string.IsNullOrWhiteSpace(_options.ApiKey) + ? new Dictionary() + : new Dictionary { [_options.ApiKeyHeaderName] = "" }; + var grpcEnabled = _options.EnableGrpc && !string.IsNullOrWhiteSpace(_options.GrpcEndpointPath); + var grpcDisabledReason = grpcEnabled + ? null + : _options.EnableGrpc + ? "gRPC endpoint path is not configured." + : _options.GrpcDisabledReason; + + var configuration = new CollectorConfiguration( + new CollectorEndpointInfo("http/protobuf", _options.HttpEndpointPath, true, null), + new CollectorEndpointInfo("grpc", grpcEnabled ? _options.GrpcEndpointPath : null, grpcEnabled, grpcDisabledReason), + "OTEL_SERVICE_NAME", + "OTEL_EXPORTER_OTLP_ENDPOINT", + "OTEL_EXPORTER_OTLP_PROTOCOL", + headers); + + return ValueTask.FromResult(configuration); + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Services/DefaultOpenTelemetryProvider.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Services/DefaultOpenTelemetryProvider.cs new file mode 100644 index 000000000..5dddb9d66 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Services/DefaultOpenTelemetryProvider.cs @@ -0,0 +1,21 @@ +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Models; + +namespace Elsa.Diagnostics.OpenTelemetry.Services; + +public class DefaultOpenTelemetryProvider(IOpenTelemetryStore store, ICollectorConfigurationProvider collectorConfigurationProvider) : IOpenTelemetryProvider +{ + public ValueTask GetResourcesAsync(OpenTelemetryResourceFilter filter, CancellationToken cancellationToken = default) => store.QueryResourcesAsync(filter, cancellationToken); + + public ValueTask GetTracesAsync(OpenTelemetryTraceFilter filter, CancellationToken cancellationToken = default) => store.QueryTracesAsync(filter, cancellationToken); + + public ValueTask GetTraceAsync(string traceId, CancellationToken cancellationToken = default) => store.GetTraceAsync(traceId, cancellationToken); + + public ValueTask GetMetricsAsync(OpenTelemetryMetricFilter filter, CancellationToken cancellationToken = default) => store.QueryMetricsAsync(filter, cancellationToken); + + public ValueTask GetLogsAsync(OpenTelemetryLogFilter filter, CancellationToken cancellationToken = default) => store.QueryLogsAsync(filter, cancellationToken); + + public ValueTask GetStorageDiagnosticsAsync(CancellationToken cancellationToken = default) => store.GetDiagnosticsAsync(cancellationToken); + + public ValueTask GetCollectorConfigurationAsync(CancellationToken cancellationToken = default) => collectorConfigurationProvider.GetAsync(cancellationToken); +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Services/OpenTelemetryIngestor.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Services/OpenTelemetryIngestor.cs new file mode 100644 index 000000000..472562990 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Services/OpenTelemetryIngestor.cs @@ -0,0 +1,14 @@ +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Models; + +namespace Elsa.Diagnostics.OpenTelemetry.Services; + +public class OpenTelemetryIngestor(IOpenTelemetryRedactor redactor, IOpenTelemetryStore store, IOpenTelemetryLiveFeed liveFeed) : IOpenTelemetryIngestor +{ + public async ValueTask IngestAsync(OpenTelemetryBatch batch, CancellationToken cancellationToken = default) + { + var redactedBatch = redactor.Redact(batch); + await store.WriteAsync(redactedBatch, cancellationToken); + await liveFeed.PublishAsync(redactedBatch, cancellationToken); + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Services/OpenTelemetryRedactor.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Services/OpenTelemetryRedactor.cs new file mode 100644 index 000000000..d1630f465 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Services/OpenTelemetryRedactor.cs @@ -0,0 +1,84 @@ +using System.Text.RegularExpressions; +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Options; +using Microsoft.Extensions.Options; + +namespace Elsa.Diagnostics.OpenTelemetry.Services; + +public class OpenTelemetryRedactor(IOptions options) : IOpenTelemetryRedactor +{ + private const string Redacted = "[Redacted]"; + private readonly HashSet _sensitiveNames = options.Value.SensitiveNames.ToHashSet(StringComparer.OrdinalIgnoreCase); + private readonly IReadOnlyCollection _sensitiveTextPatterns = options.Value.SensitiveTextPatterns + .Select(pattern => new Regex(pattern, RegexOptions.Compiled | RegexOptions.CultureInvariant, options.Value.SensitiveTextPatternTimeout)) + .ToList(); + + public OpenTelemetryBatch Redact(OpenTelemetryBatch batch) + { + return batch with + { + Resources = batch.Resources.Select(RedactResource).ToList(), + Spans = batch.Spans.Select(RedactSpan).ToList(), + Instruments = batch.Instruments.Select(x => x with { Attributes = RedactDictionary(x.Attributes) }).ToList(), + MetricPoints = batch.MetricPoints.Select(x => x with { Attributes = RedactDictionary(x.Attributes) }).ToList(), + Logs = batch.Logs.Select(RedactLog).ToList() + }; + } + + private TelemetryResource RedactResource(TelemetryResource resource) => resource with { Attributes = RedactDictionary(resource.Attributes) }; + + private TelemetrySpan RedactSpan(TelemetrySpan span) + { + return span with + { + Name = RedactValue("span.name", span.Name) ?? string.Empty, + StatusDescription = RedactValue("span.status.description", span.StatusDescription), + Attributes = RedactDictionary(span.Attributes), + Events = span.Events.Select(x => x with { Attributes = RedactDictionary(x.Attributes) }).ToList(), + Links = span.Links.Select(x => x with { Attributes = RedactDictionary(x.Attributes) }).ToList() + }; + } + + private OtlpLogRecord RedactLog(OtlpLogRecord log) + { + return log with + { + Body = RedactValue("log.body", log.Body) ?? string.Empty, + Attributes = RedactDictionary(log.Attributes) + }; + } + + private Dictionary RedactDictionary(IDictionary values) + { + var result = new Dictionary(StringComparer.OrdinalIgnoreCase); + + foreach (var (key, value) in values) + result[key] = RedactValue(key, value); + + return result; + } + + private string? RedactValue(string name, string? value) + { + if (value == null) + return null; + + if (_sensitiveNames.Any(sensitiveName => name.Contains(sensitiveName, StringComparison.OrdinalIgnoreCase))) + return Redacted; + + return _sensitiveTextPatterns.Aggregate(value, RedactPattern); + } + + private static string RedactPattern(string value, Regex pattern) + { + try + { + return pattern.Replace(value, Redacted); + } + catch (RegexMatchTimeoutException) + { + return value; + } + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/Services/OpenTelemetrySourceRegistry.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/Services/OpenTelemetrySourceRegistry.cs new file mode 100644 index 000000000..07413cb7a --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/Services/OpenTelemetrySourceRegistry.cs @@ -0,0 +1,59 @@ +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Options; +using Microsoft.Extensions.Options; + +namespace Elsa.Diagnostics.OpenTelemetry.Services; + +public class OpenTelemetrySourceRegistry : IOpenTelemetrySourceRegistry +{ + private readonly object _lock = new(); + private readonly Dictionary _resources = new(StringComparer.OrdinalIgnoreCase); + private readonly int _capacity; + private long _droppedCount; + + public OpenTelemetrySourceRegistry(IOptions options) + { + _capacity = Math.Max(1, options.Value.ResourceCapacity); + } + + public OpenTelemetrySourceRegistry() : this(Microsoft.Extensions.Options.Options.Create(new OpenTelemetryDiagnosticsOptions())) + { + } + + public long DroppedCount + { + get + { + lock (_lock) + return _droppedCount; + } + } + + public void MarkSeen(TelemetryResource resource) + { + lock (_lock) + { + if (!_resources.ContainsKey(resource.Id) && _resources.Count >= _capacity) + RemoveOldestResource(); + + _resources[resource.Id] = resource; + } + } + + public IReadOnlyCollection List() + { + lock (_lock) + return _resources.Values.OrderBy(x => x.ServiceName, StringComparer.OrdinalIgnoreCase).ThenBy(x => x.Id, StringComparer.OrdinalIgnoreCase).ToList(); + } + + private void RemoveOldestResource() + { + var oldest = _resources.Values.OrderBy(x => x.LastSeen).ThenBy(x => x.Id, StringComparer.OrdinalIgnoreCase).FirstOrDefault(); + if (oldest == null) + return; + + _resources.Remove(oldest.Id); + _droppedCount++; + } +} diff --git a/src/modules/Elsa.Diagnostics.OpenTelemetry/ShellFeatures/OpenTelemetryFeature.cs b/src/modules/Elsa.Diagnostics.OpenTelemetry/ShellFeatures/OpenTelemetryFeature.cs new file mode 100644 index 000000000..d154398af --- /dev/null +++ b/src/modules/Elsa.Diagnostics.OpenTelemetry/ShellFeatures/OpenTelemetryFeature.cs @@ -0,0 +1,101 @@ +using CShells.AspNetCore.Features; +using CShells.FastEndpoints.Features; +using CShells.Features; +using Elsa.Diagnostics.OpenTelemetry.Extensions; +using Elsa.Diagnostics.OpenTelemetry.Options; +using Elsa.PackageManifest.Generator.Hints; +using JetBrains.Annotations; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace Elsa.Diagnostics.OpenTelemetry.ShellFeatures; + +[ShellFeature( + DisplayName = "OpenTelemetry Diagnostics", + Description = "Provides OpenTelemetry diagnostics collection, query services, and live updates", + DependsOn = ["ElsaFastEndpoints"])] +[UsedImplicitly] +public class OpenTelemetryFeature : IFastEndpointsShellFeature, IWebShellFeature +{ + private static readonly OpenTelemetryDiagnosticsOptions DefaultOptions = new(); + + [ManifestSetting( + DisplayName = "Trace Capacity", + Description = "Maximum number of recent traces retained in memory.", + Category = "Diagnostics", + DefaultValue = "5000", + RestartRequired = true)] + public int TraceCapacity { get; set; } = DefaultOptions.TraceCapacity; + + [ManifestSetting( + DisplayName = "Span Capacity", + Description = "Maximum number of recent spans retained in memory.", + Category = "Diagnostics", + DefaultValue = "25000", + RestartRequired = true)] + public int SpanCapacity { get; set; } = DefaultOptions.SpanCapacity; + + [ManifestSetting( + DisplayName = "Metric Point Capacity", + Description = "Maximum number of recent metric points retained in memory.", + Category = "Diagnostics", + DefaultValue = "25000", + RestartRequired = true)] + public int MetricPointCapacity { get; set; } = DefaultOptions.MetricPointCapacity; + + [ManifestSetting( + DisplayName = "Log Record Capacity", + Description = "Maximum number of recent OTLP log records retained in memory.", + Category = "Diagnostics", + DefaultValue = "10000", + RestartRequired = true)] + public int LogRecordCapacity { get; set; } = DefaultOptions.LogRecordCapacity; + + [ManifestSetting( + DisplayName = "Resource Capacity", + Description = "Maximum number of recent telemetry resources retained in memory.", + Category = "Diagnostics", + DefaultValue = "500", + RestartRequired = true)] + public int ResourceCapacity { get; set; } = DefaultOptions.ResourceCapacity; + + [ManifestSetting( + DisplayName = "Subscriber Channel Capacity", + Description = "Maximum queued live updates per subscriber before updates are dropped.", + Category = "Diagnostics", + DefaultValue = "1000", + RestartRequired = true)] + public int SubscriberChannelCapacity { get; set; } = DefaultOptions.SubscriberChannelCapacity; + + [ManifestSetting( + DisplayName = "Max HTTP Request Body Size", + Description = "Maximum OTLP HTTP/protobuf request body size in bytes.", + Category = "Diagnostics", + DefaultValue = "10485760", + RestartRequired = true)] + public long MaxHttpRequestBodySize { get; set; } = DefaultOptions.MaxHttpRequestBodySize; + + public void ConfigureServices(IServiceCollection services) + { + services.AddOpenTelemetryDiagnosticsServices(ConfigureOptions); + } + + public void MapEndpoints(IEndpointRouteBuilder endpoints, IHostEnvironment? environment) + { + endpoints.MapOpenTelemetryHttpProtobufCollector(); + endpoints.MapOpenTelemetryGrpcCollector(); + endpoints.MapOpenTelemetryHub(); + } + + private void ConfigureOptions(OpenTelemetryDiagnosticsOptions options) + { + options.TraceCapacity = TraceCapacity; + options.SpanCapacity = SpanCapacity; + options.MetricPointCapacity = MetricPointCapacity; + options.LogRecordCapacity = LogRecordCapacity; + options.ResourceCapacity = ResourceCapacity; + options.SubscriberChannelCapacity = SubscriberChannelCapacity; + options.MaxHttpRequestBodySize = MaxHttpRequestBodySize; + } +} diff --git a/src/modules/Elsa.Expressions.JavaScript.Libraries/ClientLib/dist/lodash.js b/src/modules/Elsa.Expressions.JavaScript.Libraries/ClientLib/dist/lodash.js index 6cf804060..15a989568 100644 --- a/src/modules/Elsa.Expressions.JavaScript.Libraries/ClientLib/dist/lodash.js +++ b/src/modules/Elsa.Expressions.JavaScript.Libraries/ClientLib/dist/lodash.js @@ -1,4 +1,4 @@ -!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.lodash=t():n.lodash=t()}(this,(()=>(()=>{var n={2543:function(n,t,r){var e; +!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.lodash=t():n.lodash=t()}(this,(()=>(()=>{var n={2543(n,t,r){var e; /** * @license * Lodash @@ -6,4 +6,4 @@ * Released under MIT license * Based on Underscore.js 1.8.3 * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */n=r.nmd(n),function(){var u,i="Expected a function",o="__lodash_hash_undefined__",f="__lodash_placeholder__",a=16,c=32,l=64,s=128,h=256,p=1/0,v=9007199254740991,_=NaN,g=4294967295,y=[["ary",s],["bind",1],["bindKey",2],["curry",8],["curryRight",a],["flip",512],["partial",c],["partialRight",l],["rearg",h]],d="[object Arguments]",b="[object Array]",w="[object Boolean]",m="[object Date]",x="[object Error]",j="[object Function]",A="[object GeneratorFunction]",k="[object Map]",O="[object Number]",I="[object Object]",R="[object Promise]",z="[object RegExp]",E="[object Set]",S="[object String]",W="[object Symbol]",L="[object WeakMap]",C="[object ArrayBuffer]",T="[object DataView]",U="[object Float32Array]",B="[object Float64Array]",$="[object Int8Array]",D="[object Int16Array]",F="[object Int32Array]",M="[object Uint8Array]",N="[object Uint8ClampedArray]",P="[object Uint16Array]",q="[object Uint32Array]",Z=/\b__p \+= '';/g,K=/\b(__p \+=) '' \+/g,V=/(__e\(.*?\)|\b__t\)) \+\n'';/g,G=/&(?:amp|lt|gt|quot|#39);/g,H=/[&<>"']/g,J=RegExp(G.source),Y=RegExp(H.source),Q=/<%-([\s\S]+?)%>/g,X=/<%([\s\S]+?)%>/g,nn=/<%=([\s\S]+?)%>/g,tn=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,rn=/^\w*$/,en=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,un=/[\\^$.*+?()[\]{}|]/g,on=RegExp(un.source),fn=/^\s+/,an=/\s/,cn=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,ln=/\{\n\/\* \[wrapped with (.+)\] \*/,sn=/,? & /,hn=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,pn=/[()=,{}\[\]\/\s]/,vn=/\\(\\)?/g,_n=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,gn=/\w*$/,yn=/^[-+]0x[0-9a-f]+$/i,dn=/^0b[01]+$/i,bn=/^\[object .+?Constructor\]$/,wn=/^0o[0-7]+$/i,mn=/^(?:0|[1-9]\d*)$/,xn=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,jn=/($^)/,An=/['\n\r\u2028\u2029\\]/g,kn="\\ud800-\\udfff",On="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",In="\\u2700-\\u27bf",Rn="a-z\\xdf-\\xf6\\xf8-\\xff",zn="A-Z\\xc0-\\xd6\\xd8-\\xde",En="\\ufe0e\\ufe0f",Sn="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",Wn="['’]",Ln="["+kn+"]",Cn="["+Sn+"]",Tn="["+On+"]",Un="\\d+",Bn="["+In+"]",$n="["+Rn+"]",Dn="[^"+kn+Sn+Un+In+Rn+zn+"]",Fn="\\ud83c[\\udffb-\\udfff]",Mn="[^"+kn+"]",Nn="(?:\\ud83c[\\udde6-\\uddff]){2}",Pn="[\\ud800-\\udbff][\\udc00-\\udfff]",qn="["+zn+"]",Zn="\\u200d",Kn="(?:"+$n+"|"+Dn+")",Vn="(?:"+qn+"|"+Dn+")",Gn="(?:['’](?:d|ll|m|re|s|t|ve))?",Hn="(?:['’](?:D|LL|M|RE|S|T|VE))?",Jn="(?:"+Tn+"|"+Fn+")"+"?",Yn="["+En+"]?",Qn=Yn+Jn+("(?:"+Zn+"(?:"+[Mn,Nn,Pn].join("|")+")"+Yn+Jn+")*"),Xn="(?:"+[Bn,Nn,Pn].join("|")+")"+Qn,nt="(?:"+[Mn+Tn+"?",Tn,Nn,Pn,Ln].join("|")+")",tt=RegExp(Wn,"g"),rt=RegExp(Tn,"g"),et=RegExp(Fn+"(?="+Fn+")|"+nt+Qn,"g"),ut=RegExp([qn+"?"+$n+"+"+Gn+"(?="+[Cn,qn,"$"].join("|")+")",Vn+"+"+Hn+"(?="+[Cn,qn+Kn,"$"].join("|")+")",qn+"?"+Kn+"+"+Gn,qn+"+"+Hn,"\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",Un,Xn].join("|"),"g"),it=RegExp("["+Zn+kn+On+En+"]"),ot=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,ft=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],at=-1,ct={};ct[U]=ct[B]=ct[$]=ct[D]=ct[F]=ct[M]=ct[N]=ct[P]=ct[q]=!0,ct[d]=ct[b]=ct[C]=ct[w]=ct[T]=ct[m]=ct[x]=ct[j]=ct[k]=ct[O]=ct[I]=ct[z]=ct[E]=ct[S]=ct[L]=!1;var lt={};lt[d]=lt[b]=lt[C]=lt[T]=lt[w]=lt[m]=lt[U]=lt[B]=lt[$]=lt[D]=lt[F]=lt[k]=lt[O]=lt[I]=lt[z]=lt[E]=lt[S]=lt[W]=lt[M]=lt[N]=lt[P]=lt[q]=!0,lt[x]=lt[j]=lt[L]=!1;var st={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},ht=parseFloat,pt=parseInt,vt="object"==typeof r.g&&r.g&&r.g.Object===Object&&r.g,_t="object"==typeof self&&self&&self.Object===Object&&self,gt=vt||_t||Function("return this")(),yt=t&&!t.nodeType&&t,dt=yt&&n&&!n.nodeType&&n,bt=dt&&dt.exports===yt,wt=bt&&vt.process,mt=function(){try{var n=dt&&dt.require&&dt.require("util").types;return n||wt&&wt.binding&&wt.binding("util")}catch(n){}}(),xt=mt&&mt.isArrayBuffer,jt=mt&&mt.isDate,At=mt&&mt.isMap,kt=mt&&mt.isRegExp,Ot=mt&&mt.isSet,It=mt&&mt.isTypedArray;function Rt(n,t,r){switch(r.length){case 0:return n.call(t);case 1:return n.call(t,r[0]);case 2:return n.call(t,r[0],r[1]);case 3:return n.call(t,r[0],r[1],r[2])}return n.apply(t,r)}function zt(n,t,r,e){for(var u=-1,i=null==n?0:n.length;++u-1}function Tt(n,t,r){for(var e=-1,u=null==n?0:n.length;++e-1;);return r}function ur(n,t){for(var r=n.length;r--&&qt(t,n[r],0)>-1;);return r}var ir=Ht({À:"A",Á:"A",Â:"A",Ã:"A",Ä:"A",Å:"A",à:"a",á:"a",â:"a",ã:"a",ä:"a",å:"a",Ç:"C",ç:"c",Ð:"D",ð:"d",È:"E",É:"E",Ê:"E",Ë:"E",è:"e",é:"e",ê:"e",ë:"e",Ì:"I",Í:"I",Î:"I",Ï:"I",ì:"i",í:"i",î:"i",ï:"i",Ñ:"N",ñ:"n",Ò:"O",Ó:"O",Ô:"O",Õ:"O",Ö:"O",Ø:"O",ò:"o",ó:"o",ô:"o",õ:"o",ö:"o",ø:"o",Ù:"U",Ú:"U",Û:"U",Ü:"U",ù:"u",ú:"u",û:"u",ü:"u",Ý:"Y",ý:"y",ÿ:"y",Æ:"Ae",æ:"ae",Þ:"Th",þ:"th",ß:"ss",Ā:"A",Ă:"A",Ą:"A",ā:"a",ă:"a",ą:"a",Ć:"C",Ĉ:"C",Ċ:"C",Č:"C",ć:"c",ĉ:"c",ċ:"c",č:"c",Ď:"D",Đ:"D",ď:"d",đ:"d",Ē:"E",Ĕ:"E",Ė:"E",Ę:"E",Ě:"E",ē:"e",ĕ:"e",ė:"e",ę:"e",ě:"e",Ĝ:"G",Ğ:"G",Ġ:"G",Ģ:"G",ĝ:"g",ğ:"g",ġ:"g",ģ:"g",Ĥ:"H",Ħ:"H",ĥ:"h",ħ:"h",Ĩ:"I",Ī:"I",Ĭ:"I",Į:"I",İ:"I",ĩ:"i",ī:"i",ĭ:"i",į:"i",ı:"i",Ĵ:"J",ĵ:"j",Ķ:"K",ķ:"k",ĸ:"k",Ĺ:"L",Ļ:"L",Ľ:"L",Ŀ:"L",Ł:"L",ĺ:"l",ļ:"l",ľ:"l",ŀ:"l",ł:"l",Ń:"N",Ņ:"N",Ň:"N",Ŋ:"N",ń:"n",ņ:"n",ň:"n",ŋ:"n",Ō:"O",Ŏ:"O",Ő:"O",ō:"o",ŏ:"o",ő:"o",Ŕ:"R",Ŗ:"R",Ř:"R",ŕ:"r",ŗ:"r",ř:"r",Ś:"S",Ŝ:"S",Ş:"S",Š:"S",ś:"s",ŝ:"s",ş:"s",š:"s",Ţ:"T",Ť:"T",Ŧ:"T",ţ:"t",ť:"t",ŧ:"t",Ũ:"U",Ū:"U",Ŭ:"U",Ů:"U",Ű:"U",Ų:"U",ũ:"u",ū:"u",ŭ:"u",ů:"u",ű:"u",ų:"u",Ŵ:"W",ŵ:"w",Ŷ:"Y",ŷ:"y",Ÿ:"Y",Ź:"Z",Ż:"Z",Ž:"Z",ź:"z",ż:"z",ž:"z",IJ:"IJ",ij:"ij",Œ:"Oe",œ:"oe",ʼn:"'n",ſ:"s"}),or=Ht({"&":"&","<":"<",">":">",'"':""","'":"'"});function fr(n){return"\\"+st[n]}function ar(n){return it.test(n)}function cr(n){var t=-1,r=Array(n.size);return n.forEach((function(n,e){r[++t]=[e,n]})),r}function lr(n,t){return function(r){return n(t(r))}}function sr(n,t){for(var r=-1,e=n.length,u=0,i=[];++r",""":'"',"'":"'"});var dr=function n(t){var r,e=(t=null==t?gt:dr.defaults(gt.Object(),t,dr.pick(gt,ft))).Array,an=t.Date,kn=t.Error,On=t.Function,In=t.Math,Rn=t.Object,zn=t.RegExp,En=t.String,Sn=t.TypeError,Wn=e.prototype,Ln=On.prototype,Cn=Rn.prototype,Tn=t["__core-js_shared__"],Un=Ln.toString,Bn=Cn.hasOwnProperty,$n=0,Dn=(r=/[^.]+$/.exec(Tn&&Tn.keys&&Tn.keys.IE_PROTO||""))?"Symbol(src)_1."+r:"",Fn=Cn.toString,Mn=Un.call(Rn),Nn=gt._,Pn=zn("^"+Un.call(Bn).replace(un,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),qn=bt?t.Buffer:u,Zn=t.Symbol,Kn=t.Uint8Array,Vn=qn?qn.allocUnsafe:u,Gn=lr(Rn.getPrototypeOf,Rn),Hn=Rn.create,Jn=Cn.propertyIsEnumerable,Yn=Wn.splice,Qn=Zn?Zn.isConcatSpreadable:u,Xn=Zn?Zn.iterator:u,nt=Zn?Zn.toStringTag:u,et=function(){try{var n=hi(Rn,"defineProperty");return n({},"",{}),n}catch(n){}}(),it=t.clearTimeout!==gt.clearTimeout&&t.clearTimeout,st=an&&an.now!==gt.Date.now&&an.now,vt=t.setTimeout!==gt.setTimeout&&t.setTimeout,_t=In.ceil,yt=In.floor,dt=Rn.getOwnPropertySymbols,wt=qn?qn.isBuffer:u,mt=t.isFinite,Mt=Wn.join,Ht=lr(Rn.keys,Rn),br=In.max,wr=In.min,mr=an.now,xr=t.parseInt,jr=In.random,Ar=Wn.reverse,kr=hi(t,"DataView"),Or=hi(t,"Map"),Ir=hi(t,"Promise"),Rr=hi(t,"Set"),zr=hi(t,"WeakMap"),Er=hi(Rn,"create"),Sr=zr&&new zr,Wr={},Lr=$i(kr),Cr=$i(Or),Tr=$i(Ir),Ur=$i(Rr),Br=$i(zr),$r=Zn?Zn.prototype:u,Dr=$r?$r.valueOf:u,Fr=$r?$r.toString:u;function Mr(n){if(rf(n)&&!Zo(n)&&!(n instanceof Zr)){if(n instanceof qr)return n;if(Bn.call(n,"__wrapped__"))return Di(n)}return new qr(n)}var Nr=function(){function n(){}return function(t){if(!tf(t))return{};if(Hn)return Hn(t);n.prototype=t;var r=new n;return n.prototype=u,r}}();function Pr(){}function qr(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=u}function Zr(n){this.__wrapped__=n,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=g,this.__views__=[]}function Kr(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t=t?n:t)),n}function ce(n,t,r,e,i,o){var f,a=1&t,c=2&t,l=4&t;if(r&&(f=i?r(n,e,i,o):r(n)),f!==u)return f;if(!tf(n))return n;var s=Zo(n);if(s){if(f=function(n){var t=n.length,r=new n.constructor(t);t&&"string"==typeof n[0]&&Bn.call(n,"index")&&(r.index=n.index,r.input=n.input);return r}(n),!a)return Eu(n,f)}else{var h=_i(n),p=h==j||h==A;if(Ho(n))return Au(n,a);if(h==I||h==d||p&&!i){if(f=c||p?{}:yi(n),!a)return c?function(n,t){return Su(n,vi(n),t)}(n,function(n,t){return n&&Su(t,Cf(t),n)}(f,n)):function(n,t){return Su(n,pi(n),t)}(n,ie(f,n))}else{if(!lt[h])return i?n:{};f=function(n,t,r){var e=n.constructor;switch(t){case C:return ku(n);case w:case m:return new e(+n);case T:return function(n,t){var r=t?ku(n.buffer):n.buffer;return new n.constructor(r,n.byteOffset,n.byteLength)}(n,r);case U:case B:case $:case D:case F:case M:case N:case P:case q:return Ou(n,r);case k:return new e;case O:case S:return new e(n);case z:return function(n){var t=new n.constructor(n.source,gn.exec(n));return t.lastIndex=n.lastIndex,t}(n);case E:return new e;case W:return u=n,Dr?Rn(Dr.call(u)):{}}var u}(n,h,a)}}o||(o=new Jr);var v=o.get(n);if(v)return v;o.set(n,f),af(n)?n.forEach((function(e){f.add(ce(e,t,r,e,n,o))})):ef(n)&&n.forEach((function(e,u){f.set(u,ce(e,t,r,u,n,o))}));var _=s?u:(l?c?ii:ui:c?Cf:Lf)(n);return Et(_||n,(function(e,u){_&&(e=n[u=e]),re(f,u,ce(e,t,r,u,n,o))})),f}function le(n,t,r){var e=r.length;if(null==n)return!e;for(n=Rn(n);e--;){var i=r[e],o=t[i],f=n[i];if(f===u&&!(i in n)||!o(f))return!1}return!0}function se(n,t,r){if("function"!=typeof n)throw new Sn(i);return Si((function(){n.apply(u,r)}),t)}function he(n,t,r,e){var u=-1,i=Ct,o=!0,f=n.length,a=[],c=t.length;if(!f)return a;r&&(t=Ut(t,nr(r))),e?(i=Tt,o=!1):t.length>=200&&(i=rr,o=!1,t=new Hr(t));n:for(;++u-1},Vr.prototype.set=function(n,t){var r=this.__data__,e=ee(r,n);return e<0?(++this.size,r.push([n,t])):r[e][1]=t,this},Gr.prototype.clear=function(){this.size=0,this.__data__={hash:new Kr,map:new(Or||Vr),string:new Kr}},Gr.prototype.delete=function(n){var t=li(this,n).delete(n);return this.size-=t?1:0,t},Gr.prototype.get=function(n){return li(this,n).get(n)},Gr.prototype.has=function(n){return li(this,n).has(n)},Gr.prototype.set=function(n,t){var r=li(this,n),e=r.size;return r.set(n,t),this.size+=r.size==e?0:1,this},Hr.prototype.add=Hr.prototype.push=function(n){return this.__data__.set(n,o),this},Hr.prototype.has=function(n){return this.__data__.has(n)},Jr.prototype.clear=function(){this.__data__=new Vr,this.size=0},Jr.prototype.delete=function(n){var t=this.__data__,r=t.delete(n);return this.size=t.size,r},Jr.prototype.get=function(n){return this.__data__.get(n)},Jr.prototype.has=function(n){return this.__data__.has(n)},Jr.prototype.set=function(n,t){var r=this.__data__;if(r instanceof Vr){var e=r.__data__;if(!Or||e.length<199)return e.push([n,t]),this.size=++r.size,this;r=this.__data__=new Gr(e)}return r.set(n,t),this.size=r.size,this};var pe=Cu(me),ve=Cu(xe,!0);function _e(n,t){var r=!0;return pe(n,(function(n,e,u){return r=!!t(n,e,u)})),r}function ge(n,t,r){for(var e=-1,i=n.length;++e0&&r(f)?t>1?de(f,t-1,r,e,u):Bt(u,f):e||(u[u.length]=f)}return u}var be=Tu(),we=Tu(!0);function me(n,t){return n&&be(n,t,Lf)}function xe(n,t){return n&&we(n,t,Lf)}function je(n,t){return Lt(t,(function(t){return Qo(n[t])}))}function Ae(n,t){for(var r=0,e=(t=wu(t,n)).length;null!=n&&rt}function Re(n,t){return null!=n&&Bn.call(n,t)}function ze(n,t){return null!=n&&t in Rn(n)}function Ee(n,t,r){for(var i=r?Tt:Ct,o=n[0].length,f=n.length,a=f,c=e(f),l=1/0,s=[];a--;){var h=n[a];a&&t&&(h=Ut(h,nr(t))),l=wr(h.length,l),c[a]=!r&&(t||o>=120&&h.length>=120)?new Hr(a&&h):u}h=n[0];var p=-1,v=c[0];n:for(;++p=f?a:a*("desc"==r[e]?-1:1)}return n.index-t.index}(n,t,r)}))}function Ke(n,t,r){for(var e=-1,u=t.length,i={};++e-1;)f!==n&&Yn.call(f,a,1),Yn.call(n,a,1);return n}function Ge(n,t){for(var r=n?t.length:0,e=r-1;r--;){var u=t[r];if(r==e||u!==i){var i=u;bi(u)?Yn.call(n,u,1):hu(n,u)}}return n}function He(n,t){return n+yt(jr()*(t-n+1))}function Je(n,t){var r="";if(!n||t<1||t>v)return r;do{t%2&&(r+=n),(t=yt(t/2))&&(n+=n)}while(t);return r}function Ye(n,t){return Wi(Ii(n,t,ia),n+"")}function Qe(n){return Qr(Nf(n))}function Xe(n,t){var r=Nf(n);return Ti(r,ae(t,0,r.length))}function nu(n,t,r,e){if(!tf(n))return n;for(var i=-1,o=(t=wu(t,n)).length,f=o-1,a=n;null!=a&&++ii?0:i+t),(r=r>i?i:r)<0&&(r+=i),i=t>r?0:r-t>>>0,t>>>=0;for(var o=e(i);++u>>1,o=n[i];null!==o&&!lf(o)&&(r?o<=t:o=200){var c=t?null:Ju(n);if(c)return hr(c);o=!1,u=rr,a=new Hr}else a=t?[]:f;n:for(;++e=e?n:uu(n,t,r)}var ju=it||function(n){return gt.clearTimeout(n)};function Au(n,t){if(t)return n.slice();var r=n.length,e=Vn?Vn(r):new n.constructor(r);return n.copy(e),e}function ku(n){var t=new n.constructor(n.byteLength);return new Kn(t).set(new Kn(n)),t}function Ou(n,t){var r=t?ku(n.buffer):n.buffer;return new n.constructor(r,n.byteOffset,n.length)}function Iu(n,t){if(n!==t){var r=n!==u,e=null===n,i=n==n,o=lf(n),f=t!==u,a=null===t,c=t==t,l=lf(t);if(!a&&!l&&!o&&n>t||o&&f&&c&&!a&&!l||e&&f&&c||!r&&c||!i)return 1;if(!e&&!o&&!l&&n1?r[i-1]:u,f=i>2?r[2]:u;for(o=n.length>3&&"function"==typeof o?(i--,o):u,f&&wi(r[0],r[1],f)&&(o=i<3?u:o,i=1),t=Rn(t);++e-1?i[o?t[f]:f]:u}}function Fu(n){return ei((function(t){var r=t.length,e=r,o=qr.prototype.thru;for(n&&t.reverse();e--;){var f=t[e];if("function"!=typeof f)throw new Sn(i);if(o&&!a&&"wrapper"==fi(f))var a=new qr([],!0)}for(e=a?e:r;++e1&&w.reverse(),p&&la))return!1;var l=o.get(n),s=o.get(t);if(l&&s)return l==t&&s==n;var h=-1,p=!0,v=2&r?new Hr:u;for(o.set(n,t),o.set(t,n);++h-1&&n%1==0&&n1?"& ":"")+t[e],t=t.join(r>2?", ":" "),n.replace(cn,"{\n/* [wrapped with "+t+"] */\n")}(e,function(n,t){return Et(y,(function(r){var e="_."+r[0];t&r[1]&&!Ct(n,e)&&n.push(e)})),n.sort()}(function(n){var t=n.match(ln);return t?t[1].split(sn):[]}(e),r)))}function Ci(n){var t=0,r=0;return function(){var e=mr(),i=16-(e-r);if(r=e,i>0){if(++t>=800)return arguments[0]}else t=0;return n.apply(u,arguments)}}function Ti(n,t){var r=-1,e=n.length,i=e-1;for(t=t===u?e:t;++r1?n[t-1]:u;return r="function"==typeof r?(n.pop(),r):u,io(n,r)}));function ho(n){var t=Mr(n);return t.__chain__=!0,t}function po(n,t){return t(n)}var vo=ei((function(n){var t=n.length,r=t?n[0]:0,e=this.__wrapped__,i=function(t){return fe(t,n)};return!(t>1||this.__actions__.length)&&e instanceof Zr&&bi(r)?((e=e.slice(r,+r+(t?1:0))).__actions__.push({func:po,args:[i],thisArg:u}),new qr(e,this.__chain__).thru((function(n){return t&&!n.length&&n.push(u),n}))):this.thru(i)}));var _o=Wu((function(n,t,r){Bn.call(n,r)?++n[r]:oe(n,r,1)}));var go=Du(Pi),yo=Du(qi);function bo(n,t){return(Zo(n)?Et:pe)(n,ci(t,3))}function wo(n,t){return(Zo(n)?St:ve)(n,ci(t,3))}var mo=Wu((function(n,t,r){Bn.call(n,r)?n[r].push(t):oe(n,r,[t])}));var xo=Ye((function(n,t,r){var u=-1,i="function"==typeof t,o=Vo(n)?e(n.length):[];return pe(n,(function(n){o[++u]=i?Rt(t,n,r):Se(n,t,r)})),o})),jo=Wu((function(n,t,r){oe(n,r,t)}));function Ao(n,t){return(Zo(n)?Ut:Fe)(n,ci(t,3))}var ko=Wu((function(n,t,r){n[r?0:1].push(t)}),(function(){return[[],[]]}));var Oo=Ye((function(n,t){if(null==n)return[];var r=t.length;return r>1&&wi(n,t[0],t[1])?t=[]:r>2&&wi(t[0],t[1],t[2])&&(t=[t[0]]),Ze(n,de(t,1),[])})),Io=st||function(){return gt.Date.now()};function Ro(n,t,r){return t=r?u:t,t=n&&null==t?n.length:t,Qu(n,s,u,u,u,u,t)}function zo(n,t){var r;if("function"!=typeof t)throw new Sn(i);return n=gf(n),function(){return--n>0&&(r=t.apply(this,arguments)),n<=1&&(t=u),r}}var Eo=Ye((function(n,t,r){var e=1;if(r.length){var u=sr(r,ai(Eo));e|=c}return Qu(n,e,t,r,u)})),So=Ye((function(n,t,r){var e=3;if(r.length){var u=sr(r,ai(So));e|=c}return Qu(t,e,n,r,u)}));function Wo(n,t,r){var e,o,f,a,c,l,s=0,h=!1,p=!1,v=!0;if("function"!=typeof n)throw new Sn(i);function _(t){var r=e,i=o;return e=o=u,s=t,a=n.apply(i,r)}function g(n){var r=n-l;return l===u||r>=t||r<0||p&&n-s>=f}function y(){var n=Io();if(g(n))return d(n);c=Si(y,function(n){var r=t-(n-l);return p?wr(r,f-(n-s)):r}(n))}function d(n){return c=u,v&&e?_(n):(e=o=u,a)}function b(){var n=Io(),r=g(n);if(e=arguments,o=this,l=n,r){if(c===u)return function(n){return s=n,c=Si(y,t),h?_(n):a}(l);if(p)return ju(c),c=Si(y,t),_(l)}return c===u&&(c=Si(y,t)),a}return t=df(t)||0,tf(r)&&(h=!!r.leading,f=(p="maxWait"in r)?br(df(r.maxWait)||0,t):f,v="trailing"in r?!!r.trailing:v),b.cancel=function(){c!==u&&ju(c),s=0,e=l=o=c=u},b.flush=function(){return c===u?a:d(Io())},b}var Lo=Ye((function(n,t){return se(n,1,t)})),Co=Ye((function(n,t,r){return se(n,df(t)||0,r)}));function To(n,t){if("function"!=typeof n||null!=t&&"function"!=typeof t)throw new Sn(i);var r=function(){var e=arguments,u=t?t.apply(this,e):e[0],i=r.cache;if(i.has(u))return i.get(u);var o=n.apply(this,e);return r.cache=i.set(u,o)||i,o};return r.cache=new(To.Cache||Gr),r}function Uo(n){if("function"!=typeof n)throw new Sn(i);return function(){var t=arguments;switch(t.length){case 0:return!n.call(this);case 1:return!n.call(this,t[0]);case 2:return!n.call(this,t[0],t[1]);case 3:return!n.call(this,t[0],t[1],t[2])}return!n.apply(this,t)}}To.Cache=Gr;var Bo=mu((function(n,t){var r=(t=1==t.length&&Zo(t[0])?Ut(t[0],nr(ci())):Ut(de(t,1),nr(ci()))).length;return Ye((function(e){for(var u=-1,i=wr(e.length,r);++u=t})),qo=We(function(){return arguments}())?We:function(n){return rf(n)&&Bn.call(n,"callee")&&!Jn.call(n,"callee")},Zo=e.isArray,Ko=xt?nr(xt):function(n){return rf(n)&&Oe(n)==C};function Vo(n){return null!=n&&nf(n.length)&&!Qo(n)}function Go(n){return rf(n)&&Vo(n)}var Ho=wt||da,Jo=jt?nr(jt):function(n){return rf(n)&&Oe(n)==m};function Yo(n){if(!rf(n))return!1;var t=Oe(n);return t==x||"[object DOMException]"==t||"string"==typeof n.message&&"string"==typeof n.name&&!of(n)}function Qo(n){if(!tf(n))return!1;var t=Oe(n);return t==j||t==A||"[object AsyncFunction]"==t||"[object Proxy]"==t}function Xo(n){return"number"==typeof n&&n==gf(n)}function nf(n){return"number"==typeof n&&n>-1&&n%1==0&&n<=v}function tf(n){var t=typeof n;return null!=n&&("object"==t||"function"==t)}function rf(n){return null!=n&&"object"==typeof n}var ef=At?nr(At):function(n){return rf(n)&&_i(n)==k};function uf(n){return"number"==typeof n||rf(n)&&Oe(n)==O}function of(n){if(!rf(n)||Oe(n)!=I)return!1;var t=Gn(n);if(null===t)return!0;var r=Bn.call(t,"constructor")&&t.constructor;return"function"==typeof r&&r instanceof r&&Un.call(r)==Mn}var ff=kt?nr(kt):function(n){return rf(n)&&Oe(n)==z};var af=Ot?nr(Ot):function(n){return rf(n)&&_i(n)==E};function cf(n){return"string"==typeof n||!Zo(n)&&rf(n)&&Oe(n)==S}function lf(n){return"symbol"==typeof n||rf(n)&&Oe(n)==W}var sf=It?nr(It):function(n){return rf(n)&&nf(n.length)&&!!ct[Oe(n)]};var hf=Vu(De),pf=Vu((function(n,t){return n<=t}));function vf(n){if(!n)return[];if(Vo(n))return cf(n)?_r(n):Eu(n);if(Xn&&n[Xn])return function(n){for(var t,r=[];!(t=n.next()).done;)r.push(t.value);return r}(n[Xn]());var t=_i(n);return(t==k?cr:t==E?hr:Nf)(n)}function _f(n){return n?(n=df(n))===p||n===-1/0?17976931348623157e292*(n<0?-1:1):n==n?n:0:0===n?n:0}function gf(n){var t=_f(n),r=t%1;return t==t?r?t-r:t:0}function yf(n){return n?ae(gf(n),0,g):0}function df(n){if("number"==typeof n)return n;if(lf(n))return _;if(tf(n)){var t="function"==typeof n.valueOf?n.valueOf():n;n=tf(t)?t+"":t}if("string"!=typeof n)return 0===n?n:+n;n=Xt(n);var r=dn.test(n);return r||wn.test(n)?pt(n.slice(2),r?2:8):yn.test(n)?_:+n}function bf(n){return Su(n,Cf(n))}function wf(n){return null==n?"":lu(n)}var mf=Lu((function(n,t){if(Ai(t)||Vo(t))Su(t,Lf(t),n);else for(var r in t)Bn.call(t,r)&&re(n,r,t[r])})),xf=Lu((function(n,t){Su(t,Cf(t),n)})),jf=Lu((function(n,t,r,e){Su(t,Cf(t),n,e)})),Af=Lu((function(n,t,r,e){Su(t,Lf(t),n,e)})),kf=ei(fe);var Of=Ye((function(n,t){n=Rn(n);var r=-1,e=t.length,i=e>2?t[2]:u;for(i&&wi(t[0],t[1],i)&&(e=1);++r1),t})),Su(n,ii(n),r),e&&(r=ce(r,7,ti));for(var u=t.length;u--;)hu(r,t[u]);return r}));var $f=ei((function(n,t){return null==n?{}:function(n,t){return Ke(n,t,(function(t,r){return zf(n,r)}))}(n,t)}));function Df(n,t){if(null==n)return{};var r=Ut(ii(n),(function(n){return[n]}));return t=ci(t),Ke(n,r,(function(n,r){return t(n,r[0])}))}var Ff=Yu(Lf),Mf=Yu(Cf);function Nf(n){return null==n?[]:tr(n,Lf(n))}var Pf=Bu((function(n,t,r){return t=t.toLowerCase(),n+(r?qf(t):t)}));function qf(n){return Qf(wf(n).toLowerCase())}function Zf(n){return(n=wf(n))&&n.replace(xn,ir).replace(rt,"")}var Kf=Bu((function(n,t,r){return n+(r?"-":"")+t.toLowerCase()})),Vf=Bu((function(n,t,r){return n+(r?" ":"")+t.toLowerCase()})),Gf=Uu("toLowerCase");var Hf=Bu((function(n,t,r){return n+(r?"_":"")+t.toLowerCase()}));var Jf=Bu((function(n,t,r){return n+(r?" ":"")+Qf(t)}));var Yf=Bu((function(n,t,r){return n+(r?" ":"")+t.toUpperCase()})),Qf=Uu("toUpperCase");function Xf(n,t,r){return n=wf(n),(t=r?u:t)===u?function(n){return ot.test(n)}(n)?function(n){return n.match(ut)||[]}(n):function(n){return n.match(hn)||[]}(n):n.match(t)||[]}var na=Ye((function(n,t){try{return Rt(n,u,t)}catch(n){return Yo(n)?n:new kn(n)}})),ta=ei((function(n,t){return Et(t,(function(t){t=Bi(t),oe(n,t,Eo(n[t],n))})),n}));function ra(n){return function(){return n}}var ea=Fu(),ua=Fu(!0);function ia(n){return n}function oa(n){return Ue("function"==typeof n?n:ce(n,1))}var fa=Ye((function(n,t){return function(r){return Se(r,n,t)}})),aa=Ye((function(n,t){return function(r){return Se(n,r,t)}}));function ca(n,t,r){var e=Lf(t),u=je(t,e);null!=r||tf(t)&&(u.length||!e.length)||(r=t,t=n,n=this,u=je(t,Lf(t)));var i=!(tf(r)&&"chain"in r&&!r.chain),o=Qo(n);return Et(u,(function(r){var e=t[r];n[r]=e,o&&(n.prototype[r]=function(){var t=this.__chain__;if(i||t){var r=n(this.__wrapped__);return(r.__actions__=Eu(this.__actions__)).push({func:e,args:arguments,thisArg:n}),r.__chain__=t,r}return e.apply(n,Bt([this.value()],arguments))})})),n}function la(){}var sa=qu(Ut),ha=qu(Wt),pa=qu(Ft);function va(n){return mi(n)?Gt(Bi(n)):function(n){return function(t){return Ae(t,n)}}(n)}var _a=Ku(),ga=Ku(!0);function ya(){return[]}function da(){return!1}var ba=Pu((function(n,t){return n+t}),0),wa=Hu("ceil"),ma=Pu((function(n,t){return n/t}),1),xa=Hu("floor");var ja,Aa=Pu((function(n,t){return n*t}),1),ka=Hu("round"),Oa=Pu((function(n,t){return n-t}),0);return Mr.after=function(n,t){if("function"!=typeof t)throw new Sn(i);return n=gf(n),function(){if(--n<1)return t.apply(this,arguments)}},Mr.ary=Ro,Mr.assign=mf,Mr.assignIn=xf,Mr.assignInWith=jf,Mr.assignWith=Af,Mr.at=kf,Mr.before=zo,Mr.bind=Eo,Mr.bindAll=ta,Mr.bindKey=So,Mr.castArray=function(){if(!arguments.length)return[];var n=arguments[0];return Zo(n)?n:[n]},Mr.chain=ho,Mr.chunk=function(n,t,r){t=(r?wi(n,t,r):t===u)?1:br(gf(t),0);var i=null==n?0:n.length;if(!i||t<1)return[];for(var o=0,f=0,a=e(_t(i/t));oi?0:i+r),(e=e===u||e>i?i:gf(e))<0&&(e+=i),e=r>e?0:yf(e);r>>0)?(n=wf(n))&&("string"==typeof t||null!=t&&!ff(t))&&!(t=lu(t))&&ar(n)?xu(_r(n),0,r):n.split(t,r):[]},Mr.spread=function(n,t){if("function"!=typeof n)throw new Sn(i);return t=null==t?0:br(gf(t),0),Ye((function(r){var e=r[t],u=xu(r,0,t);return e&&Bt(u,e),Rt(n,this,u)}))},Mr.tail=function(n){var t=null==n?0:n.length;return t?uu(n,1,t):[]},Mr.take=function(n,t,r){return n&&n.length?uu(n,0,(t=r||t===u?1:gf(t))<0?0:t):[]},Mr.takeRight=function(n,t,r){var e=null==n?0:n.length;return e?uu(n,(t=e-(t=r||t===u?1:gf(t)))<0?0:t,e):[]},Mr.takeRightWhile=function(n,t){return n&&n.length?vu(n,ci(t,3),!1,!0):[]},Mr.takeWhile=function(n,t){return n&&n.length?vu(n,ci(t,3)):[]},Mr.tap=function(n,t){return t(n),n},Mr.throttle=function(n,t,r){var e=!0,u=!0;if("function"!=typeof n)throw new Sn(i);return tf(r)&&(e="leading"in r?!!r.leading:e,u="trailing"in r?!!r.trailing:u),Wo(n,t,{leading:e,maxWait:t,trailing:u})},Mr.thru=po,Mr.toArray=vf,Mr.toPairs=Ff,Mr.toPairsIn=Mf,Mr.toPath=function(n){return Zo(n)?Ut(n,Bi):lf(n)?[n]:Eu(Ui(wf(n)))},Mr.toPlainObject=bf,Mr.transform=function(n,t,r){var e=Zo(n),u=e||Ho(n)||sf(n);if(t=ci(t,4),null==r){var i=n&&n.constructor;r=u?e?new i:[]:tf(n)&&Qo(i)?Nr(Gn(n)):{}}return(u?Et:me)(n,(function(n,e,u){return t(r,n,e,u)})),r},Mr.unary=function(n){return Ro(n,1)},Mr.union=to,Mr.unionBy=ro,Mr.unionWith=eo,Mr.uniq=function(n){return n&&n.length?su(n):[]},Mr.uniqBy=function(n,t){return n&&n.length?su(n,ci(t,2)):[]},Mr.uniqWith=function(n,t){return t="function"==typeof t?t:u,n&&n.length?su(n,u,t):[]},Mr.unset=function(n,t){return null==n||hu(n,t)},Mr.unzip=uo,Mr.unzipWith=io,Mr.update=function(n,t,r){return null==n?n:pu(n,t,bu(r))},Mr.updateWith=function(n,t,r,e){return e="function"==typeof e?e:u,null==n?n:pu(n,t,bu(r),e)},Mr.values=Nf,Mr.valuesIn=function(n){return null==n?[]:tr(n,Cf(n))},Mr.without=oo,Mr.words=Xf,Mr.wrap=function(n,t){return $o(bu(t),n)},Mr.xor=fo,Mr.xorBy=ao,Mr.xorWith=co,Mr.zip=lo,Mr.zipObject=function(n,t){return yu(n||[],t||[],re)},Mr.zipObjectDeep=function(n,t){return yu(n||[],t||[],nu)},Mr.zipWith=so,Mr.entries=Ff,Mr.entriesIn=Mf,Mr.extend=xf,Mr.extendWith=jf,ca(Mr,Mr),Mr.add=ba,Mr.attempt=na,Mr.camelCase=Pf,Mr.capitalize=qf,Mr.ceil=wa,Mr.clamp=function(n,t,r){return r===u&&(r=t,t=u),r!==u&&(r=(r=df(r))==r?r:0),t!==u&&(t=(t=df(t))==t?t:0),ae(df(n),t,r)},Mr.clone=function(n){return ce(n,4)},Mr.cloneDeep=function(n){return ce(n,5)},Mr.cloneDeepWith=function(n,t){return ce(n,5,t="function"==typeof t?t:u)},Mr.cloneWith=function(n,t){return ce(n,4,t="function"==typeof t?t:u)},Mr.conformsTo=function(n,t){return null==t||le(n,t,Lf(t))},Mr.deburr=Zf,Mr.defaultTo=function(n,t){return null==n||n!=n?t:n},Mr.divide=ma,Mr.endsWith=function(n,t,r){n=wf(n),t=lu(t);var e=n.length,i=r=r===u?e:ae(gf(r),0,e);return(r-=t.length)>=0&&n.slice(r,i)==t},Mr.eq=Mo,Mr.escape=function(n){return(n=wf(n))&&Y.test(n)?n.replace(H,or):n},Mr.escapeRegExp=function(n){return(n=wf(n))&&on.test(n)?n.replace(un,"\\$&"):n},Mr.every=function(n,t,r){var e=Zo(n)?Wt:_e;return r&&wi(n,t,r)&&(t=u),e(n,ci(t,3))},Mr.find=go,Mr.findIndex=Pi,Mr.findKey=function(n,t){return Nt(n,ci(t,3),me)},Mr.findLast=yo,Mr.findLastIndex=qi,Mr.findLastKey=function(n,t){return Nt(n,ci(t,3),xe)},Mr.floor=xa,Mr.forEach=bo,Mr.forEachRight=wo,Mr.forIn=function(n,t){return null==n?n:be(n,ci(t,3),Cf)},Mr.forInRight=function(n,t){return null==n?n:we(n,ci(t,3),Cf)},Mr.forOwn=function(n,t){return n&&me(n,ci(t,3))},Mr.forOwnRight=function(n,t){return n&&xe(n,ci(t,3))},Mr.get=Rf,Mr.gt=No,Mr.gte=Po,Mr.has=function(n,t){return null!=n&&gi(n,t,Re)},Mr.hasIn=zf,Mr.head=Ki,Mr.identity=ia,Mr.includes=function(n,t,r,e){n=Vo(n)?n:Nf(n),r=r&&!e?gf(r):0;var u=n.length;return r<0&&(r=br(u+r,0)),cf(n)?r<=u&&n.indexOf(t,r)>-1:!!u&&qt(n,t,r)>-1},Mr.indexOf=function(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=null==r?0:gf(r);return u<0&&(u=br(e+u,0)),qt(n,t,u)},Mr.inRange=function(n,t,r){return t=_f(t),r===u?(r=t,t=0):r=_f(r),function(n,t,r){return n>=wr(t,r)&&n=-9007199254740991&&n<=v},Mr.isSet=af,Mr.isString=cf,Mr.isSymbol=lf,Mr.isTypedArray=sf,Mr.isUndefined=function(n){return n===u},Mr.isWeakMap=function(n){return rf(n)&&_i(n)==L},Mr.isWeakSet=function(n){return rf(n)&&"[object WeakSet]"==Oe(n)},Mr.join=function(n,t){return null==n?"":Mt.call(n,t)},Mr.kebabCase=Kf,Mr.last=Ji,Mr.lastIndexOf=function(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var i=e;return r!==u&&(i=(i=gf(r))<0?br(e+i,0):wr(i,e-1)),t==t?function(n,t,r){for(var e=r+1;e--;)if(n[e]===t)return e;return e}(n,t,i):Pt(n,Kt,i,!0)},Mr.lowerCase=Vf,Mr.lowerFirst=Gf,Mr.lt=hf,Mr.lte=pf,Mr.max=function(n){return n&&n.length?ge(n,ia,Ie):u},Mr.maxBy=function(n,t){return n&&n.length?ge(n,ci(t,2),Ie):u},Mr.mean=function(n){return Vt(n,ia)},Mr.meanBy=function(n,t){return Vt(n,ci(t,2))},Mr.min=function(n){return n&&n.length?ge(n,ia,De):u},Mr.minBy=function(n,t){return n&&n.length?ge(n,ci(t,2),De):u},Mr.stubArray=ya,Mr.stubFalse=da,Mr.stubObject=function(){return{}},Mr.stubString=function(){return""},Mr.stubTrue=function(){return!0},Mr.multiply=Aa,Mr.nth=function(n,t){return n&&n.length?qe(n,gf(t)):u},Mr.noConflict=function(){return gt._===this&&(gt._=Nn),this},Mr.noop=la,Mr.now=Io,Mr.pad=function(n,t,r){n=wf(n);var e=(t=gf(t))?vr(n):0;if(!t||e>=t)return n;var u=(t-e)/2;return Zu(yt(u),r)+n+Zu(_t(u),r)},Mr.padEnd=function(n,t,r){n=wf(n);var e=(t=gf(t))?vr(n):0;return t&&et){var e=n;n=t,t=e}if(r||n%1||t%1){var i=jr();return wr(n+i*(t-n+ht("1e-"+((i+"").length-1))),t)}return He(n,t)},Mr.reduce=function(n,t,r){var e=Zo(n)?$t:Jt,u=arguments.length<3;return e(n,ci(t,4),r,u,pe)},Mr.reduceRight=function(n,t,r){var e=Zo(n)?Dt:Jt,u=arguments.length<3;return e(n,ci(t,4),r,u,ve)},Mr.repeat=function(n,t,r){return t=(r?wi(n,t,r):t===u)?1:gf(t),Je(wf(n),t)},Mr.replace=function(){var n=arguments,t=wf(n[0]);return n.length<3?t:t.replace(n[1],n[2])},Mr.result=function(n,t,r){var e=-1,i=(t=wu(t,n)).length;for(i||(i=1,n=u);++ev)return[];var r=g,e=wr(n,g);t=ci(t),n-=g;for(var u=Qt(e,t);++r=o)return n;var a=r-vr(e);if(a<1)return e;var c=f?xu(f,0,a).join(""):n.slice(0,a);if(i===u)return c+e;if(f&&(a+=c.length-a),ff(i)){if(n.slice(a).search(i)){var l,s=c;for(i.global||(i=zn(i.source,wf(gn.exec(i))+"g")),i.lastIndex=0;l=i.exec(s);)var h=l.index;c=c.slice(0,h===u?a:h)}}else if(n.indexOf(lu(i),a)!=a){var p=c.lastIndexOf(i);p>-1&&(c=c.slice(0,p))}return c+e},Mr.unescape=function(n){return(n=wf(n))&&J.test(n)?n.replace(G,yr):n},Mr.uniqueId=function(n){var t=++$n;return wf(n)+t},Mr.upperCase=Yf,Mr.upperFirst=Qf,Mr.each=bo,Mr.eachRight=wo,Mr.first=Ki,ca(Mr,(ja={},me(Mr,(function(n,t){Bn.call(Mr.prototype,t)||(ja[t]=n)})),ja),{chain:!1}),Mr.VERSION="4.17.21",Et(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(n){Mr[n].placeholder=Mr})),Et(["drop","take"],(function(n,t){Zr.prototype[n]=function(r){r=r===u?1:br(gf(r),0);var e=this.__filtered__&&!t?new Zr(this):this.clone();return e.__filtered__?e.__takeCount__=wr(r,e.__takeCount__):e.__views__.push({size:wr(r,g),type:n+(e.__dir__<0?"Right":"")}),e},Zr.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}})),Et(["filter","map","takeWhile"],(function(n,t){var r=t+1,e=1==r||3==r;Zr.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:ci(n,3),type:r}),t.__filtered__=t.__filtered__||e,t}})),Et(["head","last"],(function(n,t){var r="take"+(t?"Right":"");Zr.prototype[n]=function(){return this[r](1).value()[0]}})),Et(["initial","tail"],(function(n,t){var r="drop"+(t?"":"Right");Zr.prototype[n]=function(){return this.__filtered__?new Zr(this):this[r](1)}})),Zr.prototype.compact=function(){return this.filter(ia)},Zr.prototype.find=function(n){return this.filter(n).head()},Zr.prototype.findLast=function(n){return this.reverse().find(n)},Zr.prototype.invokeMap=Ye((function(n,t){return"function"==typeof n?new Zr(this):this.map((function(r){return Se(r,n,t)}))})),Zr.prototype.reject=function(n){return this.filter(Uo(ci(n)))},Zr.prototype.slice=function(n,t){n=gf(n);var r=this;return r.__filtered__&&(n>0||t<0)?new Zr(r):(n<0?r=r.takeRight(-n):n&&(r=r.drop(n)),t!==u&&(r=(t=gf(t))<0?r.dropRight(-t):r.take(t-n)),r)},Zr.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},Zr.prototype.toArray=function(){return this.take(g)},me(Zr.prototype,(function(n,t){var r=/^(?:filter|find|map|reject)|While$/.test(t),e=/^(?:head|last)$/.test(t),i=Mr[e?"take"+("last"==t?"Right":""):t],o=e||/^find/.test(t);i&&(Mr.prototype[t]=function(){var t=this.__wrapped__,f=e?[1]:arguments,a=t instanceof Zr,c=f[0],l=a||Zo(t),s=function(n){var t=i.apply(Mr,Bt([n],f));return e&&h?t[0]:t};l&&r&&"function"==typeof c&&1!=c.length&&(a=l=!1);var h=this.__chain__,p=!!this.__actions__.length,v=o&&!h,_=a&&!p;if(!o&&l){t=_?t:new Zr(this);var g=n.apply(t,f);return g.__actions__.push({func:po,args:[s],thisArg:u}),new qr(g,h)}return v&&_?n.apply(this,f):(g=this.thru(s),v?e?g.value()[0]:g.value():g)})})),Et(["pop","push","shift","sort","splice","unshift"],(function(n){var t=Wn[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:pop|shift)$/.test(n);Mr.prototype[n]=function(){var n=arguments;if(e&&!this.__chain__){var u=this.value();return t.apply(Zo(u)?u:[],n)}return this[r]((function(r){return t.apply(Zo(r)?r:[],n)}))}})),me(Zr.prototype,(function(n,t){var r=Mr[t];if(r){var e=r.name+"";Bn.call(Wr,e)||(Wr[e]=[]),Wr[e].push({name:t,func:r})}})),Wr[Mu(u,2).name]=[{name:"wrapper",func:u}],Zr.prototype.clone=function(){var n=new Zr(this.__wrapped__);return n.__actions__=Eu(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=Eu(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=Eu(this.__views__),n},Zr.prototype.reverse=function(){if(this.__filtered__){var n=new Zr(this);n.__dir__=-1,n.__filtered__=!0}else(n=this.clone()).__dir__*=-1;return n},Zr.prototype.value=function(){var n=this.__wrapped__.value(),t=this.__dir__,r=Zo(n),e=t<0,u=r?n.length:0,i=function(n,t,r){var e=-1,u=r.length;for(;++e=this.__values__.length;return{done:n,value:n?u:this.__values__[this.__index__++]}},Mr.prototype.plant=function(n){for(var t,r=this;r instanceof Pr;){var e=Di(r);e.__index__=0,e.__values__=u,t?i.__wrapped__=e:t=e;var i=e;r=r.__wrapped__}return i.__wrapped__=n,t},Mr.prototype.reverse=function(){var n=this.__wrapped__;if(n instanceof Zr){var t=n;return this.__actions__.length&&(t=new Zr(this)),(t=t.reverse()).__actions__.push({func:po,args:[no],thisArg:u}),new qr(t,this.__chain__)}return this.thru(no)},Mr.prototype.toJSON=Mr.prototype.valueOf=Mr.prototype.value=function(){return _u(this.__wrapped__,this.__actions__)},Mr.prototype.first=Mr.prototype.head,Xn&&(Mr.prototype[Xn]=function(){return this}),Mr}();gt._=dr,(e=function(){return dr}.call(t,r,t,n))===u||(n.exports=e)}.call(this)},7803:(n,t,r)=>{n.exports=r(2543)}},t={};function r(e){var u=t[e];if(void 0!==u)return u.exports;var i=t[e]={id:e,loaded:!1,exports:{}};return n[e].call(i.exports,i,i.exports,r),i.loaded=!0,i.exports}return r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(n){if("object"==typeof window)return window}}(),r.nmd=n=>(n.paths=[],n.children||(n.children=[]),n),r(7803)})())); \ No newline at end of file + */n=r.nmd(n),function(){var u,i="Expected a function",o="__lodash_hash_undefined__",f="__lodash_placeholder__",a=16,c=32,l=64,s=128,h=256,p=1/0,v=9007199254740991,_=NaN,g=4294967295,y=[["ary",s],["bind",1],["bindKey",2],["curry",8],["curryRight",a],["flip",512],["partial",c],["partialRight",l],["rearg",h]],d="[object Arguments]",b="[object Array]",w="[object Boolean]",m="[object Date]",x="[object Error]",j="[object Function]",A="[object GeneratorFunction]",k="[object Map]",I="[object Number]",O="[object Object]",R="[object Promise]",z="[object RegExp]",E="[object Set]",S="[object String]",W="[object Symbol]",L="[object WeakMap]",C="[object ArrayBuffer]",T="[object DataView]",U="[object Float32Array]",B="[object Float64Array]",$="[object Int8Array]",D="[object Int16Array]",F="[object Int32Array]",M="[object Uint8Array]",N="[object Uint8ClampedArray]",P="[object Uint16Array]",q="[object Uint32Array]",Z=/\b__p \+= '';/g,K=/\b(__p \+=) '' \+/g,V=/(__e\(.*?\)|\b__t\)) \+\n'';/g,G=/&(?:amp|lt|gt|quot|#39);/g,H=/[&<>"']/g,J=RegExp(G.source),Y=RegExp(H.source),Q=/<%-([\s\S]+?)%>/g,X=/<%([\s\S]+?)%>/g,nn=/<%=([\s\S]+?)%>/g,tn=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,rn=/^\w*$/,en=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,un=/[\\^$.*+?()[\]{}|]/g,on=RegExp(un.source),fn=/^\s+/,an=/\s/,cn=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,ln=/\{\n\/\* \[wrapped with (.+)\] \*/,sn=/,? & /,hn=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,pn=/[()=,{}\[\]\/\s]/,vn=/\\(\\)?/g,_n=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,gn=/\w*$/,yn=/^[-+]0x[0-9a-f]+$/i,dn=/^0b[01]+$/i,bn=/^\[object .+?Constructor\]$/,wn=/^0o[0-7]+$/i,mn=/^(?:0|[1-9]\d*)$/,xn=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,jn=/($^)/,An=/['\n\r\u2028\u2029\\]/g,kn="\\ud800-\\udfff",In="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",On="\\u2700-\\u27bf",Rn="a-z\\xdf-\\xf6\\xf8-\\xff",zn="A-Z\\xc0-\\xd6\\xd8-\\xde",En="\\ufe0e\\ufe0f",Sn="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",Wn="['’]",Ln="["+kn+"]",Cn="["+Sn+"]",Tn="["+In+"]",Un="\\d+",Bn="["+On+"]",$n="["+Rn+"]",Dn="[^"+kn+Sn+Un+On+Rn+zn+"]",Fn="\\ud83c[\\udffb-\\udfff]",Mn="[^"+kn+"]",Nn="(?:\\ud83c[\\udde6-\\uddff]){2}",Pn="[\\ud800-\\udbff][\\udc00-\\udfff]",qn="["+zn+"]",Zn="\\u200d",Kn="(?:"+$n+"|"+Dn+")",Vn="(?:"+qn+"|"+Dn+")",Gn="(?:['’](?:d|ll|m|re|s|t|ve))?",Hn="(?:['’](?:D|LL|M|RE|S|T|VE))?",Jn="(?:"+Tn+"|"+Fn+")"+"?",Yn="["+En+"]?",Qn=Yn+Jn+("(?:"+Zn+"(?:"+[Mn,Nn,Pn].join("|")+")"+Yn+Jn+")*"),Xn="(?:"+[Bn,Nn,Pn].join("|")+")"+Qn,nt="(?:"+[Mn+Tn+"?",Tn,Nn,Pn,Ln].join("|")+")",tt=RegExp(Wn,"g"),rt=RegExp(Tn,"g"),et=RegExp(Fn+"(?="+Fn+")|"+nt+Qn,"g"),ut=RegExp([qn+"?"+$n+"+"+Gn+"(?="+[Cn,qn,"$"].join("|")+")",Vn+"+"+Hn+"(?="+[Cn,qn+Kn,"$"].join("|")+")",qn+"?"+Kn+"+"+Gn,qn+"+"+Hn,"\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",Un,Xn].join("|"),"g"),it=RegExp("["+Zn+kn+In+En+"]"),ot=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,ft=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],at=-1,ct={};ct[U]=ct[B]=ct[$]=ct[D]=ct[F]=ct[M]=ct[N]=ct[P]=ct[q]=!0,ct[d]=ct[b]=ct[C]=ct[w]=ct[T]=ct[m]=ct[x]=ct[j]=ct[k]=ct[I]=ct[O]=ct[z]=ct[E]=ct[S]=ct[L]=!1;var lt={};lt[d]=lt[b]=lt[C]=lt[T]=lt[w]=lt[m]=lt[U]=lt[B]=lt[$]=lt[D]=lt[F]=lt[k]=lt[I]=lt[O]=lt[z]=lt[E]=lt[S]=lt[W]=lt[M]=lt[N]=lt[P]=lt[q]=!0,lt[x]=lt[j]=lt[L]=!1;var st={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},ht=parseFloat,pt=parseInt,vt="object"==typeof r.g&&r.g&&r.g.Object===Object&&r.g,_t="object"==typeof self&&self&&self.Object===Object&&self,gt=vt||_t||Function("return this")(),yt=t&&!t.nodeType&&t,dt=yt&&n&&!n.nodeType&&n,bt=dt&&dt.exports===yt,wt=bt&&vt.process,mt=function(){try{var n=dt&&dt.require&&dt.require("util").types;return n||wt&&wt.binding&&wt.binding("util")}catch(n){}}(),xt=mt&&mt.isArrayBuffer,jt=mt&&mt.isDate,At=mt&&mt.isMap,kt=mt&&mt.isRegExp,It=mt&&mt.isSet,Ot=mt&&mt.isTypedArray;function Rt(n,t,r){switch(r.length){case 0:return n.call(t);case 1:return n.call(t,r[0]);case 2:return n.call(t,r[0],r[1]);case 3:return n.call(t,r[0],r[1],r[2])}return n.apply(t,r)}function zt(n,t,r,e){for(var u=-1,i=null==n?0:n.length;++u-1}function Tt(n,t,r){for(var e=-1,u=null==n?0:n.length;++e-1;);return r}function ur(n,t){for(var r=n.length;r--&&qt(t,n[r],0)>-1;);return r}var ir=Ht({À:"A",Á:"A",Â:"A",Ã:"A",Ä:"A",Å:"A",à:"a",á:"a",â:"a",ã:"a",ä:"a",å:"a",Ç:"C",ç:"c",Ð:"D",ð:"d",È:"E",É:"E",Ê:"E",Ë:"E",è:"e",é:"e",ê:"e",ë:"e",Ì:"I",Í:"I",Î:"I",Ï:"I",ì:"i",í:"i",î:"i",ï:"i",Ñ:"N",ñ:"n",Ò:"O",Ó:"O",Ô:"O",Õ:"O",Ö:"O",Ø:"O",ò:"o",ó:"o",ô:"o",õ:"o",ö:"o",ø:"o",Ù:"U",Ú:"U",Û:"U",Ü:"U",ù:"u",ú:"u",û:"u",ü:"u",Ý:"Y",ý:"y",ÿ:"y",Æ:"Ae",æ:"ae",Þ:"Th",þ:"th",ß:"ss",Ā:"A",Ă:"A",Ą:"A",ā:"a",ă:"a",ą:"a",Ć:"C",Ĉ:"C",Ċ:"C",Č:"C",ć:"c",ĉ:"c",ċ:"c",č:"c",Ď:"D",Đ:"D",ď:"d",đ:"d",Ē:"E",Ĕ:"E",Ė:"E",Ę:"E",Ě:"E",ē:"e",ĕ:"e",ė:"e",ę:"e",ě:"e",Ĝ:"G",Ğ:"G",Ġ:"G",Ģ:"G",ĝ:"g",ğ:"g",ġ:"g",ģ:"g",Ĥ:"H",Ħ:"H",ĥ:"h",ħ:"h",Ĩ:"I",Ī:"I",Ĭ:"I",Į:"I",İ:"I",ĩ:"i",ī:"i",ĭ:"i",į:"i",ı:"i",Ĵ:"J",ĵ:"j",Ķ:"K",ķ:"k",ĸ:"k",Ĺ:"L",Ļ:"L",Ľ:"L",Ŀ:"L",Ł:"L",ĺ:"l",ļ:"l",ľ:"l",ŀ:"l",ł:"l",Ń:"N",Ņ:"N",Ň:"N",Ŋ:"N",ń:"n",ņ:"n",ň:"n",ŋ:"n",Ō:"O",Ŏ:"O",Ő:"O",ō:"o",ŏ:"o",ő:"o",Ŕ:"R",Ŗ:"R",Ř:"R",ŕ:"r",ŗ:"r",ř:"r",Ś:"S",Ŝ:"S",Ş:"S",Š:"S",ś:"s",ŝ:"s",ş:"s",š:"s",Ţ:"T",Ť:"T",Ŧ:"T",ţ:"t",ť:"t",ŧ:"t",Ũ:"U",Ū:"U",Ŭ:"U",Ů:"U",Ű:"U",Ų:"U",ũ:"u",ū:"u",ŭ:"u",ů:"u",ű:"u",ų:"u",Ŵ:"W",ŵ:"w",Ŷ:"Y",ŷ:"y",Ÿ:"Y",Ź:"Z",Ż:"Z",Ž:"Z",ź:"z",ż:"z",ž:"z",IJ:"IJ",ij:"ij",Œ:"Oe",œ:"oe",ʼn:"'n",ſ:"s"}),or=Ht({"&":"&","<":"<",">":">",'"':""","'":"'"});function fr(n){return"\\"+st[n]}function ar(n){return it.test(n)}function cr(n){var t=-1,r=Array(n.size);return n.forEach((function(n,e){r[++t]=[e,n]})),r}function lr(n,t){return function(r){return n(t(r))}}function sr(n,t){for(var r=-1,e=n.length,u=0,i=[];++r",""":'"',"'":"'"});var dr=function n(t){var r,e=(t=null==t?gt:dr.defaults(gt.Object(),t,dr.pick(gt,ft))).Array,an=t.Date,kn=t.Error,In=t.Function,On=t.Math,Rn=t.Object,zn=t.RegExp,En=t.String,Sn=t.TypeError,Wn=e.prototype,Ln=In.prototype,Cn=Rn.prototype,Tn=t["__core-js_shared__"],Un=Ln.toString,Bn=Cn.hasOwnProperty,$n=0,Dn=(r=/[^.]+$/.exec(Tn&&Tn.keys&&Tn.keys.IE_PROTO||""))?"Symbol(src)_1."+r:"",Fn=Cn.toString,Mn=Un.call(Rn),Nn=gt._,Pn=zn("^"+Un.call(Bn).replace(un,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),qn=bt?t.Buffer:u,Zn=t.Symbol,Kn=t.Uint8Array,Vn=qn?qn.allocUnsafe:u,Gn=lr(Rn.getPrototypeOf,Rn),Hn=Rn.create,Jn=Cn.propertyIsEnumerable,Yn=Wn.splice,Qn=Zn?Zn.isConcatSpreadable:u,Xn=Zn?Zn.iterator:u,nt=Zn?Zn.toStringTag:u,et=function(){try{var n=hi(Rn,"defineProperty");return n({},"",{}),n}catch(n){}}(),it=t.clearTimeout!==gt.clearTimeout&&t.clearTimeout,st=an&&an.now!==gt.Date.now&&an.now,vt=t.setTimeout!==gt.setTimeout&&t.setTimeout,_t=On.ceil,yt=On.floor,dt=Rn.getOwnPropertySymbols,wt=qn?qn.isBuffer:u,mt=t.isFinite,Mt=Wn.join,Ht=lr(Rn.keys,Rn),br=On.max,wr=On.min,mr=an.now,xr=t.parseInt,jr=On.random,Ar=Wn.reverse,kr=hi(t,"DataView"),Ir=hi(t,"Map"),Or=hi(t,"Promise"),Rr=hi(t,"Set"),zr=hi(t,"WeakMap"),Er=hi(Rn,"create"),Sr=zr&&new zr,Wr={},Lr=$i(kr),Cr=$i(Ir),Tr=$i(Or),Ur=$i(Rr),Br=$i(zr),$r=Zn?Zn.prototype:u,Dr=$r?$r.valueOf:u,Fr=$r?$r.toString:u;function Mr(n){if(rf(n)&&!Zo(n)&&!(n instanceof Zr)){if(n instanceof qr)return n;if(Bn.call(n,"__wrapped__"))return Di(n)}return new qr(n)}var Nr=function(){function n(){}return function(t){if(!tf(t))return{};if(Hn)return Hn(t);n.prototype=t;var r=new n;return n.prototype=u,r}}();function Pr(){}function qr(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=u}function Zr(n){this.__wrapped__=n,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=g,this.__views__=[]}function Kr(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t=t?n:t)),n}function ce(n,t,r,e,i,o){var f,a=1&t,c=2&t,l=4&t;if(r&&(f=i?r(n,e,i,o):r(n)),f!==u)return f;if(!tf(n))return n;var s=Zo(n);if(s){if(f=function(n){var t=n.length,r=new n.constructor(t);t&&"string"==typeof n[0]&&Bn.call(n,"index")&&(r.index=n.index,r.input=n.input);return r}(n),!a)return Eu(n,f)}else{var h=_i(n),p=h==j||h==A;if(Ho(n))return Au(n,a);if(h==O||h==d||p&&!i){if(f=c||p?{}:yi(n),!a)return c?function(n,t){return Su(n,vi(n),t)}(n,function(n,t){return n&&Su(t,Cf(t),n)}(f,n)):function(n,t){return Su(n,pi(n),t)}(n,ie(f,n))}else{if(!lt[h])return i?n:{};f=function(n,t,r){var e=n.constructor;switch(t){case C:return ku(n);case w:case m:return new e(+n);case T:return function(n,t){var r=t?ku(n.buffer):n.buffer;return new n.constructor(r,n.byteOffset,n.byteLength)}(n,r);case U:case B:case $:case D:case F:case M:case N:case P:case q:return Iu(n,r);case k:return new e;case I:case S:return new e(n);case z:return function(n){var t=new n.constructor(n.source,gn.exec(n));return t.lastIndex=n.lastIndex,t}(n);case E:return new e;case W:return u=n,Dr?Rn(Dr.call(u)):{}}var u}(n,h,a)}}o||(o=new Jr);var v=o.get(n);if(v)return v;o.set(n,f),af(n)?n.forEach((function(e){f.add(ce(e,t,r,e,n,o))})):ef(n)&&n.forEach((function(e,u){f.set(u,ce(e,t,r,u,n,o))}));var _=s?u:(l?c?ii:ui:c?Cf:Lf)(n);return Et(_||n,(function(e,u){_&&(e=n[u=e]),re(f,u,ce(e,t,r,u,n,o))})),f}function le(n,t,r){var e=r.length;if(null==n)return!e;for(n=Rn(n);e--;){var i=r[e],o=t[i],f=n[i];if(f===u&&!(i in n)||!o(f))return!1}return!0}function se(n,t,r){if("function"!=typeof n)throw new Sn(i);return Si((function(){n.apply(u,r)}),t)}function he(n,t,r,e){var u=-1,i=Ct,o=!0,f=n.length,a=[],c=t.length;if(!f)return a;r&&(t=Ut(t,nr(r))),e?(i=Tt,o=!1):t.length>=200&&(i=rr,o=!1,t=new Hr(t));n:for(;++u-1},Vr.prototype.set=function(n,t){var r=this.__data__,e=ee(r,n);return e<0?(++this.size,r.push([n,t])):r[e][1]=t,this},Gr.prototype.clear=function(){this.size=0,this.__data__={hash:new Kr,map:new(Ir||Vr),string:new Kr}},Gr.prototype.delete=function(n){var t=li(this,n).delete(n);return this.size-=t?1:0,t},Gr.prototype.get=function(n){return li(this,n).get(n)},Gr.prototype.has=function(n){return li(this,n).has(n)},Gr.prototype.set=function(n,t){var r=li(this,n),e=r.size;return r.set(n,t),this.size+=r.size==e?0:1,this},Hr.prototype.add=Hr.prototype.push=function(n){return this.__data__.set(n,o),this},Hr.prototype.has=function(n){return this.__data__.has(n)},Jr.prototype.clear=function(){this.__data__=new Vr,this.size=0},Jr.prototype.delete=function(n){var t=this.__data__,r=t.delete(n);return this.size=t.size,r},Jr.prototype.get=function(n){return this.__data__.get(n)},Jr.prototype.has=function(n){return this.__data__.has(n)},Jr.prototype.set=function(n,t){var r=this.__data__;if(r instanceof Vr){var e=r.__data__;if(!Ir||e.length<199)return e.push([n,t]),this.size=++r.size,this;r=this.__data__=new Gr(e)}return r.set(n,t),this.size=r.size,this};var pe=Cu(me),ve=Cu(xe,!0);function _e(n,t){var r=!0;return pe(n,(function(n,e,u){return r=!!t(n,e,u)})),r}function ge(n,t,r){for(var e=-1,i=n.length;++e0&&r(f)?t>1?de(f,t-1,r,e,u):Bt(u,f):e||(u[u.length]=f)}return u}var be=Tu(),we=Tu(!0);function me(n,t){return n&&be(n,t,Lf)}function xe(n,t){return n&&we(n,t,Lf)}function je(n,t){return Lt(t,(function(t){return Qo(n[t])}))}function Ae(n,t){for(var r=0,e=(t=wu(t,n)).length;null!=n&&rt}function Re(n,t){return null!=n&&Bn.call(n,t)}function ze(n,t){return null!=n&&t in Rn(n)}function Ee(n,t,r){for(var i=r?Tt:Ct,o=n[0].length,f=n.length,a=f,c=e(f),l=1/0,s=[];a--;){var h=n[a];a&&t&&(h=Ut(h,nr(t))),l=wr(h.length,l),c[a]=!r&&(t||o>=120&&h.length>=120)?new Hr(a&&h):u}h=n[0];var p=-1,v=c[0];n:for(;++p=f?a:a*("desc"==r[e]?-1:1)}return n.index-t.index}(n,t,r)}))}function Ke(n,t,r){for(var e=-1,u=t.length,i={};++e-1;)f!==n&&Yn.call(f,a,1),Yn.call(n,a,1);return n}function Ge(n,t){for(var r=n?t.length:0,e=r-1;r--;){var u=t[r];if(r==e||u!==i){var i=u;bi(u)?Yn.call(n,u,1):hu(n,u)}}return n}function He(n,t){return n+yt(jr()*(t-n+1))}function Je(n,t){var r="";if(!n||t<1||t>v)return r;do{t%2&&(r+=n),(t=yt(t/2))&&(n+=n)}while(t);return r}function Ye(n,t){return Wi(Oi(n,t,ia),n+"")}function Qe(n){return Qr(Nf(n))}function Xe(n,t){var r=Nf(n);return Ti(r,ae(t,0,r.length))}function nu(n,t,r,e){if(!tf(n))return n;for(var i=-1,o=(t=wu(t,n)).length,f=o-1,a=n;null!=a&&++ii?0:i+t),(r=r>i?i:r)<0&&(r+=i),i=t>r?0:r-t>>>0,t>>>=0;for(var o=e(i);++u>>1,o=n[i];null!==o&&!lf(o)&&(r?o<=t:o=200){var c=t?null:Ju(n);if(c)return hr(c);o=!1,u=rr,a=new Hr}else a=t?[]:f;n:for(;++e=e?n:uu(n,t,r)}var ju=it||function(n){return gt.clearTimeout(n)};function Au(n,t){if(t)return n.slice();var r=n.length,e=Vn?Vn(r):new n.constructor(r);return n.copy(e),e}function ku(n){var t=new n.constructor(n.byteLength);return new Kn(t).set(new Kn(n)),t}function Iu(n,t){var r=t?ku(n.buffer):n.buffer;return new n.constructor(r,n.byteOffset,n.length)}function Ou(n,t){if(n!==t){var r=n!==u,e=null===n,i=n==n,o=lf(n),f=t!==u,a=null===t,c=t==t,l=lf(t);if(!a&&!l&&!o&&n>t||o&&f&&c&&!a&&!l||e&&f&&c||!r&&c||!i)return 1;if(!e&&!o&&!l&&n1?r[i-1]:u,f=i>2?r[2]:u;for(o=n.length>3&&"function"==typeof o?(i--,o):u,f&&wi(r[0],r[1],f)&&(o=i<3?u:o,i=1),t=Rn(t);++e-1?i[o?t[f]:f]:u}}function Fu(n){return ei((function(t){var r=t.length,e=r,o=qr.prototype.thru;for(n&&t.reverse();e--;){var f=t[e];if("function"!=typeof f)throw new Sn(i);if(o&&!a&&"wrapper"==fi(f))var a=new qr([],!0)}for(e=a?e:r;++e1&&w.reverse(),p&&la))return!1;var l=o.get(n),s=o.get(t);if(l&&s)return l==t&&s==n;var h=-1,p=!0,v=2&r?new Hr:u;for(o.set(n,t),o.set(t,n);++h-1&&n%1==0&&n1?"& ":"")+t[e],t=t.join(r>2?", ":" "),n.replace(cn,"{\n/* [wrapped with "+t+"] */\n")}(e,function(n,t){return Et(y,(function(r){var e="_."+r[0];t&r[1]&&!Ct(n,e)&&n.push(e)})),n.sort()}(function(n){var t=n.match(ln);return t?t[1].split(sn):[]}(e),r)))}function Ci(n){var t=0,r=0;return function(){var e=mr(),i=16-(e-r);if(r=e,i>0){if(++t>=800)return arguments[0]}else t=0;return n.apply(u,arguments)}}function Ti(n,t){var r=-1,e=n.length,i=e-1;for(t=t===u?e:t;++r1?n[t-1]:u;return r="function"==typeof r?(n.pop(),r):u,io(n,r)}));function ho(n){var t=Mr(n);return t.__chain__=!0,t}function po(n,t){return t(n)}var vo=ei((function(n){var t=n.length,r=t?n[0]:0,e=this.__wrapped__,i=function(t){return fe(t,n)};return!(t>1||this.__actions__.length)&&e instanceof Zr&&bi(r)?((e=e.slice(r,+r+(t?1:0))).__actions__.push({func:po,args:[i],thisArg:u}),new qr(e,this.__chain__).thru((function(n){return t&&!n.length&&n.push(u),n}))):this.thru(i)}));var _o=Wu((function(n,t,r){Bn.call(n,r)?++n[r]:oe(n,r,1)}));var go=Du(Pi),yo=Du(qi);function bo(n,t){return(Zo(n)?Et:pe)(n,ci(t,3))}function wo(n,t){return(Zo(n)?St:ve)(n,ci(t,3))}var mo=Wu((function(n,t,r){Bn.call(n,r)?n[r].push(t):oe(n,r,[t])}));var xo=Ye((function(n,t,r){var u=-1,i="function"==typeof t,o=Vo(n)?e(n.length):[];return pe(n,(function(n){o[++u]=i?Rt(t,n,r):Se(n,t,r)})),o})),jo=Wu((function(n,t,r){oe(n,r,t)}));function Ao(n,t){return(Zo(n)?Ut:Fe)(n,ci(t,3))}var ko=Wu((function(n,t,r){n[r?0:1].push(t)}),(function(){return[[],[]]}));var Io=Ye((function(n,t){if(null==n)return[];var r=t.length;return r>1&&wi(n,t[0],t[1])?t=[]:r>2&&wi(t[0],t[1],t[2])&&(t=[t[0]]),Ze(n,de(t,1),[])})),Oo=st||function(){return gt.Date.now()};function Ro(n,t,r){return t=r?u:t,t=n&&null==t?n.length:t,Qu(n,s,u,u,u,u,t)}function zo(n,t){var r;if("function"!=typeof t)throw new Sn(i);return n=gf(n),function(){return--n>0&&(r=t.apply(this,arguments)),n<=1&&(t=u),r}}var Eo=Ye((function(n,t,r){var e=1;if(r.length){var u=sr(r,ai(Eo));e|=c}return Qu(n,e,t,r,u)})),So=Ye((function(n,t,r){var e=3;if(r.length){var u=sr(r,ai(So));e|=c}return Qu(t,e,n,r,u)}));function Wo(n,t,r){var e,o,f,a,c,l,s=0,h=!1,p=!1,v=!0;if("function"!=typeof n)throw new Sn(i);function _(t){var r=e,i=o;return e=o=u,s=t,a=n.apply(i,r)}function g(n){var r=n-l;return l===u||r>=t||r<0||p&&n-s>=f}function y(){var n=Oo();if(g(n))return d(n);c=Si(y,function(n){var r=t-(n-l);return p?wr(r,f-(n-s)):r}(n))}function d(n){return c=u,v&&e?_(n):(e=o=u,a)}function b(){var n=Oo(),r=g(n);if(e=arguments,o=this,l=n,r){if(c===u)return function(n){return s=n,c=Si(y,t),h?_(n):a}(l);if(p)return ju(c),c=Si(y,t),_(l)}return c===u&&(c=Si(y,t)),a}return t=df(t)||0,tf(r)&&(h=!!r.leading,f=(p="maxWait"in r)?br(df(r.maxWait)||0,t):f,v="trailing"in r?!!r.trailing:v),b.cancel=function(){c!==u&&ju(c),s=0,e=l=o=c=u},b.flush=function(){return c===u?a:d(Oo())},b}var Lo=Ye((function(n,t){return se(n,1,t)})),Co=Ye((function(n,t,r){return se(n,df(t)||0,r)}));function To(n,t){if("function"!=typeof n||null!=t&&"function"!=typeof t)throw new Sn(i);var r=function(){var e=arguments,u=t?t.apply(this,e):e[0],i=r.cache;if(i.has(u))return i.get(u);var o=n.apply(this,e);return r.cache=i.set(u,o)||i,o};return r.cache=new(To.Cache||Gr),r}function Uo(n){if("function"!=typeof n)throw new Sn(i);return function(){var t=arguments;switch(t.length){case 0:return!n.call(this);case 1:return!n.call(this,t[0]);case 2:return!n.call(this,t[0],t[1]);case 3:return!n.call(this,t[0],t[1],t[2])}return!n.apply(this,t)}}To.Cache=Gr;var Bo=mu((function(n,t){var r=(t=1==t.length&&Zo(t[0])?Ut(t[0],nr(ci())):Ut(de(t,1),nr(ci()))).length;return Ye((function(e){for(var u=-1,i=wr(e.length,r);++u=t})),qo=We(function(){return arguments}())?We:function(n){return rf(n)&&Bn.call(n,"callee")&&!Jn.call(n,"callee")},Zo=e.isArray,Ko=xt?nr(xt):function(n){return rf(n)&&Ie(n)==C};function Vo(n){return null!=n&&nf(n.length)&&!Qo(n)}function Go(n){return rf(n)&&Vo(n)}var Ho=wt||da,Jo=jt?nr(jt):function(n){return rf(n)&&Ie(n)==m};function Yo(n){if(!rf(n))return!1;var t=Ie(n);return t==x||"[object DOMException]"==t||"string"==typeof n.message&&"string"==typeof n.name&&!of(n)}function Qo(n){if(!tf(n))return!1;var t=Ie(n);return t==j||t==A||"[object AsyncFunction]"==t||"[object Proxy]"==t}function Xo(n){return"number"==typeof n&&n==gf(n)}function nf(n){return"number"==typeof n&&n>-1&&n%1==0&&n<=v}function tf(n){var t=typeof n;return null!=n&&("object"==t||"function"==t)}function rf(n){return null!=n&&"object"==typeof n}var ef=At?nr(At):function(n){return rf(n)&&_i(n)==k};function uf(n){return"number"==typeof n||rf(n)&&Ie(n)==I}function of(n){if(!rf(n)||Ie(n)!=O)return!1;var t=Gn(n);if(null===t)return!0;var r=Bn.call(t,"constructor")&&t.constructor;return"function"==typeof r&&r instanceof r&&Un.call(r)==Mn}var ff=kt?nr(kt):function(n){return rf(n)&&Ie(n)==z};var af=It?nr(It):function(n){return rf(n)&&_i(n)==E};function cf(n){return"string"==typeof n||!Zo(n)&&rf(n)&&Ie(n)==S}function lf(n){return"symbol"==typeof n||rf(n)&&Ie(n)==W}var sf=Ot?nr(Ot):function(n){return rf(n)&&nf(n.length)&&!!ct[Ie(n)]};var hf=Vu(De),pf=Vu((function(n,t){return n<=t}));function vf(n){if(!n)return[];if(Vo(n))return cf(n)?_r(n):Eu(n);if(Xn&&n[Xn])return function(n){for(var t,r=[];!(t=n.next()).done;)r.push(t.value);return r}(n[Xn]());var t=_i(n);return(t==k?cr:t==E?hr:Nf)(n)}function _f(n){return n?(n=df(n))===p||n===-1/0?17976931348623157e292*(n<0?-1:1):n==n?n:0:0===n?n:0}function gf(n){var t=_f(n),r=t%1;return t==t?r?t-r:t:0}function yf(n){return n?ae(gf(n),0,g):0}function df(n){if("number"==typeof n)return n;if(lf(n))return _;if(tf(n)){var t="function"==typeof n.valueOf?n.valueOf():n;n=tf(t)?t+"":t}if("string"!=typeof n)return 0===n?n:+n;n=Xt(n);var r=dn.test(n);return r||wn.test(n)?pt(n.slice(2),r?2:8):yn.test(n)?_:+n}function bf(n){return Su(n,Cf(n))}function wf(n){return null==n?"":lu(n)}var mf=Lu((function(n,t){if(Ai(t)||Vo(t))Su(t,Lf(t),n);else for(var r in t)Bn.call(t,r)&&re(n,r,t[r])})),xf=Lu((function(n,t){Su(t,Cf(t),n)})),jf=Lu((function(n,t,r,e){Su(t,Cf(t),n,e)})),Af=Lu((function(n,t,r,e){Su(t,Lf(t),n,e)})),kf=ei(fe);var If=Ye((function(n,t){n=Rn(n);var r=-1,e=t.length,i=e>2?t[2]:u;for(i&&wi(t[0],t[1],i)&&(e=1);++r1),t})),Su(n,ii(n),r),e&&(r=ce(r,7,ti));for(var u=t.length;u--;)hu(r,t[u]);return r}));var $f=ei((function(n,t){return null==n?{}:function(n,t){return Ke(n,t,(function(t,r){return zf(n,r)}))}(n,t)}));function Df(n,t){if(null==n)return{};var r=Ut(ii(n),(function(n){return[n]}));return t=ci(t),Ke(n,r,(function(n,r){return t(n,r[0])}))}var Ff=Yu(Lf),Mf=Yu(Cf);function Nf(n){return null==n?[]:tr(n,Lf(n))}var Pf=Bu((function(n,t,r){return t=t.toLowerCase(),n+(r?qf(t):t)}));function qf(n){return Qf(wf(n).toLowerCase())}function Zf(n){return(n=wf(n))&&n.replace(xn,ir).replace(rt,"")}var Kf=Bu((function(n,t,r){return n+(r?"-":"")+t.toLowerCase()})),Vf=Bu((function(n,t,r){return n+(r?" ":"")+t.toLowerCase()})),Gf=Uu("toLowerCase");var Hf=Bu((function(n,t,r){return n+(r?"_":"")+t.toLowerCase()}));var Jf=Bu((function(n,t,r){return n+(r?" ":"")+Qf(t)}));var Yf=Bu((function(n,t,r){return n+(r?" ":"")+t.toUpperCase()})),Qf=Uu("toUpperCase");function Xf(n,t,r){return n=wf(n),(t=r?u:t)===u?function(n){return ot.test(n)}(n)?function(n){return n.match(ut)||[]}(n):function(n){return n.match(hn)||[]}(n):n.match(t)||[]}var na=Ye((function(n,t){try{return Rt(n,u,t)}catch(n){return Yo(n)?n:new kn(n)}})),ta=ei((function(n,t){return Et(t,(function(t){t=Bi(t),oe(n,t,Eo(n[t],n))})),n}));function ra(n){return function(){return n}}var ea=Fu(),ua=Fu(!0);function ia(n){return n}function oa(n){return Ue("function"==typeof n?n:ce(n,1))}var fa=Ye((function(n,t){return function(r){return Se(r,n,t)}})),aa=Ye((function(n,t){return function(r){return Se(n,r,t)}}));function ca(n,t,r){var e=Lf(t),u=je(t,e);null!=r||tf(t)&&(u.length||!e.length)||(r=t,t=n,n=this,u=je(t,Lf(t)));var i=!(tf(r)&&"chain"in r&&!r.chain),o=Qo(n);return Et(u,(function(r){var e=t[r];n[r]=e,o&&(n.prototype[r]=function(){var t=this.__chain__;if(i||t){var r=n(this.__wrapped__);return(r.__actions__=Eu(this.__actions__)).push({func:e,args:arguments,thisArg:n}),r.__chain__=t,r}return e.apply(n,Bt([this.value()],arguments))})})),n}function la(){}var sa=qu(Ut),ha=qu(Wt),pa=qu(Ft);function va(n){return mi(n)?Gt(Bi(n)):function(n){return function(t){return Ae(t,n)}}(n)}var _a=Ku(),ga=Ku(!0);function ya(){return[]}function da(){return!1}var ba=Pu((function(n,t){return n+t}),0),wa=Hu("ceil"),ma=Pu((function(n,t){return n/t}),1),xa=Hu("floor");var ja,Aa=Pu((function(n,t){return n*t}),1),ka=Hu("round"),Ia=Pu((function(n,t){return n-t}),0);return Mr.after=function(n,t){if("function"!=typeof t)throw new Sn(i);return n=gf(n),function(){if(--n<1)return t.apply(this,arguments)}},Mr.ary=Ro,Mr.assign=mf,Mr.assignIn=xf,Mr.assignInWith=jf,Mr.assignWith=Af,Mr.at=kf,Mr.before=zo,Mr.bind=Eo,Mr.bindAll=ta,Mr.bindKey=So,Mr.castArray=function(){if(!arguments.length)return[];var n=arguments[0];return Zo(n)?n:[n]},Mr.chain=ho,Mr.chunk=function(n,t,r){t=(r?wi(n,t,r):t===u)?1:br(gf(t),0);var i=null==n?0:n.length;if(!i||t<1)return[];for(var o=0,f=0,a=e(_t(i/t));oi?0:i+r),(e=e===u||e>i?i:gf(e))<0&&(e+=i),e=r>e?0:yf(e);r>>0)?(n=wf(n))&&("string"==typeof t||null!=t&&!ff(t))&&!(t=lu(t))&&ar(n)?xu(_r(n),0,r):n.split(t,r):[]},Mr.spread=function(n,t){if("function"!=typeof n)throw new Sn(i);return t=null==t?0:br(gf(t),0),Ye((function(r){var e=r[t],u=xu(r,0,t);return e&&Bt(u,e),Rt(n,this,u)}))},Mr.tail=function(n){var t=null==n?0:n.length;return t?uu(n,1,t):[]},Mr.take=function(n,t,r){return n&&n.length?uu(n,0,(t=r||t===u?1:gf(t))<0?0:t):[]},Mr.takeRight=function(n,t,r){var e=null==n?0:n.length;return e?uu(n,(t=e-(t=r||t===u?1:gf(t)))<0?0:t,e):[]},Mr.takeRightWhile=function(n,t){return n&&n.length?vu(n,ci(t,3),!1,!0):[]},Mr.takeWhile=function(n,t){return n&&n.length?vu(n,ci(t,3)):[]},Mr.tap=function(n,t){return t(n),n},Mr.throttle=function(n,t,r){var e=!0,u=!0;if("function"!=typeof n)throw new Sn(i);return tf(r)&&(e="leading"in r?!!r.leading:e,u="trailing"in r?!!r.trailing:u),Wo(n,t,{leading:e,maxWait:t,trailing:u})},Mr.thru=po,Mr.toArray=vf,Mr.toPairs=Ff,Mr.toPairsIn=Mf,Mr.toPath=function(n){return Zo(n)?Ut(n,Bi):lf(n)?[n]:Eu(Ui(wf(n)))},Mr.toPlainObject=bf,Mr.transform=function(n,t,r){var e=Zo(n),u=e||Ho(n)||sf(n);if(t=ci(t,4),null==r){var i=n&&n.constructor;r=u?e?new i:[]:tf(n)&&Qo(i)?Nr(Gn(n)):{}}return(u?Et:me)(n,(function(n,e,u){return t(r,n,e,u)})),r},Mr.unary=function(n){return Ro(n,1)},Mr.union=to,Mr.unionBy=ro,Mr.unionWith=eo,Mr.uniq=function(n){return n&&n.length?su(n):[]},Mr.uniqBy=function(n,t){return n&&n.length?su(n,ci(t,2)):[]},Mr.uniqWith=function(n,t){return t="function"==typeof t?t:u,n&&n.length?su(n,u,t):[]},Mr.unset=function(n,t){return null==n||hu(n,t)},Mr.unzip=uo,Mr.unzipWith=io,Mr.update=function(n,t,r){return null==n?n:pu(n,t,bu(r))},Mr.updateWith=function(n,t,r,e){return e="function"==typeof e?e:u,null==n?n:pu(n,t,bu(r),e)},Mr.values=Nf,Mr.valuesIn=function(n){return null==n?[]:tr(n,Cf(n))},Mr.without=oo,Mr.words=Xf,Mr.wrap=function(n,t){return $o(bu(t),n)},Mr.xor=fo,Mr.xorBy=ao,Mr.xorWith=co,Mr.zip=lo,Mr.zipObject=function(n,t){return yu(n||[],t||[],re)},Mr.zipObjectDeep=function(n,t){return yu(n||[],t||[],nu)},Mr.zipWith=so,Mr.entries=Ff,Mr.entriesIn=Mf,Mr.extend=xf,Mr.extendWith=jf,ca(Mr,Mr),Mr.add=ba,Mr.attempt=na,Mr.camelCase=Pf,Mr.capitalize=qf,Mr.ceil=wa,Mr.clamp=function(n,t,r){return r===u&&(r=t,t=u),r!==u&&(r=(r=df(r))==r?r:0),t!==u&&(t=(t=df(t))==t?t:0),ae(df(n),t,r)},Mr.clone=function(n){return ce(n,4)},Mr.cloneDeep=function(n){return ce(n,5)},Mr.cloneDeepWith=function(n,t){return ce(n,5,t="function"==typeof t?t:u)},Mr.cloneWith=function(n,t){return ce(n,4,t="function"==typeof t?t:u)},Mr.conformsTo=function(n,t){return null==t||le(n,t,Lf(t))},Mr.deburr=Zf,Mr.defaultTo=function(n,t){return null==n||n!=n?t:n},Mr.divide=ma,Mr.endsWith=function(n,t,r){n=wf(n),t=lu(t);var e=n.length,i=r=r===u?e:ae(gf(r),0,e);return(r-=t.length)>=0&&n.slice(r,i)==t},Mr.eq=Mo,Mr.escape=function(n){return(n=wf(n))&&Y.test(n)?n.replace(H,or):n},Mr.escapeRegExp=function(n){return(n=wf(n))&&on.test(n)?n.replace(un,"\\$&"):n},Mr.every=function(n,t,r){var e=Zo(n)?Wt:_e;return r&&wi(n,t,r)&&(t=u),e(n,ci(t,3))},Mr.find=go,Mr.findIndex=Pi,Mr.findKey=function(n,t){return Nt(n,ci(t,3),me)},Mr.findLast=yo,Mr.findLastIndex=qi,Mr.findLastKey=function(n,t){return Nt(n,ci(t,3),xe)},Mr.floor=xa,Mr.forEach=bo,Mr.forEachRight=wo,Mr.forIn=function(n,t){return null==n?n:be(n,ci(t,3),Cf)},Mr.forInRight=function(n,t){return null==n?n:we(n,ci(t,3),Cf)},Mr.forOwn=function(n,t){return n&&me(n,ci(t,3))},Mr.forOwnRight=function(n,t){return n&&xe(n,ci(t,3))},Mr.get=Rf,Mr.gt=No,Mr.gte=Po,Mr.has=function(n,t){return null!=n&&gi(n,t,Re)},Mr.hasIn=zf,Mr.head=Ki,Mr.identity=ia,Mr.includes=function(n,t,r,e){n=Vo(n)?n:Nf(n),r=r&&!e?gf(r):0;var u=n.length;return r<0&&(r=br(u+r,0)),cf(n)?r<=u&&n.indexOf(t,r)>-1:!!u&&qt(n,t,r)>-1},Mr.indexOf=function(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=null==r?0:gf(r);return u<0&&(u=br(e+u,0)),qt(n,t,u)},Mr.inRange=function(n,t,r){return t=_f(t),r===u?(r=t,t=0):r=_f(r),function(n,t,r){return n>=wr(t,r)&&n=-9007199254740991&&n<=v},Mr.isSet=af,Mr.isString=cf,Mr.isSymbol=lf,Mr.isTypedArray=sf,Mr.isUndefined=function(n){return n===u},Mr.isWeakMap=function(n){return rf(n)&&_i(n)==L},Mr.isWeakSet=function(n){return rf(n)&&"[object WeakSet]"==Ie(n)},Mr.join=function(n,t){return null==n?"":Mt.call(n,t)},Mr.kebabCase=Kf,Mr.last=Ji,Mr.lastIndexOf=function(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var i=e;return r!==u&&(i=(i=gf(r))<0?br(e+i,0):wr(i,e-1)),t==t?function(n,t,r){for(var e=r+1;e--;)if(n[e]===t)return e;return e}(n,t,i):Pt(n,Kt,i,!0)},Mr.lowerCase=Vf,Mr.lowerFirst=Gf,Mr.lt=hf,Mr.lte=pf,Mr.max=function(n){return n&&n.length?ge(n,ia,Oe):u},Mr.maxBy=function(n,t){return n&&n.length?ge(n,ci(t,2),Oe):u},Mr.mean=function(n){return Vt(n,ia)},Mr.meanBy=function(n,t){return Vt(n,ci(t,2))},Mr.min=function(n){return n&&n.length?ge(n,ia,De):u},Mr.minBy=function(n,t){return n&&n.length?ge(n,ci(t,2),De):u},Mr.stubArray=ya,Mr.stubFalse=da,Mr.stubObject=function(){return{}},Mr.stubString=function(){return""},Mr.stubTrue=function(){return!0},Mr.multiply=Aa,Mr.nth=function(n,t){return n&&n.length?qe(n,gf(t)):u},Mr.noConflict=function(){return gt._===this&&(gt._=Nn),this},Mr.noop=la,Mr.now=Oo,Mr.pad=function(n,t,r){n=wf(n);var e=(t=gf(t))?vr(n):0;if(!t||e>=t)return n;var u=(t-e)/2;return Zu(yt(u),r)+n+Zu(_t(u),r)},Mr.padEnd=function(n,t,r){n=wf(n);var e=(t=gf(t))?vr(n):0;return t&&et){var e=n;n=t,t=e}if(r||n%1||t%1){var i=jr();return wr(n+i*(t-n+ht("1e-"+((i+"").length-1))),t)}return He(n,t)},Mr.reduce=function(n,t,r){var e=Zo(n)?$t:Jt,u=arguments.length<3;return e(n,ci(t,4),r,u,pe)},Mr.reduceRight=function(n,t,r){var e=Zo(n)?Dt:Jt,u=arguments.length<3;return e(n,ci(t,4),r,u,ve)},Mr.repeat=function(n,t,r){return t=(r?wi(n,t,r):t===u)?1:gf(t),Je(wf(n),t)},Mr.replace=function(){var n=arguments,t=wf(n[0]);return n.length<3?t:t.replace(n[1],n[2])},Mr.result=function(n,t,r){var e=-1,i=(t=wu(t,n)).length;for(i||(i=1,n=u);++ev)return[];var r=g,e=wr(n,g);t=ci(t),n-=g;for(var u=Qt(e,t);++r=o)return n;var a=r-vr(e);if(a<1)return e;var c=f?xu(f,0,a).join(""):n.slice(0,a);if(i===u)return c+e;if(f&&(a+=c.length-a),ff(i)){if(n.slice(a).search(i)){var l,s=c;for(i.global||(i=zn(i.source,wf(gn.exec(i))+"g")),i.lastIndex=0;l=i.exec(s);)var h=l.index;c=c.slice(0,h===u?a:h)}}else if(n.indexOf(lu(i),a)!=a){var p=c.lastIndexOf(i);p>-1&&(c=c.slice(0,p))}return c+e},Mr.unescape=function(n){return(n=wf(n))&&J.test(n)?n.replace(G,yr):n},Mr.uniqueId=function(n){var t=++$n;return wf(n)+t},Mr.upperCase=Yf,Mr.upperFirst=Qf,Mr.each=bo,Mr.eachRight=wo,Mr.first=Ki,ca(Mr,(ja={},me(Mr,(function(n,t){Bn.call(Mr.prototype,t)||(ja[t]=n)})),ja),{chain:!1}),Mr.VERSION="4.18.1",Et(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(n){Mr[n].placeholder=Mr})),Et(["drop","take"],(function(n,t){Zr.prototype[n]=function(r){r=r===u?1:br(gf(r),0);var e=this.__filtered__&&!t?new Zr(this):this.clone();return e.__filtered__?e.__takeCount__=wr(r,e.__takeCount__):e.__views__.push({size:wr(r,g),type:n+(e.__dir__<0?"Right":"")}),e},Zr.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}})),Et(["filter","map","takeWhile"],(function(n,t){var r=t+1,e=1==r||3==r;Zr.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:ci(n,3),type:r}),t.__filtered__=t.__filtered__||e,t}})),Et(["head","last"],(function(n,t){var r="take"+(t?"Right":"");Zr.prototype[n]=function(){return this[r](1).value()[0]}})),Et(["initial","tail"],(function(n,t){var r="drop"+(t?"":"Right");Zr.prototype[n]=function(){return this.__filtered__?new Zr(this):this[r](1)}})),Zr.prototype.compact=function(){return this.filter(ia)},Zr.prototype.find=function(n){return this.filter(n).head()},Zr.prototype.findLast=function(n){return this.reverse().find(n)},Zr.prototype.invokeMap=Ye((function(n,t){return"function"==typeof n?new Zr(this):this.map((function(r){return Se(r,n,t)}))})),Zr.prototype.reject=function(n){return this.filter(Uo(ci(n)))},Zr.prototype.slice=function(n,t){n=gf(n);var r=this;return r.__filtered__&&(n>0||t<0)?new Zr(r):(n<0?r=r.takeRight(-n):n&&(r=r.drop(n)),t!==u&&(r=(t=gf(t))<0?r.dropRight(-t):r.take(t-n)),r)},Zr.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},Zr.prototype.toArray=function(){return this.take(g)},me(Zr.prototype,(function(n,t){var r=/^(?:filter|find|map|reject)|While$/.test(t),e=/^(?:head|last)$/.test(t),i=Mr[e?"take"+("last"==t?"Right":""):t],o=e||/^find/.test(t);i&&(Mr.prototype[t]=function(){var t=this.__wrapped__,f=e?[1]:arguments,a=t instanceof Zr,c=f[0],l=a||Zo(t),s=function(n){var t=i.apply(Mr,Bt([n],f));return e&&h?t[0]:t};l&&r&&"function"==typeof c&&1!=c.length&&(a=l=!1);var h=this.__chain__,p=!!this.__actions__.length,v=o&&!h,_=a&&!p;if(!o&&l){t=_?t:new Zr(this);var g=n.apply(t,f);return g.__actions__.push({func:po,args:[s],thisArg:u}),new qr(g,h)}return v&&_?n.apply(this,f):(g=this.thru(s),v?e?g.value()[0]:g.value():g)})})),Et(["pop","push","shift","sort","splice","unshift"],(function(n){var t=Wn[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:pop|shift)$/.test(n);Mr.prototype[n]=function(){var n=arguments;if(e&&!this.__chain__){var u=this.value();return t.apply(Zo(u)?u:[],n)}return this[r]((function(r){return t.apply(Zo(r)?r:[],n)}))}})),me(Zr.prototype,(function(n,t){var r=Mr[t];if(r){var e=r.name+"";Bn.call(Wr,e)||(Wr[e]=[]),Wr[e].push({name:t,func:r})}})),Wr[Mu(u,2).name]=[{name:"wrapper",func:u}],Zr.prototype.clone=function(){var n=new Zr(this.__wrapped__);return n.__actions__=Eu(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=Eu(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=Eu(this.__views__),n},Zr.prototype.reverse=function(){if(this.__filtered__){var n=new Zr(this);n.__dir__=-1,n.__filtered__=!0}else(n=this.clone()).__dir__*=-1;return n},Zr.prototype.value=function(){var n=this.__wrapped__.value(),t=this.__dir__,r=Zo(n),e=t<0,u=r?n.length:0,i=function(n,t,r){var e=-1,u=r.length;for(;++e=this.__values__.length;return{done:n,value:n?u:this.__values__[this.__index__++]}},Mr.prototype.plant=function(n){for(var t,r=this;r instanceof Pr;){var e=Di(r);e.__index__=0,e.__values__=u,t?i.__wrapped__=e:t=e;var i=e;r=r.__wrapped__}return i.__wrapped__=n,t},Mr.prototype.reverse=function(){var n=this.__wrapped__;if(n instanceof Zr){var t=n;return this.__actions__.length&&(t=new Zr(this)),(t=t.reverse()).__actions__.push({func:po,args:[no],thisArg:u}),new qr(t,this.__chain__)}return this.thru(no)},Mr.prototype.toJSON=Mr.prototype.valueOf=Mr.prototype.value=function(){return _u(this.__wrapped__,this.__actions__)},Mr.prototype.first=Mr.prototype.head,Xn&&(Mr.prototype[Xn]=function(){return this}),Mr}();gt._=dr,(e=function(){return dr}.call(t,r,t,n))===u||(n.exports=e)}.call(this)},7803(n,t,r){n.exports=r(2543)}},t={};function r(e){var u=t[e];if(void 0!==u)return u.exports;var i=t[e]={id:e,loaded:!1,exports:{}};return n[e].call(i.exports,i,i.exports,r),i.loaded=!0,i.exports}return r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(n){if("object"==typeof window)return window}}(),r.nmd=n=>(n.paths=[],n.children||(n.children=[]),n),r(7803)})())); \ No newline at end of file diff --git a/src/modules/Elsa.Expressions.JavaScript.Libraries/ClientLib/dist/lodashFp.js b/src/modules/Elsa.Expressions.JavaScript.Libraries/ClientLib/dist/lodashFp.js index 0fe5ac372..241bf33f6 100644 --- a/src/modules/Elsa.Expressions.JavaScript.Libraries/ClientLib/dist/lodashFp.js +++ b/src/modules/Elsa.Expressions.JavaScript.Libraries/ClientLib/dist/lodashFp.js @@ -1,9 +1,5 @@ -!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.lodashFp=t():n.lodashFp=t()}(this,(()=>(()=>{var n={4480:(n,t,r)=>{var e=r(9761).runInContext();n.exports=r(3424)(e,e)},3424:(n,t,r)=>{var e=r(6962),u=r(2874),i=Array.prototype.push;function o(n,t){return 2==t?function(t,r){return n(t,r)}:function(t){return n(t)}}function a(n){for(var t=n?n.length:0,r=Array(t);t--;)r[t]=n[t];return r}function f(n,t){return function(){var r=arguments.length;if(r){for(var e=Array(r);r--;)e[r]=arguments[r];var u=e[0]=t.apply(void 0,e);return n.apply(void 0,e),u}}}n.exports=function n(t,r,c,l){var s="function"==typeof r,h=r===Object(r);if(h&&(l=c,c=r,r=void 0),null==c)throw new TypeError;l||(l={});var p=!("cap"in l)||l.cap,v=!("curry"in l)||l.curry,g=!("fixed"in l)||l.fixed,_=!("immutable"in l)||l.immutable,d=!("rearg"in l)||l.rearg,y=s?c:u,m="curry"in l&&l.curry,b="fixed"in l&&l.fixed,w="rearg"in l&&l.rearg,x=s?c.runInContext():void 0,A=s?c:{ary:t.ary,assign:t.assign,clone:t.clone,curry:t.curry,forEach:t.forEach,isArray:t.isArray,isError:t.isError,isFunction:t.isFunction,isWeakMap:t.isWeakMap,iteratee:t.iteratee,keys:t.keys,rearg:t.rearg,toInteger:t.toInteger,toPath:t.toPath},I=A.ary,W=A.assign,j=A.clone,R=A.curry,k=A.forEach,O=A.isArray,E=A.isError,S=A.isFunction,z=A.isWeakMap,B=A.keys,L=A.rearg,C=A.toInteger,F=A.toPath,T=B(e.aryMethod),D={castArray:function(n){return function(){var t=arguments[0];return O(t)?n(a(t)):n.apply(void 0,arguments)}},iteratee:function(n){return function(){var t=arguments[1],r=n(arguments[0],t),e=r.length;return p&&"number"==typeof t?(t=t>2?t-2:1,e&&e<=t?r:o(r,t)):r}},mixin:function(n){return function(t){var r=this;if(!S(r))return n(r,Object(t));var e=[];return k(B(t),(function(n){S(t[n])&&e.push([n,r.prototype[n]])})),n(r,Object(t)),k(e,(function(n){var t=n[1];S(t)?r.prototype[n[0]]=t:delete r.prototype[n[0]]})),r}},nthArg:function(n){return function(t){var r=t<0?1:C(t)+1;return R(n(t),r)}},rearg:function(n){return function(t,r){var e=r?r.length:0;return R(n(t,r),e)}},runInContext:function(r){return function(e){return n(t,r(e),l)}}};function M(n,t){if(p){var r=e.iterateeRearg[n];if(r)return function(n,t){return N(n,(function(n){var r=t.length;return function(n,t){return 2==t?function(t,r){return n.apply(void 0,arguments)}:function(t){return n.apply(void 0,arguments)}}(L(o(n,r),t),r)}))}(t,r);var u=!s&&e.iterateeAry[n];if(u)return function(n,t){return N(n,(function(n){return"function"==typeof n?o(n,t):n}))}(t,u)}return t}function U(n,t,r){if(g&&(b||!e.skipFixed[n])){var u=e.methodSpread[n],o=u&&u.start;return void 0===o?I(t,r):function(n,t){return function(){for(var r=arguments.length,e=r-1,u=Array(r);r--;)u[r]=arguments[r];var o=u[t],a=u.slice(0,t);return o&&i.apply(a,o),t!=e&&i.apply(a,u.slice(t+1)),n.apply(this,a)}}(t,o)}return t}function P(n,t,r){return d&&r>1&&(w||!e.skipRearg[n])?L(t,e.methodRearg[n]||e.aryRearg[r]):t}function q(n,t){for(var r=-1,e=(t=F(t)).length,u=e-1,i=j(Object(n)),o=i;null!=o&&++r1?R(t,r):t}(0,u=M(i,u),n),!1}})),!u})),u||(u=o),u==t&&(u=m?R(u,1):function(){return t.apply(this,arguments)}),u.convert=$(i,t),u.placeholder=t.placeholder=r,u}if(!h)return K(r,c,y);var Z=c,V=[];return k(T,(function(n){k(e.aryMethod[n],(function(n){var t=Z[e.remap[n]||n];t&&V.push([n,K(n,t,Z)])}))})),k(B(Z),(function(n){var t=Z[n];if("function"==typeof t){for(var r=V.length;r--;)if(V[r][0]==n)return;t.convert=$(n,t),V.push([n,t])}})),k(V,(function(n){Z[n[0]]=n[1]})),Z.convert=function(n){return Z.runInContext.convert(n)(void 0)},Z.placeholder=Z,k(B(Z),(function(n){k(e.realToAlias[n]||[],(function(t){Z[t]=Z[n]}))})),Z}},6962:(n,t)=>{t.aliasToReal={each:"forEach",eachRight:"forEachRight",entries:"toPairs",entriesIn:"toPairsIn",extend:"assignIn",extendAll:"assignInAll",extendAllWith:"assignInAllWith",extendWith:"assignInWith",first:"head",conforms:"conformsTo",matches:"isMatch",property:"get",__:"placeholder",F:"stubFalse",T:"stubTrue",all:"every",allPass:"overEvery",always:"constant",any:"some",anyPass:"overSome",apply:"spread",assoc:"set",assocPath:"set",complement:"negate",compose:"flowRight",contains:"includes",dissoc:"unset",dissocPath:"unset",dropLast:"dropRight",dropLastWhile:"dropRightWhile",equals:"isEqual",identical:"eq",indexBy:"keyBy",init:"initial",invertObj:"invert",juxt:"over",omitAll:"omit",nAry:"ary",path:"get",pathEq:"matchesProperty",pathOr:"getOr",paths:"at",pickAll:"pick",pipe:"flow",pluck:"map",prop:"get",propEq:"matchesProperty",propOr:"getOr",props:"at",symmetricDifference:"xor",symmetricDifferenceBy:"xorBy",symmetricDifferenceWith:"xorWith",takeLast:"takeRight",takeLastWhile:"takeRightWhile",unapply:"rest",unnest:"flatten",useWith:"overArgs",where:"conformsTo",whereEq:"isMatch",zipObj:"zipObject"},t.aryMethod={1:["assignAll","assignInAll","attempt","castArray","ceil","create","curry","curryRight","defaultsAll","defaultsDeepAll","floor","flow","flowRight","fromPairs","invert","iteratee","memoize","method","mergeAll","methodOf","mixin","nthArg","over","overEvery","overSome","rest","reverse","round","runInContext","spread","template","trim","trimEnd","trimStart","uniqueId","words","zipAll"],2:["add","after","ary","assign","assignAllWith","assignIn","assignInAllWith","at","before","bind","bindAll","bindKey","chunk","cloneDeepWith","cloneWith","concat","conformsTo","countBy","curryN","curryRightN","debounce","defaults","defaultsDeep","defaultTo","delay","difference","divide","drop","dropRight","dropRightWhile","dropWhile","endsWith","eq","every","filter","find","findIndex","findKey","findLast","findLastIndex","findLastKey","flatMap","flatMapDeep","flattenDepth","forEach","forEachRight","forIn","forInRight","forOwn","forOwnRight","get","groupBy","gt","gte","has","hasIn","includes","indexOf","intersection","invertBy","invoke","invokeMap","isEqual","isMatch","join","keyBy","lastIndexOf","lt","lte","map","mapKeys","mapValues","matchesProperty","maxBy","meanBy","merge","mergeAllWith","minBy","multiply","nth","omit","omitBy","overArgs","pad","padEnd","padStart","parseInt","partial","partialRight","partition","pick","pickBy","propertyOf","pull","pullAll","pullAt","random","range","rangeRight","rearg","reject","remove","repeat","restFrom","result","sampleSize","some","sortBy","sortedIndex","sortedIndexOf","sortedLastIndex","sortedLastIndexOf","sortedUniqBy","split","spreadFrom","startsWith","subtract","sumBy","take","takeRight","takeRightWhile","takeWhile","tap","throttle","thru","times","trimChars","trimCharsEnd","trimCharsStart","truncate","union","uniqBy","uniqWith","unset","unzipWith","without","wrap","xor","zip","zipObject","zipObjectDeep"],3:["assignInWith","assignWith","clamp","differenceBy","differenceWith","findFrom","findIndexFrom","findLastFrom","findLastIndexFrom","getOr","includesFrom","indexOfFrom","inRange","intersectionBy","intersectionWith","invokeArgs","invokeArgsMap","isEqualWith","isMatchWith","flatMapDepth","lastIndexOfFrom","mergeWith","orderBy","padChars","padCharsEnd","padCharsStart","pullAllBy","pullAllWith","rangeStep","rangeStepRight","reduce","reduceRight","replace","set","slice","sortedIndexBy","sortedLastIndexBy","transform","unionBy","unionWith","update","xorBy","xorWith","zipWith"],4:["fill","setWith","updateWith"]},t.aryRearg={2:[1,0],3:[2,0,1],4:[3,2,0,1]},t.iterateeAry={dropRightWhile:1,dropWhile:1,every:1,filter:1,find:1,findFrom:1,findIndex:1,findIndexFrom:1,findKey:1,findLast:1,findLastFrom:1,findLastIndex:1,findLastIndexFrom:1,findLastKey:1,flatMap:1,flatMapDeep:1,flatMapDepth:1,forEach:1,forEachRight:1,forIn:1,forInRight:1,forOwn:1,forOwnRight:1,map:1,mapKeys:1,mapValues:1,partition:1,reduce:2,reduceRight:2,reject:1,remove:1,some:1,takeRightWhile:1,takeWhile:1,times:1,transform:2},t.iterateeRearg={mapKeys:[1],reduceRight:[1,0]},t.methodRearg={assignInAllWith:[1,0],assignInWith:[1,2,0],assignAllWith:[1,0],assignWith:[1,2,0],differenceBy:[1,2,0],differenceWith:[1,2,0],getOr:[2,1,0],intersectionBy:[1,2,0],intersectionWith:[1,2,0],isEqualWith:[1,2,0],isMatchWith:[2,1,0],mergeAllWith:[1,0],mergeWith:[1,2,0],padChars:[2,1,0],padCharsEnd:[2,1,0],padCharsStart:[2,1,0],pullAllBy:[2,1,0],pullAllWith:[2,1,0],rangeStep:[1,2,0],rangeStepRight:[1,2,0],setWith:[3,1,2,0],sortedIndexBy:[2,1,0],sortedLastIndexBy:[2,1,0],unionBy:[1,2,0],unionWith:[1,2,0],updateWith:[3,1,2,0],xorBy:[1,2,0],xorWith:[1,2,0],zipWith:[1,2,0]},t.methodSpread={assignAll:{start:0},assignAllWith:{start:0},assignInAll:{start:0},assignInAllWith:{start:0},defaultsAll:{start:0},defaultsDeepAll:{start:0},invokeArgs:{start:2},invokeArgsMap:{start:2},mergeAll:{start:0},mergeAllWith:{start:0},partial:{start:1},partialRight:{start:1},without:{start:1},zipAll:{start:0}},t.mutate={array:{fill:!0,pull:!0,pullAll:!0,pullAllBy:!0,pullAllWith:!0,pullAt:!0,remove:!0,reverse:!0},object:{assign:!0,assignAll:!0,assignAllWith:!0,assignIn:!0,assignInAll:!0,assignInAllWith:!0,assignInWith:!0,assignWith:!0,defaults:!0,defaultsAll:!0,defaultsDeep:!0,defaultsDeepAll:!0,merge:!0,mergeAll:!0,mergeAllWith:!0,mergeWith:!0},set:{set:!0,setWith:!0,unset:!0,update:!0,updateWith:!0}},t.realToAlias=function(){var n=Object.prototype.hasOwnProperty,r=t.aliasToReal,e={};for(var u in r){var i=r[u];n.call(e,i)?e[i].push(u):e[i]=[u]}return e}(),t.remap={assignAll:"assign",assignAllWith:"assignWith",assignInAll:"assignIn",assignInAllWith:"assignInWith",curryN:"curry",curryRightN:"curryRight",defaultsAll:"defaults",defaultsDeepAll:"defaultsDeep",findFrom:"find",findIndexFrom:"findIndex",findLastFrom:"findLast",findLastIndexFrom:"findLastIndex",getOr:"get",includesFrom:"includes",indexOfFrom:"indexOf",invokeArgs:"invoke",invokeArgsMap:"invokeMap",lastIndexOfFrom:"lastIndexOf",mergeAll:"merge",mergeAllWith:"mergeWith",padChars:"pad",padCharsEnd:"padEnd",padCharsStart:"padStart",propertyOf:"get",rangeStep:"range",rangeStepRight:"rangeRight",restFrom:"rest",spreadFrom:"spread",trimChars:"trim",trimCharsEnd:"trimEnd",trimCharsStart:"trimStart",zipAll:"zip"},t.skipFixed={castArray:!0,flow:!0,flowRight:!0,iteratee:!0,mixin:!0,rearg:!0,runInContext:!0},t.skipRearg={add:!0,assign:!0,assignIn:!0,bind:!0,bindKey:!0,concat:!0,difference:!0,divide:!0,eq:!0,gt:!0,gte:!0,isEqual:!0,lt:!0,lte:!0,matchesProperty:!0,merge:!0,multiply:!0,overArgs:!0,partial:!0,partialRight:!0,propertyOf:!0,random:!0,range:!0,rangeRight:!0,subtract:!0,zip:!0,zipObject:!0,zipObjectDeep:!0}},2874:n=>{n.exports={}},9761:function(n,t,r){var e; +!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.lodashFp=t():n.lodashFp=t()}(this,(()=>(()=>{var n={4480(n,t,r){var e=r(9761).runInContext();n.exports=r(3424)(e,e)},3424(n,t,r){var e=r(6962),u=r(2874),i=Array.prototype.push;function o(n,t){return 2==t?function(t,r){return n(t,r)}:function(t){return n(t)}}function a(n){for(var t=n?n.length:0,r=Array(t);t--;)r[t]=n[t];return r}function f(n,t){return function(){var r=arguments.length;if(r){for(var e=Array(r);r--;)e[r]=arguments[r];var u=e[0]=t.apply(void 0,e);return n.apply(void 0,e),u}}}n.exports=function n(t,r,c,l){var s="function"==typeof r,h=r===Object(r);if(h&&(l=c,c=r,r=void 0),null==c)throw new TypeError;l||(l={});var p=!("cap"in l)||l.cap,v=!("curry"in l)||l.curry,g=!("fixed"in l)||l.fixed,_=!("immutable"in l)||l.immutable,d=!("rearg"in l)||l.rearg,y=s?c:u,m="curry"in l&&l.curry,b="fixed"in l&&l.fixed,w="rearg"in l&&l.rearg,x=s?c.runInContext():void 0,A=s?c:{ary:t.ary,assign:t.assign,clone:t.clone,curry:t.curry,forEach:t.forEach,isArray:t.isArray,isError:t.isError,isFunction:t.isFunction,isWeakMap:t.isWeakMap,iteratee:t.iteratee,keys:t.keys,rearg:t.rearg,toInteger:t.toInteger,toPath:t.toPath},I=A.ary,W=A.assign,j=A.clone,R=A.curry,k=A.forEach,O=A.isArray,E=A.isError,z=A.isFunction,S=A.isWeakMap,B=A.keys,L=A.rearg,C=A.toInteger,F=A.toPath,T=B(e.aryMethod),D={castArray:function(n){return function(){var t=arguments[0];return O(t)?n(a(t)):n.apply(void 0,arguments)}},iteratee:function(n){return function(){var t=arguments[1],r=n(arguments[0],t),e=r.length;return p&&"number"==typeof t?(t=t>2?t-2:1,e&&e<=t?r:o(r,t)):r}},mixin:function(n){return function(t){var r=this;if(!z(r))return n(r,Object(t));var e=[];return k(B(t),(function(n){z(t[n])&&e.push([n,r.prototype[n]])})),n(r,Object(t)),k(e,(function(n){var t=n[1];z(t)?r.prototype[n[0]]=t:delete r.prototype[n[0]]})),r}},nthArg:function(n){return function(t){var r=t<0?1:C(t)+1;return R(n(t),r)}},rearg:function(n){return function(t,r){var e=r?r.length:0;return R(n(t,r),e)}},runInContext:function(r){return function(e){return n(t,r(e),l)}}};function M(n,t){if(p){var r=e.iterateeRearg[n];if(r)return function(n,t){return N(n,(function(n){var r=t.length;return function(n,t){return 2==t?function(t,r){return n.apply(void 0,arguments)}:function(t){return n.apply(void 0,arguments)}}(L(o(n,r),t),r)}))}(t,r);var u=!s&&e.iterateeAry[n];if(u)return function(n,t){return N(n,(function(n){return"function"==typeof n?o(n,t):n}))}(t,u)}return t}function U(n,t,r){if(g&&(b||!e.skipFixed[n])){var u=e.methodSpread[n],o=u&&u.start;return void 0===o?I(t,r):function(n,t){return function(){for(var r=arguments.length,e=r-1,u=Array(r);r--;)u[r]=arguments[r];var o=u[t],a=u.slice(0,t);return o&&i.apply(a,o),t!=e&&i.apply(a,u.slice(t+1)),n.apply(this,a)}}(t,o)}return t}function P(n,t,r){return d&&r>1&&(w||!e.skipRearg[n])?L(t,e.methodRearg[n]||e.aryRearg[r]):t}function q(n,t){for(var r=-1,e=(t=F(t)).length,u=e-1,i=j(Object(n)),o=i;null!=o&&++r1?R(t,r):t}(0,u=M(i,u),n),!1}})),!u})),u||(u=o),u==t&&(u=m?R(u,1):function(){return t.apply(this,arguments)}),u.convert=$(i,t),u.placeholder=t.placeholder=r,u}if(!h)return K(r,c,y);var Z=c,V=[];return k(T,(function(n){k(e.aryMethod[n],(function(n){var t=Z[e.remap[n]||n];t&&V.push([n,K(n,t,Z)])}))})),k(B(Z),(function(n){var t=Z[n];if("function"==typeof t){for(var r=V.length;r--;)if(V[r][0]==n)return;t.convert=$(n,t),V.push([n,t])}})),k(V,(function(n){Z[n[0]]=n[1]})),Z.convert=function(n){return Z.runInContext.convert(n)(void 0)},Z.placeholder=Z,k(B(Z),(function(n){k(e.realToAlias[n]||[],(function(t){Z[t]=Z[n]}))})),Z}},6962(n,t){t.aliasToReal={each:"forEach",eachRight:"forEachRight",entries:"toPairs",entriesIn:"toPairsIn",extend:"assignIn",extendAll:"assignInAll",extendAllWith:"assignInAllWith",extendWith:"assignInWith",first:"head",conforms:"conformsTo",matches:"isMatch",property:"get",__:"placeholder",F:"stubFalse",T:"stubTrue",all:"every",allPass:"overEvery",always:"constant",any:"some",anyPass:"overSome",apply:"spread",assoc:"set",assocPath:"set",complement:"negate",compose:"flowRight",contains:"includes",dissoc:"unset",dissocPath:"unset",dropLast:"dropRight",dropLastWhile:"dropRightWhile",equals:"isEqual",identical:"eq",indexBy:"keyBy",init:"initial",invertObj:"invert",juxt:"over",omitAll:"omit",nAry:"ary",path:"get",pathEq:"matchesProperty",pathOr:"getOr",paths:"at",pickAll:"pick",pipe:"flow",pluck:"map",prop:"get",propEq:"matchesProperty",propOr:"getOr",props:"at",symmetricDifference:"xor",symmetricDifferenceBy:"xorBy",symmetricDifferenceWith:"xorWith",takeLast:"takeRight",takeLastWhile:"takeRightWhile",unapply:"rest",unnest:"flatten",useWith:"overArgs",where:"conformsTo",whereEq:"isMatch",zipObj:"zipObject"},t.aryMethod={1:["assignAll","assignInAll","attempt","castArray","ceil","create","curry","curryRight","defaultsAll","defaultsDeepAll","floor","flow","flowRight","fromPairs","invert","iteratee","memoize","method","mergeAll","methodOf","mixin","nthArg","over","overEvery","overSome","rest","reverse","round","runInContext","spread","template","trim","trimEnd","trimStart","uniqueId","words","zipAll"],2:["add","after","ary","assign","assignAllWith","assignIn","assignInAllWith","at","before","bind","bindAll","bindKey","chunk","cloneDeepWith","cloneWith","concat","conformsTo","countBy","curryN","curryRightN","debounce","defaults","defaultsDeep","defaultTo","delay","difference","divide","drop","dropRight","dropRightWhile","dropWhile","endsWith","eq","every","filter","find","findIndex","findKey","findLast","findLastIndex","findLastKey","flatMap","flatMapDeep","flattenDepth","forEach","forEachRight","forIn","forInRight","forOwn","forOwnRight","get","groupBy","gt","gte","has","hasIn","includes","indexOf","intersection","invertBy","invoke","invokeMap","isEqual","isMatch","join","keyBy","lastIndexOf","lt","lte","map","mapKeys","mapValues","matchesProperty","maxBy","meanBy","merge","mergeAllWith","minBy","multiply","nth","omit","omitBy","overArgs","pad","padEnd","padStart","parseInt","partial","partialRight","partition","pick","pickBy","propertyOf","pull","pullAll","pullAt","random","range","rangeRight","rearg","reject","remove","repeat","restFrom","result","sampleSize","some","sortBy","sortedIndex","sortedIndexOf","sortedLastIndex","sortedLastIndexOf","sortedUniqBy","split","spreadFrom","startsWith","subtract","sumBy","take","takeRight","takeRightWhile","takeWhile","tap","throttle","thru","times","trimChars","trimCharsEnd","trimCharsStart","truncate","union","uniqBy","uniqWith","unset","unzipWith","without","wrap","xor","zip","zipObject","zipObjectDeep"],3:["assignInWith","assignWith","clamp","differenceBy","differenceWith","findFrom","findIndexFrom","findLastFrom","findLastIndexFrom","getOr","includesFrom","indexOfFrom","inRange","intersectionBy","intersectionWith","invokeArgs","invokeArgsMap","isEqualWith","isMatchWith","flatMapDepth","lastIndexOfFrom","mergeWith","orderBy","padChars","padCharsEnd","padCharsStart","pullAllBy","pullAllWith","rangeStep","rangeStepRight","reduce","reduceRight","replace","set","slice","sortedIndexBy","sortedLastIndexBy","transform","unionBy","unionWith","update","xorBy","xorWith","zipWith"],4:["fill","setWith","updateWith"]},t.aryRearg={2:[1,0],3:[2,0,1],4:[3,2,0,1]},t.iterateeAry={dropRightWhile:1,dropWhile:1,every:1,filter:1,find:1,findFrom:1,findIndex:1,findIndexFrom:1,findKey:1,findLast:1,findLastFrom:1,findLastIndex:1,findLastIndexFrom:1,findLastKey:1,flatMap:1,flatMapDeep:1,flatMapDepth:1,forEach:1,forEachRight:1,forIn:1,forInRight:1,forOwn:1,forOwnRight:1,map:1,mapKeys:1,mapValues:1,partition:1,reduce:2,reduceRight:2,reject:1,remove:1,some:1,takeRightWhile:1,takeWhile:1,times:1,transform:2},t.iterateeRearg={mapKeys:[1],reduceRight:[1,0]},t.methodRearg={assignInAllWith:[1,0],assignInWith:[1,2,0],assignAllWith:[1,0],assignWith:[1,2,0],differenceBy:[1,2,0],differenceWith:[1,2,0],getOr:[2,1,0],intersectionBy:[1,2,0],intersectionWith:[1,2,0],isEqualWith:[1,2,0],isMatchWith:[2,1,0],mergeAllWith:[1,0],mergeWith:[1,2,0],padChars:[2,1,0],padCharsEnd:[2,1,0],padCharsStart:[2,1,0],pullAllBy:[2,1,0],pullAllWith:[2,1,0],rangeStep:[1,2,0],rangeStepRight:[1,2,0],setWith:[3,1,2,0],sortedIndexBy:[2,1,0],sortedLastIndexBy:[2,1,0],unionBy:[1,2,0],unionWith:[1,2,0],updateWith:[3,1,2,0],xorBy:[1,2,0],xorWith:[1,2,0],zipWith:[1,2,0]},t.methodSpread={assignAll:{start:0},assignAllWith:{start:0},assignInAll:{start:0},assignInAllWith:{start:0},defaultsAll:{start:0},defaultsDeepAll:{start:0},invokeArgs:{start:2},invokeArgsMap:{start:2},mergeAll:{start:0},mergeAllWith:{start:0},partial:{start:1},partialRight:{start:1},without:{start:1},zipAll:{start:0}},t.mutate={array:{fill:!0,pull:!0,pullAll:!0,pullAllBy:!0,pullAllWith:!0,pullAt:!0,remove:!0,reverse:!0},object:{assign:!0,assignAll:!0,assignAllWith:!0,assignIn:!0,assignInAll:!0,assignInAllWith:!0,assignInWith:!0,assignWith:!0,defaults:!0,defaultsAll:!0,defaultsDeep:!0,defaultsDeepAll:!0,merge:!0,mergeAll:!0,mergeAllWith:!0,mergeWith:!0},set:{set:!0,setWith:!0,unset:!0,update:!0,updateWith:!0}},t.realToAlias=function(){var n=Object.prototype.hasOwnProperty,r=t.aliasToReal,e={};for(var u in r){var i=r[u];n.call(e,i)?e[i].push(u):e[i]=[u]}return e}(),t.remap={assignAll:"assign",assignAllWith:"assignWith",assignInAll:"assignIn",assignInAllWith:"assignInWith",curryN:"curry",curryRightN:"curryRight",defaultsAll:"defaults",defaultsDeepAll:"defaultsDeep",findFrom:"find",findIndexFrom:"findIndex",findLastFrom:"findLast",findLastIndexFrom:"findLastIndex",getOr:"get",includesFrom:"includes",indexOfFrom:"indexOf",invokeArgs:"invoke",invokeArgsMap:"invokeMap",lastIndexOfFrom:"lastIndexOf",mergeAll:"merge",mergeAllWith:"mergeWith",padChars:"pad",padCharsEnd:"padEnd",padCharsStart:"padStart",propertyOf:"get",rangeStep:"range",rangeStepRight:"rangeRight",restFrom:"rest",spreadFrom:"spread",trimChars:"trim",trimCharsEnd:"trimEnd",trimCharsStart:"trimStart",zipAll:"zip"},t.skipFixed={castArray:!0,flow:!0,flowRight:!0,iteratee:!0,mixin:!0,rearg:!0,runInContext:!0},t.skipRearg={add:!0,assign:!0,assignIn:!0,bind:!0,bindKey:!0,concat:!0,difference:!0,divide:!0,eq:!0,gt:!0,gte:!0,isEqual:!0,lt:!0,lte:!0,matchesProperty:!0,merge:!0,multiply:!0,overArgs:!0,partial:!0,partialRight:!0,propertyOf:!0,random:!0,range:!0,rangeRight:!0,subtract:!0,zip:!0,zipObject:!0,zipObjectDeep:!0}},2874(n){n.exports={}},9761(n,t,r){var e; /** * @license - * Lodash - * Copyright OpenJS Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */n=r.nmd(n),function(){function u(n,t,r){switch(r.length){case 0:return n.call(t);case 1:return n.call(t,r[0]);case 2:return n.call(t,r[0],r[1]);case 3:return n.call(t,r[0],r[1],r[2])}return n.apply(t,r)}function i(n,t,r,e){for(var u=-1,i=null==n?0:n.length;++u-1}function s(n,t,r){for(var e=-1,u=null==n?0:n.length;++e-1;);return r}function L(n,t){for(var r=n.length;r--&&b(t,n[r],0)>-1;);return r}function C(n){return"\\"+tr[n]}function F(n){return Ht.test(n)}function T(n){return Jt.test(n)}function D(n){var t=-1,r=Array(n.size);return n.forEach((function(n,e){r[++t]=[e,n]})),r}function M(n,t){return function(r){return n(t(r))}}function U(n,t){for(var r=-1,e=n.length,u=0,i=[];++r>>1,fn=[["ary",X],["bind",1],["bindKey",2],["curry",8],["curryRight",J],["flip",512],["partial",Y],["partialRight",Q],["rearg",nn]],cn="[object Arguments]",ln="[object Array]",sn="[object Boolean]",hn="[object Date]",pn="[object Error]",vn="[object Function]",gn="[object GeneratorFunction]",_n="[object Map]",dn="[object Number]",yn="[object Object]",mn="[object Promise]",bn="[object RegExp]",wn="[object Set]",xn="[object String]",An="[object Symbol]",In="[object WeakMap]",Wn="[object ArrayBuffer]",jn="[object DataView]",Rn="[object Float32Array]",kn="[object Float64Array]",On="[object Int8Array]",En="[object Int16Array]",Sn="[object Int32Array]",zn="[object Uint8Array]",Bn="[object Uint8ClampedArray]",Ln="[object Uint16Array]",Cn="[object Uint32Array]",Fn=/\b__p \+= '';/g,Tn=/\b(__p \+=) '' \+/g,Dn=/(__e\(.*?\)|\b__t\)) \+\n'';/g,Mn=/&(?:amp|lt|gt|quot|#39);/g,Un=/[&<>"']/g,Pn=RegExp(Mn.source),qn=RegExp(Un.source),$n=/<%-([\s\S]+?)%>/g,Nn=/<%([\s\S]+?)%>/g,Kn=/<%=([\s\S]+?)%>/g,Zn=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,Vn=/^\w*$/,Gn=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,Hn=/[\\^$.*+?()[\]{}|]/g,Jn=RegExp(Hn.source),Yn=/^\s+/,Qn=/\s/,Xn=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,nt=/\{\n\/\* \[wrapped with (.+)\] \*/,tt=/,? & /,rt=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,et=/[()=,{}\[\]\/\s]/,ut=/\\(\\)?/g,it=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,ot=/\w*$/,at=/^[-+]0x[0-9a-f]+$/i,ft=/^0b[01]+$/i,ct=/^\[object .+?Constructor\]$/,lt=/^0o[0-7]+$/i,st=/^(?:0|[1-9]\d*)$/,ht=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,pt=/($^)/,vt=/['\n\r\u2028\u2029\\]/g,gt="\\ud800-\\udfff",_t="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",dt="\\u2700-\\u27bf",yt="a-z\\xdf-\\xf6\\xf8-\\xff",mt="A-Z\\xc0-\\xd6\\xd8-\\xde",bt="\\ufe0e\\ufe0f",wt="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",xt="['’]",At="["+gt+"]",It="["+wt+"]",Wt="["+_t+"]",jt="\\d+",Rt="["+dt+"]",kt="["+yt+"]",Ot="[^"+gt+wt+jt+dt+yt+mt+"]",Et="\\ud83c[\\udffb-\\udfff]",St="[^"+gt+"]",zt="(?:\\ud83c[\\udde6-\\uddff]){2}",Bt="[\\ud800-\\udbff][\\udc00-\\udfff]",Lt="["+mt+"]",Ct="\\u200d",Ft="(?:"+kt+"|"+Ot+")",Tt="(?:"+Lt+"|"+Ot+")",Dt="(?:['’](?:d|ll|m|re|s|t|ve))?",Mt="(?:['’](?:D|LL|M|RE|S|T|VE))?",Ut="(?:"+Wt+"|"+Et+")"+"?",Pt="["+bt+"]?",qt=Pt+Ut+("(?:"+Ct+"(?:"+[St,zt,Bt].join("|")+")"+Pt+Ut+")*"),$t="(?:"+[Rt,zt,Bt].join("|")+")"+qt,Nt="(?:"+[St+Wt+"?",Wt,zt,Bt,At].join("|")+")",Kt=RegExp(xt,"g"),Zt=RegExp(Wt,"g"),Vt=RegExp(Et+"(?="+Et+")|"+Nt+qt,"g"),Gt=RegExp([Lt+"?"+kt+"+"+Dt+"(?="+[It,Lt,"$"].join("|")+")",Tt+"+"+Mt+"(?="+[It,Lt+Ft,"$"].join("|")+")",Lt+"?"+Ft+"+"+Dt,Lt+"+"+Mt,"\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",jt,$t].join("|"),"g"),Ht=RegExp("["+Ct+gt+_t+bt+"]"),Jt=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Yt=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Qt=-1,Xt={};Xt[Rn]=Xt[kn]=Xt[On]=Xt[En]=Xt[Sn]=Xt[zn]=Xt[Bn]=Xt[Ln]=Xt[Cn]=!0,Xt[cn]=Xt[ln]=Xt[Wn]=Xt[sn]=Xt[jn]=Xt[hn]=Xt[pn]=Xt[vn]=Xt[_n]=Xt[dn]=Xt[yn]=Xt[bn]=Xt[wn]=Xt[xn]=Xt[In]=!1;var nr={};nr[cn]=nr[ln]=nr[Wn]=nr[jn]=nr[sn]=nr[hn]=nr[Rn]=nr[kn]=nr[On]=nr[En]=nr[Sn]=nr[_n]=nr[dn]=nr[yn]=nr[bn]=nr[wn]=nr[xn]=nr[An]=nr[zn]=nr[Bn]=nr[Ln]=nr[Cn]=!0,nr[pn]=nr[vn]=nr[In]=!1;var tr={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},rr=parseFloat,er=parseInt,ur="object"==typeof r.g&&r.g&&r.g.Object===Object&&r.g,ir="object"==typeof self&&self&&self.Object===Object&&self,or=ur||ir||Function("return this")(),ar=t&&!t.nodeType&&t,fr=ar&&n&&!n.nodeType&&n,cr=fr&&fr.exports===ar,lr=cr&&ur.process,sr=function(){try{var n=fr&&fr.require&&fr.require("util").types;return n||lr&&lr.binding&&lr.binding("util")}catch(n){}}(),hr=sr&&sr.isArrayBuffer,pr=sr&&sr.isDate,vr=sr&&sr.isMap,gr=sr&&sr.isRegExp,_r=sr&&sr.isSet,dr=sr&&sr.isTypedArray,yr=I("length"),mr=W({À:"A",Á:"A",Â:"A",Ã:"A",Ä:"A",Å:"A",à:"a",á:"a",â:"a",ã:"a",ä:"a",å:"a",Ç:"C",ç:"c",Ð:"D",ð:"d",È:"E",É:"E",Ê:"E",Ë:"E",è:"e",é:"e",ê:"e",ë:"e",Ì:"I",Í:"I",Î:"I",Ï:"I",ì:"i",í:"i",î:"i",ï:"i",Ñ:"N",ñ:"n",Ò:"O",Ó:"O",Ô:"O",Õ:"O",Ö:"O",Ø:"O",ò:"o",ó:"o",ô:"o",õ:"o",ö:"o",ø:"o",Ù:"U",Ú:"U",Û:"U",Ü:"U",ù:"u",ú:"u",û:"u",ü:"u",Ý:"Y",ý:"y",ÿ:"y",Æ:"Ae",æ:"ae",Þ:"Th",þ:"th",ß:"ss",Ā:"A",Ă:"A",Ą:"A",ā:"a",ă:"a",ą:"a",Ć:"C",Ĉ:"C",Ċ:"C",Č:"C",ć:"c",ĉ:"c",ċ:"c",č:"c",Ď:"D",Đ:"D",ď:"d",đ:"d",Ē:"E",Ĕ:"E",Ė:"E",Ę:"E",Ě:"E",ē:"e",ĕ:"e",ė:"e",ę:"e",ě:"e",Ĝ:"G",Ğ:"G",Ġ:"G",Ģ:"G",ĝ:"g",ğ:"g",ġ:"g",ģ:"g",Ĥ:"H",Ħ:"H",ĥ:"h",ħ:"h",Ĩ:"I",Ī:"I",Ĭ:"I",Į:"I",İ:"I",ĩ:"i",ī:"i",ĭ:"i",į:"i",ı:"i",Ĵ:"J",ĵ:"j",Ķ:"K",ķ:"k",ĸ:"k",Ĺ:"L",Ļ:"L",Ľ:"L",Ŀ:"L",Ł:"L",ĺ:"l",ļ:"l",ľ:"l",ŀ:"l",ł:"l",Ń:"N",Ņ:"N",Ň:"N",Ŋ:"N",ń:"n",ņ:"n",ň:"n",ŋ:"n",Ō:"O",Ŏ:"O",Ő:"O",ō:"o",ŏ:"o",ő:"o",Ŕ:"R",Ŗ:"R",Ř:"R",ŕ:"r",ŗ:"r",ř:"r",Ś:"S",Ŝ:"S",Ş:"S",Š:"S",ś:"s",ŝ:"s",ş:"s",š:"s",Ţ:"T",Ť:"T",Ŧ:"T",ţ:"t",ť:"t",ŧ:"t",Ũ:"U",Ū:"U",Ŭ:"U",Ů:"U",Ű:"U",Ų:"U",ũ:"u",ū:"u",ŭ:"u",ů:"u",ű:"u",ų:"u",Ŵ:"W",ŵ:"w",Ŷ:"Y",ŷ:"y",Ÿ:"Y",Ź:"Z",Ż:"Z",Ž:"Z",ź:"z",ż:"z",ž:"z",IJ:"IJ",ij:"ij",Œ:"Oe",œ:"oe",ʼn:"'n",ſ:"s"}),br=W({"&":"&","<":"<",">":">",'"':""","'":"'"}),wr=W({"&":"&","<":"<",">":">",""":'"',"'":"'"}),xr=function n(t){function r(n){if(Uu(n)&&!Ea(n)&&!(n instanceof Qn)){if(n instanceof W)return n;if(Oi.call(n,"__wrapped__"))return hu(n)}return new W(n)}function e(){}function W(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=Z}function Qn(n){this.__wrapped__=n,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=un,this.__views__=[]}function rt(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t=t?n:t)),n}function St(n,t,r,e,u,i){var a,f=1&t,c=2&t,l=4&t;if(r&&(a=u?r(n,e,u,i):r(n)),a!==Z)return a;if(!Mu(n))return n;var s=Ea(n);if(s){if(a=function(n){var t=n.length,r=new n.constructor(t);return t&&"string"==typeof n[0]&&Oi.call(n,"index")&&(r.index=n.index,r.input=n.input),r}(n),!f)return le(n,a)}else{var h=Uo(n),p=h==vn||h==gn;if(za(n))return ue(n,f);if(h==yn||h==cn||p&&!u){if(a=c||p?{}:Ge(n),!f)return c?function(n,t){return se(n,Mo(n),t)}(n,function(n,t){return n&&se(t,ti(t),n)}(a,n)):function(n,t){return se(n,Do(n),t)}(n,Rt(a,n))}else{if(!nr[h])return u?n:{};a=function(n,t,r){var e=n.constructor;switch(t){case Wn:return ie(n);case sn:case hn:return new e(+n);case jn:return function(n,t){return new n.constructor(t?ie(n.buffer):n.buffer,n.byteOffset,n.byteLength)}(n,r);case Rn:case kn:case On:case En:case Sn:case zn:case Bn:case Ln:case Cn:return oe(n,r);case _n:return new e;case dn:case xn:return new e(n);case bn:return function(n){var t=new n.constructor(n.source,ot.exec(n));return t.lastIndex=n.lastIndex,t}(n);case wn:return new e;case An:return function(n){return Wo?bi(Wo.call(n)):{}}(n)}}(n,h,f)}}i||(i=new yt);var v=i.get(n);if(v)return v;i.set(n,a),Fa(n)?n.forEach((function(e){a.add(St(e,t,r,e,n,i))})):La(n)&&n.forEach((function(e,u){a.set(u,St(e,t,r,u,n,i))}));var g=s?Z:(l?c?Ue:Me:c?ti:ni)(n);return o(g||n,(function(e,u){g&&(e=n[u=e]),It(a,u,St(e,t,r,u,n,i))})),a}function zt(n,t,r){var e=r.length;if(null==n)return!e;for(n=bi(n);e--;){var u=r[e],i=t[u],o=n[u];if(o===Z&&!(u in n)||!i(o))return!1}return!0}function Bt(n,t,r){if("function"!=typeof n)throw new Ai(V);return $o((function(){n.apply(Z,r)}),t)}function Lt(n,t,r,e){var u=-1,i=l,o=!0,a=n.length,f=[],c=t.length;if(!a)return f;r&&(t=h(t,E(r))),e?(i=s,o=!1):t.length>=200&&(i=z,o=!1,t=new dt(t));n:for(;++u0&&r(a)?t>1?Dt(a,t-1,r,e,u):p(u,a):e||(u[u.length]=a)}return u}function Mt(n,t){return n&&Eo(n,t,ni)}function Ut(n,t){return n&&So(n,t,ni)}function Pt(n,t){return c(t,(function(t){return Fu(n[t])}))}function qt(n,t){for(var r=0,e=(t=re(t,n)).length;null!=n&&rt}function Gt(n,t){return null!=n&&Oi.call(n,t)}function Ht(n,t){return null!=n&&t in bi(n)}function Jt(n,t,r){for(var e=r?s:l,u=n[0].length,i=n.length,o=i,a=gi(i),f=1/0,c=[];o--;){var p=n[o];o&&t&&(p=h(p,E(t))),f=io(p.length,f),a[o]=!r&&(t||u>=120&&p.length>=120)?new dt(o&&p):Z}p=n[0];var v=-1,g=a[0];n:for(;++v=a?f:f*("desc"==r[e]?-1:1)}return n.index-t.index}(n,t,r)}))}function Er(n,t,r){for(var e=-1,u=t.length,i={};++e-1;)a!==n&&$i.call(a,f,1),$i.call(n,f,1);return n}function zr(n,t){for(var r=n?t.length:0,e=r-1;r--;){var u=t[r];if(r==e||u!==i){var i=u;Je(u)?$i.call(n,u,1):Gr(n,u)}}return n}function Br(n,t){return n+Qi(fo()*(t-n+1))}function Lr(n,t){var r="";if(!n||t<1||t>rn)return r;do{t%2&&(r+=n),(t=Qi(t/2))&&(n+=n)}while(t);return r}function Cr(n,t){return No(eu(n,t,fi),n+"")}function Fr(n){return bt(ei(n))}function Tr(n,t){var r=ei(n);return fu(r,Et(t,0,r.length))}function Dr(n,t,r,e){if(!Mu(n))return n;for(var u=-1,i=(t=re(t,n)).length,o=i-1,a=n;null!=a&&++uu?0:u+t),(r=r>u?u:r)<0&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0;for(var i=gi(u);++e>>1,o=n[i];null!==o&&!Nu(o)&&(r?o<=t:o=200){var c=t?null:Fo(n);if(c)return P(c);o=!1,u=z,f=new dt}else f=t?[]:a;n:for(;++e=e?n:Ur(n,t,r)}function ue(n,t){if(t)return n.slice();var r=n.length,e=Mi?Mi(r):new n.constructor(r);return n.copy(e),e}function ie(n){var t=new n.constructor(n.byteLength);return new Di(t).set(new Di(n)),t}function oe(n,t){return new n.constructor(t?ie(n.buffer):n.buffer,n.byteOffset,n.length)}function ae(n,t){if(n!==t){var r=n!==Z,e=null===n,u=n==n,i=Nu(n),o=t!==Z,a=null===t,f=t==t,c=Nu(t);if(!a&&!c&&!i&&n>t||i&&o&&f&&!a&&!c||e&&o&&f||!r&&f||!u)return 1;if(!e&&!i&&!c&&n1?r[u-1]:Z,o=u>2?r[2]:Z;for(i=n.length>3&&"function"==typeof i?(u--,i):Z,o&&Ye(r[0],r[1],o)&&(i=u<3?Z:i,u=1),t=bi(t);++e-1?u[i?t[o]:o]:Z}}function we(n){return De((function(t){var r=t.length,e=r,u=W.prototype.thru;for(n&&t.reverse();e--;){var i=t[e];if("function"!=typeof i)throw new Ai(V);if(u&&!o&&"wrapper"==Pe(i))var o=new W([],!0)}for(e=o?e:r;++e1&&y.reverse(),l&&fa))return!1;var c=i.get(n),l=i.get(t);if(c&&l)return c==t&&l==n;var s=-1,h=!0,p=2&r?new dt:Z;for(i.set(n,t),i.set(t,n);++s-1&&n%1==0&&n1?"& ":"")+t[e],t=t.join(r>2?", ":" "),n.replace(Xn,"{\n/* [wrapped with "+t+"] */\n")}(e,su(function(n){var t=n.match(nt);return t?t[1].split(tt):[]}(e),r)))}function au(n){var t=0,r=0;return function(){var e=oo(),u=16-(e-r);if(r=e,u>0){if(++t>=800)return arguments[0]}else t=0;return n.apply(Z,arguments)}}function fu(n,t){var r=-1,e=n.length,u=e-1;for(t=t===Z?e:t;++r0&&(r=t.apply(this,arguments)),n<=1&&(t=Z),r}}function Ou(n,t,r){function e(t){var r=f,e=c;return f=c=Z,v=t,s=n.apply(e,r)}function u(n){var r=n-p;return p===Z||r>=t||r<0||_&&n-v>=l}function i(){var n=ya();return u(n)?o(n):(h=$o(i,function(n){var r=t-(n-p);return _?io(r,l-(n-v)):r}(n)),Z)}function o(n){return h=Z,d&&f?e(n):(f=c=Z,s)}function a(){var n=ya(),r=u(n);if(f=arguments,c=this,p=n,r){if(h===Z)return function(n){return v=n,h=$o(i,t),g?e(n):s}(p);if(_)return Co(h),h=$o(i,t),e(p)}return h===Z&&(h=$o(i,t)),s}var f,c,l,s,h,p,v=0,g=!1,_=!1,d=!0;if("function"!=typeof n)throw new Ai(V);return t=Hu(t)||0,Mu(r)&&(g=!!r.leading,l=(_="maxWait"in r)?uo(Hu(r.maxWait)||0,t):l,d="trailing"in r?!!r.trailing:d),a.cancel=function(){h!==Z&&Co(h),v=0,f=p=c=h=Z},a.flush=function(){return h===Z?s:o(ya())},a}function Eu(n,t){if("function"!=typeof n||null!=t&&"function"!=typeof t)throw new Ai(V);var r=function(){var e=arguments,u=t?t.apply(this,e):e[0],i=r.cache;if(i.has(u))return i.get(u);var o=n.apply(this,e);return r.cache=i.set(u,o)||i,o};return r.cache=new(Eu.Cache||_t),r}function Su(n){if("function"!=typeof n)throw new Ai(V);return function(){var t=arguments;switch(t.length){case 0:return!n.call(this);case 1:return!n.call(this,t[0]);case 2:return!n.call(this,t[0],t[1]);case 3:return!n.call(this,t[0],t[1],t[2])}return!n.apply(this,t)}}function zu(n,t){return n===t||n!=n&&t!=t}function Bu(n){return null!=n&&Du(n.length)&&!Fu(n)}function Lu(n){return Uu(n)&&Bu(n)}function Cu(n){if(!Uu(n))return!1;var t=Nt(n);return t==pn||"[object DOMException]"==t||"string"==typeof n.message&&"string"==typeof n.name&&!qu(n)}function Fu(n){if(!Mu(n))return!1;var t=Nt(n);return t==vn||t==gn||"[object AsyncFunction]"==t||"[object Proxy]"==t}function Tu(n){return"number"==typeof n&&n==Vu(n)}function Du(n){return"number"==typeof n&&n>-1&&n%1==0&&n<=rn}function Mu(n){var t=typeof n;return null!=n&&("object"==t||"function"==t)}function Uu(n){return null!=n&&"object"==typeof n}function Pu(n){return"number"==typeof n||Uu(n)&&Nt(n)==dn}function qu(n){if(!Uu(n)||Nt(n)!=yn)return!1;var t=Ui(n);if(null===t)return!0;var r=Oi.call(t,"constructor")&&t.constructor;return"function"==typeof r&&r instanceof r&&ki.call(r)==Bi}function $u(n){return"string"==typeof n||!Ea(n)&&Uu(n)&&Nt(n)==xn}function Nu(n){return"symbol"==typeof n||Uu(n)&&Nt(n)==An}function Ku(n){if(!n)return[];if(Bu(n))return $u(n)?$(n):le(n);if(Ki&&n[Ki])return function(n){for(var t,r=[];!(t=n.next()).done;)r.push(t.value);return r}(n[Ki]());var t=Uo(n);return(t==_n?D:t==wn?P:ei)(n)}function Zu(n){return n?(n=Hu(n))===tn||n===-tn?17976931348623157e292*(n<0?-1:1):n==n?n:0:0===n?n:0}function Vu(n){var t=Zu(n),r=t%1;return t==t?r?t-r:t:0}function Gu(n){return n?Et(Vu(n),0,un):0}function Hu(n){if("number"==typeof n)return n;if(Nu(n))return en;if(Mu(n)){var t="function"==typeof n.valueOf?n.valueOf():n;n=Mu(t)?t+"":t}if("string"!=typeof n)return 0===n?n:+n;n=O(n);var r=ft.test(n);return r||lt.test(n)?er(n.slice(2),r?2:8):at.test(n)?en:+n}function Ju(n){return se(n,ti(n))}function Yu(n){return null==n?"":Zr(n)}function Qu(n,t,r){var e=null==n?Z:qt(n,t);return e===Z?r:e}function Xu(n,t){return null!=n&&Ve(n,t,Ht)}function ni(n){return Bu(n)?mt(n):sr(n)}function ti(n){return Bu(n)?mt(n,!0):yr(n)}function ri(n,t){if(null==n)return{};var r=h(Ue(n),(function(n){return[n]}));return t=$e(t),Er(n,r,(function(n,r){return t(n,r[0])}))}function ei(n){return null==n?[]:S(n,ni(n))}function ui(n){return lf(Yu(n).toLowerCase())}function ii(n){return(n=Yu(n))&&n.replace(ht,mr).replace(Zt,"")}function oi(n,t,r){return n=Yu(n),(t=r?Z:t)===Z?T(n)?K(n):d(n):n.match(t)||[]}function ai(n){return function(){return n}}function fi(n){return n}function ci(n){return lr("function"==typeof n?n:St(n,1))}function li(n,t,r){var e=ni(t),u=Pt(t,e);null!=r||Mu(t)&&(u.length||!e.length)||(r=t,t=n,n=this,u=Pt(t,ni(t)));var i=!(Mu(r)&&"chain"in r&&!r.chain),a=Fu(n);return o(u,(function(r){var e=t[r];n[r]=e,a&&(n.prototype[r]=function(){var t=this.__chain__;if(i||t){var r=n(this.__wrapped__);return(r.__actions__=le(this.__actions__)).push({func:e,args:arguments,thisArg:n}),r.__chain__=t,r}return e.apply(n,p([this.value()],arguments))})})),n}function si(){}function hi(n){return Qe(n)?I(cu(n)):function(n){return function(t){return qt(t,n)}}(n)}function pi(){return[]}function vi(){return!1}var gi=(t=null==t?or:xr.defaults(or.Object(),t,xr.pick(or,Yt))).Array,_i=t.Date,di=t.Error,yi=t.Function,mi=t.Math,bi=t.Object,wi=t.RegExp,xi=t.String,Ai=t.TypeError,Ii=gi.prototype,Wi=yi.prototype,ji=bi.prototype,Ri=t["__core-js_shared__"],ki=Wi.toString,Oi=ji.hasOwnProperty,Ei=0,Si=function(){var n=/[^.]+$/.exec(Ri&&Ri.keys&&Ri.keys.IE_PROTO||"");return n?"Symbol(src)_1."+n:""}(),zi=ji.toString,Bi=ki.call(bi),Li=or._,Ci=wi("^"+ki.call(Oi).replace(Hn,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Fi=cr?t.Buffer:Z,Ti=t.Symbol,Di=t.Uint8Array,Mi=Fi?Fi.allocUnsafe:Z,Ui=M(bi.getPrototypeOf,bi),Pi=bi.create,qi=ji.propertyIsEnumerable,$i=Ii.splice,Ni=Ti?Ti.isConcatSpreadable:Z,Ki=Ti?Ti.iterator:Z,Zi=Ti?Ti.toStringTag:Z,Vi=function(){try{var n=Ze(bi,"defineProperty");return n({},"",{}),n}catch(n){}}(),Gi=t.clearTimeout!==or.clearTimeout&&t.clearTimeout,Hi=_i&&_i.now!==or.Date.now&&_i.now,Ji=t.setTimeout!==or.setTimeout&&t.setTimeout,Yi=mi.ceil,Qi=mi.floor,Xi=bi.getOwnPropertySymbols,no=Fi?Fi.isBuffer:Z,to=t.isFinite,ro=Ii.join,eo=M(bi.keys,bi),uo=mi.max,io=mi.min,oo=_i.now,ao=t.parseInt,fo=mi.random,co=Ii.reverse,lo=Ze(t,"DataView"),so=Ze(t,"Map"),ho=Ze(t,"Promise"),po=Ze(t,"Set"),vo=Ze(t,"WeakMap"),go=Ze(bi,"create"),_o=vo&&new vo,yo={},mo=lu(lo),bo=lu(so),wo=lu(ho),xo=lu(po),Ao=lu(vo),Io=Ti?Ti.prototype:Z,Wo=Io?Io.valueOf:Z,jo=Io?Io.toString:Z,Ro=function(){function n(){}return function(t){if(!Mu(t))return{};if(Pi)return Pi(t);n.prototype=t;var r=new n;return n.prototype=Z,r}}();r.templateSettings={escape:$n,evaluate:Nn,interpolate:Kn,variable:"",imports:{_:r}},r.prototype=e.prototype,r.prototype.constructor=r,W.prototype=Ro(e.prototype),W.prototype.constructor=W,Qn.prototype=Ro(e.prototype),Qn.prototype.constructor=Qn,rt.prototype.clear=function(){this.__data__=go?go(null):{},this.size=0},rt.prototype.delete=function(n){var t=this.has(n)&&delete this.__data__[n];return this.size-=t?1:0,t},rt.prototype.get=function(n){var t=this.__data__;if(go){var r=t[n];return r===G?Z:r}return Oi.call(t,n)?t[n]:Z},rt.prototype.has=function(n){var t=this.__data__;return go?t[n]!==Z:Oi.call(t,n)},rt.prototype.set=function(n,t){var r=this.__data__;return this.size+=this.has(n)?0:1,r[n]=go&&t===Z?G:t,this},gt.prototype.clear=function(){this.__data__=[],this.size=0},gt.prototype.delete=function(n){var t=this.__data__,r=Wt(t,n);return!(r<0||(r==t.length-1?t.pop():$i.call(t,r,1),--this.size,0))},gt.prototype.get=function(n){var t=this.__data__,r=Wt(t,n);return r<0?Z:t[r][1]},gt.prototype.has=function(n){return Wt(this.__data__,n)>-1},gt.prototype.set=function(n,t){var r=this.__data__,e=Wt(r,n);return e<0?(++this.size,r.push([n,t])):r[e][1]=t,this},_t.prototype.clear=function(){this.size=0,this.__data__={hash:new rt,map:new(so||gt),string:new rt}},_t.prototype.delete=function(n){var t=Ne(this,n).delete(n);return this.size-=t?1:0,t},_t.prototype.get=function(n){return Ne(this,n).get(n)},_t.prototype.has=function(n){return Ne(this,n).has(n)},_t.prototype.set=function(n,t){var r=Ne(this,n),e=r.size;return r.set(n,t),this.size+=r.size==e?0:1,this},dt.prototype.add=dt.prototype.push=function(n){return this.__data__.set(n,G),this},dt.prototype.has=function(n){return this.__data__.has(n)},yt.prototype.clear=function(){this.__data__=new gt,this.size=0},yt.prototype.delete=function(n){var t=this.__data__,r=t.delete(n);return this.size=t.size,r},yt.prototype.get=function(n){return this.__data__.get(n)},yt.prototype.has=function(n){return this.__data__.has(n)},yt.prototype.set=function(n,t){var r=this.__data__;if(r instanceof gt){var e=r.__data__;if(!so||e.length<199)return e.push([n,t]),this.size=++r.size,this;r=this.__data__=new _t(e)}return r.set(n,t),this.size=r.size,this};var ko=ve(Mt),Oo=ve(Ut,!0),Eo=ge(),So=ge(!0),zo=_o?function(n,t){return _o.set(n,t),n}:fi,Bo=Vi?function(n,t){return Vi(n,"toString",{configurable:!0,enumerable:!1,value:ai(t),writable:!0})}:fi,Lo=Cr,Co=Gi||function(n){return or.clearTimeout(n)},Fo=po&&1/P(new po([,-0]))[1]==tn?function(n){return new po(n)}:si,To=_o?function(n){return _o.get(n)}:si,Do=Xi?function(n){return null==n?[]:(n=bi(n),c(Xi(n),(function(t){return qi.call(n,t)})))}:pi,Mo=Xi?function(n){for(var t=[];n;)p(t,Do(n)),n=Ui(n);return t}:pi,Uo=Nt;(lo&&Uo(new lo(new ArrayBuffer(1)))!=jn||so&&Uo(new so)!=_n||ho&&Uo(ho.resolve())!=mn||po&&Uo(new po)!=wn||vo&&Uo(new vo)!=In)&&(Uo=function(n){var t=Nt(n),r=t==yn?n.constructor:Z,e=r?lu(r):"";if(e)switch(e){case mo:return jn;case bo:return _n;case wo:return mn;case xo:return wn;case Ao:return In}return t});var Po=Ri?Fu:vi,qo=au(zo),$o=Ji||function(n,t){return or.setTimeout(n,t)},No=au(Bo),Ko=function(n){var t=Eu(n,(function(n){return 500===r.size&&r.clear(),n})),r=t.cache;return t}((function(n){var t=[];return 46===n.charCodeAt(0)&&t.push(""),n.replace(Gn,(function(n,r,e,u){t.push(e?u.replace(ut,"$1"):r||n)})),t})),Zo=Cr((function(n,t){return Lu(n)?Lt(n,Dt(t,1,Lu,!0)):[]})),Vo=Cr((function(n,t){var r=du(t);return Lu(r)&&(r=Z),Lu(n)?Lt(n,Dt(t,1,Lu,!0),$e(r,2)):[]})),Go=Cr((function(n,t){var r=du(t);return Lu(r)&&(r=Z),Lu(n)?Lt(n,Dt(t,1,Lu,!0),Z,r):[]})),Ho=Cr((function(n){var t=h(n,ne);return t.length&&t[0]===n[0]?Jt(t):[]})),Jo=Cr((function(n){var t=du(n),r=h(n,ne);return t===du(r)?t=Z:r.pop(),r.length&&r[0]===n[0]?Jt(r,$e(t,2)):[]})),Yo=Cr((function(n){var t=du(n),r=h(n,ne);return(t="function"==typeof t?t:Z)&&r.pop(),r.length&&r[0]===n[0]?Jt(r,Z,t):[]})),Qo=Cr(yu),Xo=De((function(n,t){var r=null==n?0:n.length,e=Ot(n,t);return zr(n,h(t,(function(n){return Je(n,r)?+n:n})).sort(ae)),e})),na=Cr((function(n){return Vr(Dt(n,1,Lu,!0))})),ta=Cr((function(n){var t=du(n);return Lu(t)&&(t=Z),Vr(Dt(n,1,Lu,!0),$e(t,2))})),ra=Cr((function(n){var t=du(n);return t="function"==typeof t?t:Z,Vr(Dt(n,1,Lu,!0),Z,t)})),ea=Cr((function(n,t){return Lu(n)?Lt(n,t):[]})),ua=Cr((function(n){return Qr(c(n,Lu))})),ia=Cr((function(n){var t=du(n);return Lu(t)&&(t=Z),Qr(c(n,Lu),$e(t,2))})),oa=Cr((function(n){var t=du(n);return t="function"==typeof t?t:Z,Qr(c(n,Lu),Z,t)})),aa=Cr(bu),fa=Cr((function(n){var t=n.length,r=t>1?n[t-1]:Z;return r="function"==typeof r?(n.pop(),r):Z,wu(n,r)})),ca=De((function(n){var t=n.length,r=t?n[0]:0,e=this.__wrapped__,u=function(t){return Ot(t,n)};return!(t>1||this.__actions__.length)&&e instanceof Qn&&Je(r)?((e=e.slice(r,+r+(t?1:0))).__actions__.push({func:Au,args:[u],thisArg:Z}),new W(e,this.__chain__).thru((function(n){return t&&!n.length&&n.push(Z),n}))):this.thru(u)})),la=he((function(n,t,r){Oi.call(n,r)?++n[r]:kt(n,r,1)})),sa=be(pu),ha=be(vu),pa=he((function(n,t,r){Oi.call(n,r)?n[r].push(t):kt(n,r,[t])})),va=Cr((function(n,t,r){var e=-1,i="function"==typeof t,o=Bu(n)?gi(n.length):[];return ko(n,(function(n){o[++e]=i?u(t,n,r):tr(n,t,r)})),o})),ga=he((function(n,t,r){kt(n,r,t)})),_a=he((function(n,t,r){n[r?0:1].push(t)}),(function(){return[[],[]]})),da=Cr((function(n,t){if(null==n)return[];var r=t.length;return r>1&&Ye(n,t[0],t[1])?t=[]:r>2&&Ye(t[0],t[1],t[2])&&(t=[t[0]]),Or(n,Dt(t,1),[])})),ya=Hi||function(){return or.Date.now()},ma=Cr((function(n,t,r){var e=1;if(r.length){var u=U(r,qe(ma));e|=Y}return Be(n,e,t,r,u)})),ba=Cr((function(n,t,r){var e=3;if(r.length){var u=U(r,qe(ba));e|=Y}return Be(t,e,n,r,u)})),wa=Cr((function(n,t){return Bt(n,1,t)})),xa=Cr((function(n,t,r){return Bt(n,Hu(t)||0,r)}));Eu.Cache=_t;var Aa=Lo((function(n,t){var r=(t=1==t.length&&Ea(t[0])?h(t[0],E($e())):h(Dt(t,1),E($e()))).length;return Cr((function(e){for(var i=-1,o=io(e.length,r);++i=t})),Oa=ur(function(){return arguments}())?ur:function(n){return Uu(n)&&Oi.call(n,"callee")&&!qi.call(n,"callee")},Ea=gi.isArray,Sa=hr?E(hr):function(n){return Uu(n)&&Nt(n)==Wn},za=no||vi,Ba=pr?E(pr):function(n){return Uu(n)&&Nt(n)==hn},La=vr?E(vr):function(n){return Uu(n)&&Uo(n)==_n},Ca=gr?E(gr):function(n){return Uu(n)&&Nt(n)==bn},Fa=_r?E(_r):function(n){return Uu(n)&&Uo(n)==wn},Ta=dr?E(dr):function(n){return Uu(n)&&Du(n.length)&&!!Xt[Nt(n)]},Da=Oe(Ar),Ma=Oe((function(n,t){return n<=t})),Ua=pe((function(n,t){if(nu(t)||Bu(t))return se(t,ni(t),n),Z;for(var r in t)Oi.call(t,r)&&It(n,r,t[r])})),Pa=pe((function(n,t){se(t,ti(t),n)})),qa=pe((function(n,t,r,e){se(t,ti(t),n,e)})),$a=pe((function(n,t,r,e){se(t,ni(t),n,e)})),Na=De(Ot),Ka=Cr((function(n,t){n=bi(n);var r=-1,e=t.length,u=e>2?t[2]:Z;for(u&&Ye(t[0],t[1],u)&&(e=1);++r1),t})),se(n,Ue(n),r),e&&(r=St(r,7,Fe));for(var u=t.length;u--;)Gr(r,t[u]);return r})),Xa=De((function(n,t){return null==n?{}:function(n,t){return Er(n,t,(function(t,r){return Xu(n,r)}))}(n,t)})),nf=ze(ni),tf=ze(ti),rf=de((function(n,t,r){return t=t.toLowerCase(),n+(r?ui(t):t)})),ef=de((function(n,t,r){return n+(r?"-":"")+t.toLowerCase()})),uf=de((function(n,t,r){return n+(r?" ":"")+t.toLowerCase()})),of=_e("toLowerCase"),af=de((function(n,t,r){return n+(r?"_":"")+t.toLowerCase()})),ff=de((function(n,t,r){return n+(r?" ":"")+lf(t)})),cf=de((function(n,t,r){return n+(r?" ":"")+t.toUpperCase()})),lf=_e("toUpperCase"),sf=Cr((function(n,t){try{return u(n,Z,t)}catch(n){return Cu(n)?n:new di(n)}})),hf=De((function(n,t){return o(t,(function(t){t=cu(t),kt(n,t,ma(n[t],n))})),n})),pf=we(),vf=we(!0),gf=Cr((function(n,t){return function(r){return tr(r,n,t)}})),_f=Cr((function(n,t){return function(r){return tr(n,r,t)}})),df=We(h),yf=We(f),mf=We(_),bf=ke(),wf=ke(!0),xf=Ie((function(n,t){return n+t}),0),Af=Se("ceil"),If=Ie((function(n,t){return n/t}),1),Wf=Se("floor"),jf=Ie((function(n,t){return n*t}),1),Rf=Se("round"),kf=Ie((function(n,t){return n-t}),0);return r.after=function(n,t){if("function"!=typeof t)throw new Ai(V);return n=Vu(n),function(){if(--n<1)return t.apply(this,arguments)}},r.ary=Ru,r.assign=Ua,r.assignIn=Pa,r.assignInWith=qa,r.assignWith=$a,r.at=Na,r.before=ku,r.bind=ma,r.bindAll=hf,r.bindKey=ba,r.castArray=function(){if(!arguments.length)return[];var n=arguments[0];return Ea(n)?n:[n]},r.chain=xu,r.chunk=function(n,t,r){t=(r?Ye(n,t,r):t===Z)?1:uo(Vu(t),0);var e=null==n?0:n.length;if(!e||t<1)return[];for(var u=0,i=0,o=gi(Yi(e/t));uu?0:u+r),(e=e===Z||e>u?u:Vu(e))<0&&(e+=u),e=r>e?0:Gu(e);r>>0)?(n=Yu(n))&&("string"==typeof t||null!=t&&!Ca(t))&&(!(t=Zr(t))&&F(n))?ee($(n),0,r):n.split(t,r):[]},r.spread=function(n,t){if("function"!=typeof n)throw new Ai(V);return t=null==t?0:uo(Vu(t),0),Cr((function(r){var e=r[t],i=ee(r,0,t);return e&&p(i,e),u(n,this,i)}))},r.tail=function(n){var t=null==n?0:n.length;return t?Ur(n,1,t):[]},r.take=function(n,t,r){return n&&n.length?Ur(n,0,(t=r||t===Z?1:Vu(t))<0?0:t):[]},r.takeRight=function(n,t,r){var e=null==n?0:n.length;return e?Ur(n,(t=e-(t=r||t===Z?1:Vu(t)))<0?0:t,e):[]},r.takeRightWhile=function(n,t){return n&&n.length?Jr(n,$e(t,3),!1,!0):[]},r.takeWhile=function(n,t){return n&&n.length?Jr(n,$e(t,3)):[]},r.tap=function(n,t){return t(n),n},r.throttle=function(n,t,r){var e=!0,u=!0;if("function"!=typeof n)throw new Ai(V);return Mu(r)&&(e="leading"in r?!!r.leading:e,u="trailing"in r?!!r.trailing:u),Ou(n,t,{leading:e,maxWait:t,trailing:u})},r.thru=Au,r.toArray=Ku,r.toPairs=nf,r.toPairsIn=tf,r.toPath=function(n){return Ea(n)?h(n,cu):Nu(n)?[n]:le(Ko(Yu(n)))},r.toPlainObject=Ju,r.transform=function(n,t,r){var e=Ea(n),u=e||za(n)||Ta(n);if(t=$e(t,4),null==r){var i=n&&n.constructor;r=u?e?new i:[]:Mu(n)&&Fu(i)?Ro(Ui(n)):{}}return(u?o:Mt)(n,(function(n,e,u){return t(r,n,e,u)})),r},r.unary=function(n){return Ru(n,1)},r.union=na,r.unionBy=ta,r.unionWith=ra,r.uniq=function(n){return n&&n.length?Vr(n):[]},r.uniqBy=function(n,t){return n&&n.length?Vr(n,$e(t,2)):[]},r.uniqWith=function(n,t){return t="function"==typeof t?t:Z,n&&n.length?Vr(n,Z,t):[]},r.unset=function(n,t){return null==n||Gr(n,t)},r.unzip=bu,r.unzipWith=wu,r.update=function(n,t,r){return null==n?n:Hr(n,t,te(r))},r.updateWith=function(n,t,r,e){return e="function"==typeof e?e:Z,null==n?n:Hr(n,t,te(r),e)},r.values=ei,r.valuesIn=function(n){return null==n?[]:S(n,ti(n))},r.without=ea,r.words=oi,r.wrap=function(n,t){return Ia(te(t),n)},r.xor=ua,r.xorBy=ia,r.xorWith=oa,r.zip=aa,r.zipObject=function(n,t){return Xr(n||[],t||[],It)},r.zipObjectDeep=function(n,t){return Xr(n||[],t||[],Dr)},r.zipWith=fa,r.entries=nf,r.entriesIn=tf,r.extend=Pa,r.extendWith=qa,li(r,r),r.add=xf,r.attempt=sf,r.camelCase=rf,r.capitalize=ui,r.ceil=Af,r.clamp=function(n,t,r){return r===Z&&(r=t,t=Z),r!==Z&&(r=(r=Hu(r))==r?r:0),t!==Z&&(t=(t=Hu(t))==t?t:0),Et(Hu(n),t,r)},r.clone=function(n){return St(n,4)},r.cloneDeep=function(n){return St(n,5)},r.cloneDeepWith=function(n,t){return St(n,5,t="function"==typeof t?t:Z)},r.cloneWith=function(n,t){return St(n,4,t="function"==typeof t?t:Z)},r.conformsTo=function(n,t){return null==t||zt(n,t,ni(t))},r.deburr=ii,r.defaultTo=function(n,t){return null==n||n!=n?t:n},r.divide=If,r.endsWith=function(n,t,r){n=Yu(n),t=Zr(t);var e=n.length,u=r=r===Z?e:Et(Vu(r),0,e);return(r-=t.length)>=0&&n.slice(r,u)==t},r.eq=zu,r.escape=function(n){return(n=Yu(n))&&qn.test(n)?n.replace(Un,br):n},r.escapeRegExp=function(n){return(n=Yu(n))&&Jn.test(n)?n.replace(Hn,"\\$&"):n},r.every=function(n,t,r){var e=Ea(n)?f:Ct;return r&&Ye(n,t,r)&&(t=Z),e(n,$e(t,3))},r.find=sa,r.findIndex=pu,r.findKey=function(n,t){return y(n,$e(t,3),Mt)},r.findLast=ha,r.findLastIndex=vu,r.findLastKey=function(n,t){return y(n,$e(t,3),Ut)},r.floor=Wf,r.forEach=Iu,r.forEachRight=Wu,r.forIn=function(n,t){return null==n?n:Eo(n,$e(t,3),ti)},r.forInRight=function(n,t){return null==n?n:So(n,$e(t,3),ti)},r.forOwn=function(n,t){return n&&Mt(n,$e(t,3))},r.forOwnRight=function(n,t){return n&&Ut(n,$e(t,3))},r.get=Qu,r.gt=Ra,r.gte=ka,r.has=function(n,t){return null!=n&&Ve(n,t,Gt)},r.hasIn=Xu,r.head=_u,r.identity=fi,r.includes=function(n,t,r,e){n=Bu(n)?n:ei(n),r=r&&!e?Vu(r):0;var u=n.length;return r<0&&(r=uo(u+r,0)),$u(n)?r<=u&&n.indexOf(t,r)>-1:!!u&&b(n,t,r)>-1},r.indexOf=function(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=null==r?0:Vu(r);return u<0&&(u=uo(e+u,0)),b(n,t,u)},r.inRange=function(n,t,r){return t=Zu(t),r===Z?(r=t,t=0):r=Zu(r),function(n,t,r){return n>=io(t,r)&&n=-rn&&n<=rn},r.isSet=Fa,r.isString=$u,r.isSymbol=Nu,r.isTypedArray=Ta,r.isUndefined=function(n){return n===Z},r.isWeakMap=function(n){return Uu(n)&&Uo(n)==In},r.isWeakSet=function(n){return Uu(n)&&"[object WeakSet]"==Nt(n)},r.join=function(n,t){return null==n?"":ro.call(n,t)},r.kebabCase=ef,r.last=du,r.lastIndexOf=function(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=e;return r!==Z&&(u=(u=Vu(r))<0?uo(e+u,0):io(u,e-1)),t==t?function(n,t,r){for(var e=r+1;e--;)if(n[e]===t)return e;return e}(n,t,u):m(n,x,u,!0)},r.lowerCase=uf,r.lowerFirst=of,r.lt=Da,r.lte=Ma,r.max=function(n){return n&&n.length?Ft(n,fi,Vt):Z},r.maxBy=function(n,t){return n&&n.length?Ft(n,$e(t,2),Vt):Z},r.mean=function(n){return A(n,fi)},r.meanBy=function(n,t){return A(n,$e(t,2))},r.min=function(n){return n&&n.length?Ft(n,fi,Ar):Z},r.minBy=function(n,t){return n&&n.length?Ft(n,$e(t,2),Ar):Z},r.stubArray=pi,r.stubFalse=vi,r.stubObject=function(){return{}},r.stubString=function(){return""},r.stubTrue=function(){return!0},r.multiply=jf,r.nth=function(n,t){return n&&n.length?kr(n,Vu(t)):Z},r.noConflict=function(){return or._===this&&(or._=Li),this},r.noop=si,r.now=ya,r.pad=function(n,t,r){n=Yu(n);var e=(t=Vu(t))?q(n):0;if(!t||e>=t)return n;var u=(t-e)/2;return je(Qi(u),r)+n+je(Yi(u),r)},r.padEnd=function(n,t,r){n=Yu(n);var e=(t=Vu(t))?q(n):0;return t&&et){var e=n;n=t,t=e}if(r||n%1||t%1){var u=fo();return io(n+u*(t-n+rr("1e-"+((u+"").length-1))),t)}return Br(n,t)},r.reduce=function(n,t,r){var e=Ea(n)?v:j,u=arguments.length<3;return e(n,$e(t,4),r,u,ko)},r.reduceRight=function(n,t,r){var e=Ea(n)?g:j,u=arguments.length<3;return e(n,$e(t,4),r,u,Oo)},r.repeat=function(n,t,r){return t=(r?Ye(n,t,r):t===Z)?1:Vu(t),Lr(Yu(n),t)},r.replace=function(){var n=arguments,t=Yu(n[0]);return n.length<3?t:t.replace(n[1],n[2])},r.result=function(n,t,r){var e=-1,u=(t=re(t,n)).length;for(u||(u=1,n=Z);++ern)return[];var r=un,e=io(n,un);t=$e(t),n-=un;for(var u=k(e,t);++r=i)return n;var a=r-q(e);if(a<1)return e;var f=o?ee(o,0,a).join(""):n.slice(0,a);if(u===Z)return f+e;if(o&&(a+=f.length-a),Ca(u)){if(n.slice(a).search(u)){var c,l=f;for(u.global||(u=wi(u.source,Yu(ot.exec(u))+"g")),u.lastIndex=0;c=u.exec(l);)var s=c.index;f=f.slice(0,s===Z?a:s)}}else if(n.indexOf(Zr(u),a)!=a){var h=f.lastIndexOf(u);h>-1&&(f=f.slice(0,h))}return f+e},r.unescape=function(n){return(n=Yu(n))&&Pn.test(n)?n.replace(Mn,wr):n},r.uniqueId=function(n){var t=++Ei;return Yu(n)+t},r.upperCase=cf,r.upperFirst=lf,r.each=Iu,r.eachRight=Wu,r.first=_u,li(r,function(){var n={};return Mt(r,(function(t,e){Oi.call(r.prototype,e)||(n[e]=t)})),n}(),{chain:!1}),r.VERSION="4.17.21",o(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(n){r[n].placeholder=r})),o(["drop","take"],(function(n,t){Qn.prototype[n]=function(r){r=r===Z?1:uo(Vu(r),0);var e=this.__filtered__&&!t?new Qn(this):this.clone();return e.__filtered__?e.__takeCount__=io(r,e.__takeCount__):e.__views__.push({size:io(r,un),type:n+(e.__dir__<0?"Right":"")}),e},Qn.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}})),o(["filter","map","takeWhile"],(function(n,t){var r=t+1,e=1==r||3==r;Qn.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:$e(n,3),type:r}),t.__filtered__=t.__filtered__||e,t}})),o(["head","last"],(function(n,t){var r="take"+(t?"Right":"");Qn.prototype[n]=function(){return this[r](1).value()[0]}})),o(["initial","tail"],(function(n,t){var r="drop"+(t?"":"Right");Qn.prototype[n]=function(){return this.__filtered__?new Qn(this):this[r](1)}})),Qn.prototype.compact=function(){return this.filter(fi)},Qn.prototype.find=function(n){return this.filter(n).head()},Qn.prototype.findLast=function(n){return this.reverse().find(n)},Qn.prototype.invokeMap=Cr((function(n,t){return"function"==typeof n?new Qn(this):this.map((function(r){return tr(r,n,t)}))})),Qn.prototype.reject=function(n){return this.filter(Su($e(n)))},Qn.prototype.slice=function(n,t){n=Vu(n);var r=this;return r.__filtered__&&(n>0||t<0)?new Qn(r):(n<0?r=r.takeRight(-n):n&&(r=r.drop(n)),t!==Z&&(r=(t=Vu(t))<0?r.dropRight(-t):r.take(t-n)),r)},Qn.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},Qn.prototype.toArray=function(){return this.take(un)},Mt(Qn.prototype,(function(n,t){var e=/^(?:filter|find|map|reject)|While$/.test(t),u=/^(?:head|last)$/.test(t),i=r[u?"take"+("last"==t?"Right":""):t],o=u||/^find/.test(t);i&&(r.prototype[t]=function(){var t=this.__wrapped__,a=u?[1]:arguments,f=t instanceof Qn,c=a[0],l=f||Ea(t),s=function(n){var t=i.apply(r,p([n],a));return u&&h?t[0]:t};l&&e&&"function"==typeof c&&1!=c.length&&(f=l=!1);var h=this.__chain__,v=!!this.__actions__.length,g=o&&!h,_=f&&!v;if(!o&&l){t=_?t:new Qn(this);var d=n.apply(t,a);return d.__actions__.push({func:Au,args:[s],thisArg:Z}),new W(d,h)}return g&&_?n.apply(this,a):(d=this.thru(s),g?u?d.value()[0]:d.value():d)})})),o(["pop","push","shift","sort","splice","unshift"],(function(n){var t=Ii[n],e=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",u=/^(?:pop|shift)$/.test(n);r.prototype[n]=function(){var n=arguments;if(u&&!this.__chain__){var r=this.value();return t.apply(Ea(r)?r:[],n)}return this[e]((function(r){return t.apply(Ea(r)?r:[],n)}))}})),Mt(Qn.prototype,(function(n,t){var e=r[t];if(e){var u=e.name+"";Oi.call(yo,u)||(yo[u]=[]),yo[u].push({name:t,func:e})}})),yo[xe(Z,2).name]=[{name:"wrapper",func:Z}],Qn.prototype.clone=function(){var n=new Qn(this.__wrapped__);return n.__actions__=le(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=le(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=le(this.__views__),n},Qn.prototype.reverse=function(){if(this.__filtered__){var n=new Qn(this);n.__dir__=-1,n.__filtered__=!0}else(n=this.clone()).__dir__*=-1;return n},Qn.prototype.value=function(){var n=this.__wrapped__.value(),t=this.__dir__,r=Ea(n),e=t<0,u=r?n.length:0,i=function(n,t,r){for(var e=-1,u=r.length;++e=this.__values__.length;return{done:n,value:n?Z:this.__values__[this.__index__++]}},r.prototype.plant=function(n){for(var t,r=this;r instanceof e;){var u=hu(r);u.__index__=0,u.__values__=Z,t?i.__wrapped__=u:t=u;var i=u;r=r.__wrapped__}return i.__wrapped__=n,t},r.prototype.reverse=function(){var n=this.__wrapped__;if(n instanceof Qn){var t=n;return this.__actions__.length&&(t=new Qn(this)),(t=t.reverse()).__actions__.push({func:Au,args:[mu],thisArg:Z}),new W(t,this.__chain__)}return this.thru(mu)},r.prototype.toJSON=r.prototype.valueOf=r.prototype.value=function(){return Yr(this.__wrapped__,this.__actions__)},r.prototype.first=r.prototype.head,Ki&&(r.prototype[Ki]=function(){return this}),r}();or._=xr,void 0===(e=function(){return xr}.call(t,r,t,n))||(n.exports=e)}.call(this)},6877:(n,t,r)=>{n.exports=r(4480)}},t={};function r(e){var u=t[e];if(void 0!==u)return u.exports;var i=t[e]={id:e,loaded:!1,exports:{}};return n[e].call(i.exports,i,i.exports,r),i.loaded=!0,i.exports}return r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(n){if("object"==typeof window)return window}}(),r.nmd=n=>(n.paths=[],n.children||(n.children=[]),n),r(6877)})())); \ No newline at end of file + * Lodash lodash.com/license | Underscore.js 1.8.3 underscorejs.org/LICENSE + */n=r.nmd(n),function(){function u(n,t,r){switch(r.length){case 0:return n.call(t);case 1:return n.call(t,r[0]);case 2:return n.call(t,r[0],r[1]);case 3:return n.call(t,r[0],r[1],r[2])}return n.apply(t,r)}function i(n,t,r,e){for(var u=-1,i=null==n?0:n.length;++u-1}function s(n,t,r){for(var e=-1,u=null==n?0:n.length;++e-1;);return r}function L(n,t){for(var r=n.length;r--&&b(t,n[r],0)>-1;);return r}function C(n){return"\\"+nr[n]}function F(n){return Ht.test(n)}function T(n){return Jt.test(n)}function D(n){var t=-1,r=Array(n.size);return n.forEach((function(n,e){r[++t]=[e,n]})),r}function M(n,t){return function(r){return n(t(r))}}function U(n,t){for(var r=-1,e=n.length,u=0,i=[];++r>>1,fn=[["ary",X],["bind",1],["bindKey",2],["curry",8],["curryRight",J],["flip",512],["partial",Y],["partialRight",Q],["rearg",nn]],cn="[object Arguments]",ln="[object Array]",sn="[object Boolean]",hn="[object Date]",pn="[object Error]",vn="[object Function]",gn="[object GeneratorFunction]",_n="[object Map]",dn="[object Number]",yn="[object Object]",mn="[object Promise]",bn="[object RegExp]",wn="[object Set]",xn="[object String]",An="[object Symbol]",In="[object WeakMap]",Wn="[object ArrayBuffer]",jn="[object DataView]",Rn="[object Float32Array]",kn="[object Float64Array]",On="[object Int8Array]",En="[object Int16Array]",zn="[object Int32Array]",Sn="[object Uint8Array]",Bn="[object Uint8ClampedArray]",Ln="[object Uint16Array]",Cn="[object Uint32Array]",Fn=/\b__p\+='';/g,Tn=/\b(__p\+=)''\+/g,Dn=/(__e\(.*?\)|\b__t\))\+'';/g,Mn=/&(?:amp|lt|gt|quot|#39);/g,Un=/[&<>"']/g,Pn=RegExp(Mn.source),qn=RegExp(Un.source),$n=/<%-([\s\S]+?)%>/g,Nn=/<%([\s\S]+?)%>/g,Kn=/<%=([\s\S]+?)%>/g,Zn=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,Vn=/^\w*$/,Gn=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,Hn=/[\\^$.*+?()[\]{}|]/g,Jn=RegExp(Hn.source),Yn=/^\s+/,Qn=/\s/,Xn=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,nt=/\{\n\/\* \[wrapped with (.+)\] \*/,tt=/,? & /,rt=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,et=/[()=,{}\[\]\/\s]/,ut=/\\(\\)?/g,it=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,ot=/\w*$/,at=/^[-+]0x[0-9a-f]+$/i,ft=/^0b[01]+$/i,ct=/^\[object .+?Constructor\]$/,lt=/^0o[0-7]+$/i,st=/^(?:0|[1-9]\d*)$/,ht=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,pt=/($^)/,vt=/['\n\r\u2028\u2029\\]/g,gt="\\ud800-\\udfff",_t="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",dt="\\u2700-\\u27bf",yt="a-z\\xdf-\\xf6\\xf8-\\xff",mt="A-Z\\xc0-\\xd6\\xd8-\\xde",bt="\\ufe0e\\ufe0f",wt="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",xt="['’]",At="["+gt+"]",It="["+wt+"]",Wt="["+_t+"]",jt="\\d+",Rt="["+dt+"]",kt="["+yt+"]",Ot="[^"+gt+wt+jt+dt+yt+mt+"]",Et="\\ud83c[\\udffb-\\udfff]",zt="[^"+gt+"]",St="(?:\\ud83c[\\udde6-\\uddff]){2}",Bt="[\\ud800-\\udbff][\\udc00-\\udfff]",Lt="["+mt+"]",Ct="\\u200d",Ft="(?:"+kt+"|"+Ot+")",Tt="(?:"+Lt+"|"+Ot+")",Dt="(?:['’](?:d|ll|m|re|s|t|ve))?",Mt="(?:['’](?:D|LL|M|RE|S|T|VE))?",Ut="(?:"+Wt+"|"+Et+")"+"?",Pt="["+bt+"]?",qt=Pt+Ut+("(?:"+Ct+"(?:"+[zt,St,Bt].join("|")+")"+Pt+Ut+")*"),$t="(?:"+[Rt,St,Bt].join("|")+")"+qt,Nt="(?:"+[zt+Wt+"?",Wt,St,Bt,At].join("|")+")",Kt=RegExp(xt,"g"),Zt=RegExp(Wt,"g"),Vt=RegExp(Et+"(?="+Et+")|"+Nt+qt,"g"),Gt=RegExp([Lt+"?"+kt+"+"+Dt+"(?="+[It,Lt,"$"].join("|")+")",Tt+"+"+Mt+"(?="+[It,Lt+Ft,"$"].join("|")+")",Lt+"?"+Ft+"+"+Dt,Lt+"+"+Mt,"\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",jt,$t].join("|"),"g"),Ht=RegExp("["+Ct+gt+_t+bt+"]"),Jt=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Yt=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Qt={};Qt[Rn]=Qt[kn]=Qt[On]=Qt[En]=Qt[zn]=Qt[Sn]=Qt[Bn]=Qt[Ln]=Qt[Cn]=!0,Qt[cn]=Qt[ln]=Qt[Wn]=Qt[sn]=Qt[jn]=Qt[hn]=Qt[pn]=Qt[vn]=Qt[_n]=Qt[dn]=Qt[yn]=Qt[bn]=Qt[wn]=Qt[xn]=Qt[In]=!1;var Xt={};Xt[cn]=Xt[ln]=Xt[Wn]=Xt[jn]=Xt[sn]=Xt[hn]=Xt[Rn]=Xt[kn]=Xt[On]=Xt[En]=Xt[zn]=Xt[_n]=Xt[dn]=Xt[yn]=Xt[bn]=Xt[wn]=Xt[xn]=Xt[An]=Xt[Sn]=Xt[Bn]=Xt[Ln]=Xt[Cn]=!0,Xt[pn]=Xt[vn]=Xt[In]=!1;var nr={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},tr=parseFloat,rr=parseInt,er="object"==typeof r.g&&r.g&&r.g.Object===Object&&r.g,ur="object"==typeof self&&self&&self.Object===Object&&self,ir=er||ur||Function("return this")(),or=t&&!t.nodeType&&t,ar=or&&n&&!n.nodeType&&n,fr=ar&&ar.exports===or,cr=fr&&er.process,lr=function(){try{var n=ar&&ar.require&&ar.require("util").types;return n||cr&&cr.binding&&cr.binding("util")}catch(n){}}(),sr=lr&&lr.isArrayBuffer,hr=lr&&lr.isDate,pr=lr&&lr.isMap,vr=lr&&lr.isRegExp,gr=lr&&lr.isSet,_r=lr&&lr.isTypedArray,dr=I("length"),yr=W({À:"A",Á:"A",Â:"A",Ã:"A",Ä:"A",Å:"A",à:"a",á:"a",â:"a",ã:"a",ä:"a",å:"a",Ç:"C",ç:"c",Ð:"D",ð:"d",È:"E",É:"E",Ê:"E",Ë:"E",è:"e",é:"e",ê:"e",ë:"e",Ì:"I",Í:"I",Î:"I",Ï:"I",ì:"i",í:"i",î:"i",ï:"i",Ñ:"N",ñ:"n",Ò:"O",Ó:"O",Ô:"O",Õ:"O",Ö:"O",Ø:"O",ò:"o",ó:"o",ô:"o",õ:"o",ö:"o",ø:"o",Ù:"U",Ú:"U",Û:"U",Ü:"U",ù:"u",ú:"u",û:"u",ü:"u",Ý:"Y",ý:"y",ÿ:"y",Æ:"Ae",æ:"ae",Þ:"Th",þ:"th",ß:"ss",Ā:"A",Ă:"A",Ą:"A",ā:"a",ă:"a",ą:"a",Ć:"C",Ĉ:"C",Ċ:"C",Č:"C",ć:"c",ĉ:"c",ċ:"c",č:"c",Ď:"D",Đ:"D",ď:"d",đ:"d",Ē:"E",Ĕ:"E",Ė:"E",Ę:"E",Ě:"E",ē:"e",ĕ:"e",ė:"e",ę:"e",ě:"e",Ĝ:"G",Ğ:"G",Ġ:"G",Ģ:"G",ĝ:"g",ğ:"g",ġ:"g",ģ:"g",Ĥ:"H",Ħ:"H",ĥ:"h",ħ:"h",Ĩ:"I",Ī:"I",Ĭ:"I",Į:"I",İ:"I",ĩ:"i",ī:"i",ĭ:"i",į:"i",ı:"i",Ĵ:"J",ĵ:"j",Ķ:"K",ķ:"k",ĸ:"k",Ĺ:"L",Ļ:"L",Ľ:"L",Ŀ:"L",Ł:"L",ĺ:"l",ļ:"l",ľ:"l",ŀ:"l",ł:"l",Ń:"N",Ņ:"N",Ň:"N",Ŋ:"N",ń:"n",ņ:"n",ň:"n",ŋ:"n",Ō:"O",Ŏ:"O",Ő:"O",ō:"o",ŏ:"o",ő:"o",Ŕ:"R",Ŗ:"R",Ř:"R",ŕ:"r",ŗ:"r",ř:"r",Ś:"S",Ŝ:"S",Ş:"S",Š:"S",ś:"s",ŝ:"s",ş:"s",š:"s",Ţ:"T",Ť:"T",Ŧ:"T",ţ:"t",ť:"t",ŧ:"t",Ũ:"U",Ū:"U",Ŭ:"U",Ů:"U",Ű:"U",Ų:"U",ũ:"u",ū:"u",ŭ:"u",ů:"u",ű:"u",ų:"u",Ŵ:"W",ŵ:"w",Ŷ:"Y",ŷ:"y",Ÿ:"Y",Ź:"Z",Ż:"Z",Ž:"Z",ź:"z",ż:"z",ž:"z",IJ:"IJ",ij:"ij",Œ:"Oe",œ:"oe",ʼn:"'n",ſ:"s"}),mr=W({"&":"&","<":"<",">":">",'"':""","'":"'"}),br=W({"&":"&","<":"<",">":">",""":'"',"'":"'"}),wr=function n(t){function r(n){if(Mu(n)&&!Oa(n)&&!(n instanceof Qn)){if(n instanceof W)return n;if(ki.call(n,"__wrapped__"))return su(n)}return new W(n)}function e(){}function W(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=Z}function Qn(n){this.__wrapped__=n,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=un,this.__views__=[]}function rt(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t=t?n:t)),n}function zt(n,t,r,e,u,i){var a,f=1&t,c=2&t,l=4&t;if(r&&(a=u?r(n,e,u,i):r(n)),a!==Z)return a;if(!Du(n))return n;var s=Oa(n);if(s){if(a=function(n){var t=n.length,r=new n.constructor(t);return t&&"string"==typeof n[0]&&ki.call(n,"index")&&(r.index=n.index,r.input=n.input),r}(n),!f)return ce(n,a)}else{var h=Mo(n),p=h==vn||h==gn;if(za(n))return ee(n,f);if(h==yn||h==cn||p&&!u){if(a=c||p?{}:Ve(n),!f)return c?function(n,t){return le(n,Do(n),t)}(n,function(n,t){return n&&le(t,ni(t),n)}(a,n)):function(n,t){return le(n,To(n),t)}(n,Rt(a,n))}else{if(!Xt[h])return u?n:{};a=function(n,t,r){var e=n.constructor;switch(t){case Wn:return ue(n);case sn:case hn:return new e(+n);case jn:return function(n,t){return new n.constructor(t?ue(n.buffer):n.buffer,n.byteOffset,n.byteLength)}(n,r);case Rn:case kn:case On:case En:case zn:case Sn:case Bn:case Ln:case Cn:return ie(n,r);case _n:return new e;case dn:case xn:return new e(n);case bn:return function(n){var t=new n.constructor(n.source,ot.exec(n));return t.lastIndex=n.lastIndex,t}(n);case wn:return new e;case An:return function(n){return Io?mi(Io.call(n)):{}}(n)}}(n,h,f)}}i||(i=new yt);var v=i.get(n);if(v)return v;i.set(n,a),Ca(n)?n.forEach((function(e){a.add(zt(e,t,r,e,n,i))})):Ba(n)&&n.forEach((function(e,u){a.set(u,zt(e,t,r,u,n,i))}));var g=s?Z:(l?c?Me:De:c?ni:Xu)(n);return o(g||n,(function(e,u){g&&(e=n[u=e]),It(a,u,zt(e,t,r,u,n,i))})),a}function St(n,t,r){var e=r.length;if(null==n)return!e;for(n=mi(n);e--;){var u=r[e],i=t[u],o=n[u];if(o===Z&&!(u in n)||!i(o))return!1}return!0}function Bt(n,t,r){if("function"!=typeof n)throw new xi(V);return qo((function(){n.apply(Z,r)}),t)}function Lt(n,t,r,e){var u=-1,i=l,o=!0,a=n.length,f=[],c=t.length;if(!a)return f;r&&(t=h(t,E(r))),e?(i=s,o=!1):t.length>=200&&(i=S,o=!1,t=new dt(t));n:for(;++u0&&r(a)?t>1?Dt(a,t-1,r,e,u):p(u,a):e||(u[u.length]=a)}return u}function Mt(n,t){return n&&Oo(n,t,Xu)}function Ut(n,t){return n&&Eo(n,t,Xu)}function Pt(n,t){return c(t,(function(t){return Cu(n[t])}))}function qt(n,t){for(var r=0,e=(t=te(t,n)).length;null!=n&&rt}function Gt(n,t){return null!=n&&ki.call(n,t)}function Ht(n,t){return null!=n&&t in mi(n)}function Jt(n,t,r){for(var e=r?s:l,u=n[0].length,i=n.length,o=i,a=vi(i),f=1/0,c=[];o--;){var p=n[o];o&&t&&(p=h(p,E(t))),f=uo(p.length,f),a[o]=!r&&(t||u>=120&&p.length>=120)?new dt(o&&p):Z}p=n[0];var v=-1,g=a[0];n:for(;++v=a?f:f*("desc"==r[e]?-1:1)}return n.b-t.b}(n,t,r)}))}function Or(n,t,r){for(var e=-1,u=t.length,i={};++e-1;)a!==n&&qi.call(a,f,1),qi.call(n,f,1);return n}function zr(n,t){for(var r=n?t.length:0,e=r-1;r--;){var u=t[r];if(r==e||u!==i){var i=u;He(u)?qi.call(n,u,1):Vr(n,u)}}return n}function Sr(n,t){return n+Yi(ao()*(t-n+1))}function Br(n,t){var r="";if(!n||t<1||t>rn)return r;do{t%2&&(r+=n),(t=Yi(t/2))&&(n+=n)}while(t);return r}function Lr(n,t){return $o(ru(n,t,ai),n+"")}function Cr(n){return bt(ri(n))}function Fr(n,t){var r=ri(n);return au(r,Et(t,0,r.length))}function Tr(n,t,r,e){if(!Du(n))return n;for(var u=-1,i=(t=te(t,n)).length,o=i-1,a=n;null!=a&&++uu?0:u+t),(r=r>u?u:r)<0&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0;for(var i=vi(u);++e>>1,o=n[i];null!==o&&!$u(o)&&(r?o<=t:o=200){var c=t?null:Co(n);if(c)return P(c);o=!1,u=S,f=new dt}else f=t?[]:a;n:for(;++e=e?n:Mr(n,t,r)}function ee(n,t){if(t)return n.slice();var r=n.length,e=Di?Di(r):new n.constructor(r);return n.copy(e),e}function ue(n){var t=new n.constructor(n.byteLength);return new Ti(t).set(new Ti(n)),t}function ie(n,t){return new n.constructor(t?ue(n.buffer):n.buffer,n.byteOffset,n.length)}function oe(n,t){if(n!==t){var r=n!==Z,e=null===n,u=n==n,i=$u(n),o=t!==Z,a=null===t,f=t==t,c=$u(t);if(!a&&!c&&!i&&n>t||i&&o&&f&&!a&&!c||e&&o&&f||!r&&f||!u)return 1;if(!e&&!i&&!c&&n1?r[u-1]:Z,o=u>2?r[2]:Z;for(i=n.length>3&&"function"==typeof i?(u--,i):Z,o&&Je(r[0],r[1],o)&&(i=u<3?Z:i,u=1),t=mi(t);++e-1?u[i?t[o]:o]:Z}}function be(n){return Te((function(t){var r=t.length,e=r,u=W.prototype.thru;for(n&&t.reverse();e--;){var i=t[e];if("function"!=typeof i)throw new xi(V);if(u&&!o&&"wrapper"==Ue(i))var o=new W([],!0)}for(e=o?e:r;++e1&&y.reverse(),l&&fa))return!1;var c=i.get(n),l=i.get(t);if(c&&l)return c==t&&l==n;var s=-1,h=!0,p=2&r?new dt:Z;for(i.set(n,t),i.set(t,n);++s-1&&n%1==0&&n1?"& ":"")+t[e],t=t.join(r>2?", ":" "),n.replace(Xn,"{\n/* [wrapped with "+t+"] */\n")}(e,lu(function(n){var t=n.match(nt);return t?t[1].split(tt):[]}(e),r)))}function ou(n){var t=0,r=0;return function(){var e=io(),u=16-(e-r);if(r=e,u>0){if(++t>=800)return arguments[0]}else t=0;return n.apply(Z,arguments)}}function au(n,t){var r=-1,e=n.length,u=e-1;for(t=t===Z?e:t;++r0&&(r=t.apply(this,arguments)),n<=1&&(t=Z),r}}function ku(n,t,r){function e(t){var r=f,e=c;return f=c=Z,v=t,s=n.apply(e,r)}function u(n){var r=n-p;return p===Z||r>=t||r<0||_&&n-v>=l}function i(){var n=da();return u(n)?o(n):(h=qo(i,function(n){var r=t-(n-p);return _?uo(r,l-(n-v)):r}(n)),Z)}function o(n){return h=Z,d&&f?e(n):(f=c=Z,s)}function a(){var n=da(),r=u(n);if(f=arguments,c=this,p=n,r){if(h===Z)return function(n){return v=n,h=qo(i,t),g?e(n):s}(p);if(_)return Lo(h),h=qo(i,t),e(p)}return h===Z&&(h=qo(i,t)),s}var f,c,l,s,h,p,v=0,g=!1,_=!1,d=!0;if("function"!=typeof n)throw new xi(V);return t=Gu(t)||0,Du(r)&&(g=!!r.leading,l=(_="maxWait"in r)?eo(Gu(r.maxWait)||0,t):l,d="trailing"in r?!!r.trailing:d),a.cancel=function(){h!==Z&&Lo(h),v=0,f=p=c=h=Z},a.flush=function(){return h===Z?s:o(da())},a}function Ou(n,t){if("function"!=typeof n||null!=t&&"function"!=typeof t)throw new xi(V);var r=function(){var e=arguments,u=t?t.apply(this,e):e[0],i=r.cache;if(i.has(u))return i.get(u);var o=n.apply(this,e);return r.cache=i.set(u,o)||i,o};return r.cache=new(Ou.Cache||_t),r}function Eu(n){if("function"!=typeof n)throw new xi(V);return function(){var t=arguments;switch(t.length){case 0:return!n.call(this);case 1:return!n.call(this,t[0]);case 2:return!n.call(this,t[0],t[1]);case 3:return!n.call(this,t[0],t[1],t[2])}return!n.apply(this,t)}}function zu(n,t){return n===t||n!=n&&t!=t}function Su(n){return null!=n&&Tu(n.length)&&!Cu(n)}function Bu(n){return Mu(n)&&Su(n)}function Lu(n){if(!Mu(n))return!1;var t=Nt(n);return t==pn||"[object DOMException]"==t||"string"==typeof n.message&&"string"==typeof n.name&&!Pu(n)}function Cu(n){if(!Du(n))return!1;var t=Nt(n);return t==vn||t==gn||"[object AsyncFunction]"==t||"[object Proxy]"==t}function Fu(n){return"number"==typeof n&&n==Zu(n)}function Tu(n){return"number"==typeof n&&n>-1&&n%1==0&&n<=rn}function Du(n){var t=typeof n;return null!=n&&("object"==t||"function"==t)}function Mu(n){return null!=n&&"object"==typeof n}function Uu(n){return"number"==typeof n||Mu(n)&&Nt(n)==dn}function Pu(n){if(!Mu(n)||Nt(n)!=yn)return!1;var t=Mi(n);if(null===t)return!0;var r=ki.call(t,"constructor")&&t.constructor;return"function"==typeof r&&r instanceof r&&Ri.call(r)==Si}function qu(n){return"string"==typeof n||!Oa(n)&&Mu(n)&&Nt(n)==xn}function $u(n){return"symbol"==typeof n||Mu(n)&&Nt(n)==An}function Nu(n){if(!n)return[];if(Su(n))return qu(n)?$(n):ce(n);if(Ni&&n[Ni])return function(n){for(var t,r=[];!(t=n.next()).done;)r.push(t.value);return r}(n[Ni]());var t=Mo(n);return(t==_n?D:t==wn?P:ri)(n)}function Ku(n){return n?(n=Gu(n))===tn||n===-tn?17976931348623157e292*(n<0?-1:1):n==n?n:0:0===n?n:0}function Zu(n){var t=Ku(n),r=t%1;return t==t?r?t-r:t:0}function Vu(n){return n?Et(Zu(n),0,un):0}function Gu(n){if("number"==typeof n)return n;if($u(n))return en;if(Du(n)){var t="function"==typeof n.valueOf?n.valueOf():n;n=Du(t)?t+"":t}if("string"!=typeof n)return 0===n?n:+n;n=O(n);var r=ft.test(n);return r||lt.test(n)?rr(n.slice(2),r?2:8):at.test(n)?en:+n}function Hu(n){return le(n,ni(n))}function Ju(n){return null==n?"":Kr(n)}function Yu(n,t,r){var e=null==n?Z:qt(n,t);return e===Z?r:e}function Qu(n,t){return null!=n&&Ze(n,t,Ht)}function Xu(n){return Su(n)?mt(n):lr(n)}function ni(n){return Su(n)?mt(n,!0):dr(n)}function ti(n,t){if(null==n)return{};var r=h(Me(n),(function(n){return[n]}));return t=qe(t),Or(n,r,(function(n,r){return t(n,r[0])}))}function ri(n){return null==n?[]:z(n,Xu(n))}function ei(n){return cf(Ju(n).toLowerCase())}function ui(n){return(n=Ju(n))&&n.replace(ht,yr).replace(Zt,"")}function ii(n,t,r){return n=Ju(n),(t=r?Z:t)===Z?T(n)?K(n):d(n):n.match(t)||[]}function oi(n){return function(){return n}}function ai(n){return n}function fi(n){return cr("function"==typeof n?n:zt(n,1))}function ci(n,t,r){var e=Xu(t),u=Pt(t,e);null!=r||Du(t)&&(u.length||!e.length)||(r=t,t=n,n=this,u=Pt(t,Xu(t)));var i=!(Du(r)&&"chain"in r&&!r.chain),a=Cu(n);return o(u,(function(r){var e=t[r];n[r]=e,a&&(n.prototype[r]=function(){var t=this.__chain__;if(i||t){var r=n(this.__wrapped__);return(r.__actions__=ce(this.__actions__)).push({func:e,args:arguments,thisArg:n}),r.__chain__=t,r}return e.apply(n,p([this.value()],arguments))})})),n}function li(){}function si(n){return Ye(n)?I(fu(n)):function(n){return function(t){return qt(t,n)}}(n)}function hi(){return[]}function pi(){return!1}var vi=(t=null==t?ir:wr.defaults(ir.Object(),t,wr.pick(ir,Yt))).Array,gi=t.Date,_i=t.Error,di=t.Function,yi=t.Math,mi=t.Object,bi=t.RegExp,wi=t.String,xi=t.TypeError,Ai=vi.prototype,Ii=di.prototype,Wi=mi.prototype,ji=t["__core-js_shared__"],Ri=Ii.toString,ki=Wi.hasOwnProperty,Oi=0,Ei=function(){var n=/[^.]+$/.exec(ji&&ji.keys&&ji.keys.IE_PROTO||"");return n?"Symbol(src)_1."+n:""}(),zi=Wi.toString,Si=Ri.call(mi),Bi=ir._,Li=bi("^"+Ri.call(ki).replace(Hn,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Ci=fr?t.Buffer:Z,Fi=t.Symbol,Ti=t.Uint8Array,Di=Ci?Ci.allocUnsafe:Z,Mi=M(mi.getPrototypeOf,mi),Ui=mi.create,Pi=Wi.propertyIsEnumerable,qi=Ai.splice,$i=Fi?Fi.isConcatSpreadable:Z,Ni=Fi?Fi.iterator:Z,Ki=Fi?Fi.toStringTag:Z,Zi=function(){try{var n=Ke(mi,"defineProperty");return n({},"",{}),n}catch(n){}}(),Vi=t.clearTimeout!==ir.clearTimeout&&t.clearTimeout,Gi=gi&&gi.now!==ir.Date.now&&gi.now,Hi=t.setTimeout!==ir.setTimeout&&t.setTimeout,Ji=yi.ceil,Yi=yi.floor,Qi=mi.getOwnPropertySymbols,Xi=Ci?Ci.isBuffer:Z,no=t.isFinite,to=Ai.join,ro=M(mi.keys,mi),eo=yi.max,uo=yi.min,io=gi.now,oo=t.parseInt,ao=yi.random,fo=Ai.reverse,co=Ke(t,"DataView"),lo=Ke(t,"Map"),so=Ke(t,"Promise"),ho=Ke(t,"Set"),po=Ke(t,"WeakMap"),vo=Ke(mi,"create"),go=po&&new po,_o={},yo=cu(co),mo=cu(lo),bo=cu(so),wo=cu(ho),xo=cu(po),Ao=Fi?Fi.prototype:Z,Io=Ao?Ao.valueOf:Z,Wo=Ao?Ao.toString:Z,jo=function(){function n(){}return function(t){if(!Du(t))return{};if(Ui)return Ui(t);n.prototype=t;var r=new n;return n.prototype=Z,r}}();r.templateSettings={escape:$n,evaluate:Nn,interpolate:Kn,variable:"",imports:{_:r}},r.prototype=e.prototype,r.prototype.constructor=r,W.prototype=jo(e.prototype),W.prototype.constructor=W,Qn.prototype=jo(e.prototype),Qn.prototype.constructor=Qn,rt.prototype.clear=function(){this.__data__=vo?vo(null):{},this.size=0},rt.prototype.delete=function(n){var t=this.has(n)&&delete this.__data__[n];return this.size-=t?1:0,t},rt.prototype.get=function(n){var t=this.__data__;if(vo){var r=t[n];return r===G?Z:r}return ki.call(t,n)?t[n]:Z},rt.prototype.has=function(n){var t=this.__data__;return vo?t[n]!==Z:ki.call(t,n)},rt.prototype.set=function(n,t){var r=this.__data__;return this.size+=this.has(n)?0:1,r[n]=vo&&t===Z?G:t,this},gt.prototype.clear=function(){this.__data__=[],this.size=0},gt.prototype.delete=function(n){var t=this.__data__,r=Wt(t,n);return!(r<0||(r==t.length-1?t.pop():qi.call(t,r,1),--this.size,0))},gt.prototype.get=function(n){var t=this.__data__,r=Wt(t,n);return r<0?Z:t[r][1]},gt.prototype.has=function(n){return Wt(this.__data__,n)>-1},gt.prototype.set=function(n,t){var r=this.__data__,e=Wt(r,n);return e<0?(++this.size,r.push([n,t])):r[e][1]=t,this},_t.prototype.clear=function(){this.size=0,this.__data__={hash:new rt,map:new(lo||gt),string:new rt}},_t.prototype.delete=function(n){var t=$e(this,n).delete(n);return this.size-=t?1:0,t},_t.prototype.get=function(n){return $e(this,n).get(n)},_t.prototype.has=function(n){return $e(this,n).has(n)},_t.prototype.set=function(n,t){var r=$e(this,n),e=r.size;return r.set(n,t),this.size+=r.size==e?0:1,this},dt.prototype.add=dt.prototype.push=function(n){return this.__data__.set(n,G),this},dt.prototype.has=function(n){return this.__data__.has(n)},yt.prototype.clear=function(){this.__data__=new gt,this.size=0},yt.prototype.delete=function(n){var t=this.__data__,r=t.delete(n);return this.size=t.size,r},yt.prototype.get=function(n){return this.__data__.get(n)},yt.prototype.has=function(n){return this.__data__.has(n)},yt.prototype.set=function(n,t){var r=this.__data__;if(r instanceof gt){var e=r.__data__;if(!lo||e.length<199)return e.push([n,t]),this.size=++r.size,this;r=this.__data__=new _t(e)}return r.set(n,t),this.size=r.size,this};var Ro=pe(Mt),ko=pe(Ut,!0),Oo=ve(),Eo=ve(!0),zo=go?function(n,t){return go.set(n,t),n}:ai,So=Zi?function(n,t){return Zi(n,"toString",{configurable:!0,enumerable:!1,value:oi(t),writable:!0})}:ai,Bo=Lr,Lo=Vi||function(n){return ir.clearTimeout(n)},Co=ho&&1/P(new ho([,-0]))[1]==tn?function(n){return new ho(n)}:li,Fo=go?function(n){return go.get(n)}:li,To=Qi?function(n){return null==n?[]:(n=mi(n),c(Qi(n),(function(t){return Pi.call(n,t)})))}:hi,Do=Qi?function(n){for(var t=[];n;)p(t,To(n)),n=Mi(n);return t}:hi,Mo=Nt;(co&&Mo(new co(new ArrayBuffer(1)))!=jn||lo&&Mo(new lo)!=_n||so&&Mo(so.resolve())!=mn||ho&&Mo(new ho)!=wn||po&&Mo(new po)!=In)&&(Mo=function(n){var t=Nt(n),r=t==yn?n.constructor:Z,e=r?cu(r):"";if(e)switch(e){case yo:return jn;case mo:return _n;case bo:return mn;case wo:return wn;case xo:return In}return t});var Uo=ji?Cu:pi,Po=ou(zo),qo=Hi||function(n,t){return ir.setTimeout(n,t)},$o=ou(So),No=function(n){var t=Ou(n,(function(n){return 500===r.size&&r.clear(),n})),r=t.cache;return t}((function(n){var t=[];return 46===n.charCodeAt(0)&&t.push(""),n.replace(Gn,(function(n,r,e,u){t.push(e?u.replace(ut,"$1"):r||n)})),t})),Ko=Lr((function(n,t){return Bu(n)?Lt(n,Dt(t,1,Bu,!0)):[]})),Zo=Lr((function(n,t){var r=_u(t);return Bu(r)&&(r=Z),Bu(n)?Lt(n,Dt(t,1,Bu,!0),qe(r,2)):[]})),Vo=Lr((function(n,t){var r=_u(t);return Bu(r)&&(r=Z),Bu(n)?Lt(n,Dt(t,1,Bu,!0),Z,r):[]})),Go=Lr((function(n){var t=h(n,Xr);return t.length&&t[0]===n[0]?Jt(t):[]})),Ho=Lr((function(n){var t=_u(n),r=h(n,Xr);return t===_u(r)?t=Z:r.pop(),r.length&&r[0]===n[0]?Jt(r,qe(t,2)):[]})),Jo=Lr((function(n){var t=_u(n),r=h(n,Xr);return(t="function"==typeof t?t:Z)&&r.pop(),r.length&&r[0]===n[0]?Jt(r,Z,t):[]})),Yo=Lr(du),Qo=Te((function(n,t){var r=null==n?0:n.length,e=Ot(n,t);return zr(n,h(t,(function(n){return He(n,r)?+n:n})).sort(oe)),e})),Xo=Lr((function(n){return Zr(Dt(n,1,Bu,!0))})),na=Lr((function(n){var t=_u(n);return Bu(t)&&(t=Z),Zr(Dt(n,1,Bu,!0),qe(t,2))})),ta=Lr((function(n){var t=_u(n);return t="function"==typeof t?t:Z,Zr(Dt(n,1,Bu,!0),Z,t)})),ra=Lr((function(n,t){return Bu(n)?Lt(n,t):[]})),ea=Lr((function(n){return Yr(c(n,Bu))})),ua=Lr((function(n){var t=_u(n);return Bu(t)&&(t=Z),Yr(c(n,Bu),qe(t,2))})),ia=Lr((function(n){var t=_u(n);return t="function"==typeof t?t:Z,Yr(c(n,Bu),Z,t)})),oa=Lr(mu),aa=Lr((function(n){var t=n.length,r=t>1?n[t-1]:Z;return r="function"==typeof r?(n.pop(),r):Z,bu(n,r)})),fa=Te((function(n){var t=n.length,r=t?n[0]:0,e=this.__wrapped__,u=function(t){return Ot(t,n)};return!(t>1||this.__actions__.length)&&e instanceof Qn&&He(r)?((e=e.slice(r,+r+(t?1:0))).__actions__.push({func:xu,args:[u],thisArg:Z}),new W(e,this.__chain__).thru((function(n){return t&&!n.length&&n.push(Z),n}))):this.thru(u)})),ca=se((function(n,t,r){ki.call(n,r)?++n[r]:kt(n,r,1)})),la=me(hu),sa=me(pu),ha=se((function(n,t,r){ki.call(n,r)?n[r].push(t):kt(n,r,[t])})),pa=Lr((function(n,t,r){var e=-1,i="function"==typeof t,o=Su(n)?vi(n.length):[];return Ro(n,(function(n){o[++e]=i?u(t,n,r):nr(n,t,r)})),o})),va=se((function(n,t,r){kt(n,r,t)})),ga=se((function(n,t,r){n[r?0:1].push(t)}),(function(){return[[],[]]})),_a=Lr((function(n,t){if(null==n)return[];var r=t.length;return r>1&&Je(n,t[0],t[1])?t=[]:r>2&&Je(t[0],t[1],t[2])&&(t=[t[0]]),kr(n,Dt(t,1),[])})),da=Gi||function(){return ir.Date.now()},ya=Lr((function(n,t,r){var e=1;if(r.length){var u=U(r,Pe(ya));e|=Y}return Se(n,e,t,r,u)})),ma=Lr((function(n,t,r){var e=3;if(r.length){var u=U(r,Pe(ma));e|=Y}return Se(t,e,n,r,u)})),ba=Lr((function(n,t){return Bt(n,1,t)})),wa=Lr((function(n,t,r){return Bt(n,Gu(t)||0,r)}));Ou.Cache=_t;var xa=Bo((function(n,t){var r=(t=1==t.length&&Oa(t[0])?h(t[0],E(qe())):h(Dt(t,1),E(qe()))).length;return Lr((function(e){for(var i=-1,o=uo(e.length,r);++i=t})),ka=er(function(){return arguments}())?er:function(n){return Mu(n)&&ki.call(n,"callee")&&!Pi.call(n,"callee")},Oa=vi.isArray,Ea=sr?E(sr):function(n){return Mu(n)&&Nt(n)==Wn},za=Xi||pi,Sa=hr?E(hr):function(n){return Mu(n)&&Nt(n)==hn},Ba=pr?E(pr):function(n){return Mu(n)&&Mo(n)==_n},La=vr?E(vr):function(n){return Mu(n)&&Nt(n)==bn},Ca=gr?E(gr):function(n){return Mu(n)&&Mo(n)==wn},Fa=_r?E(_r):function(n){return Mu(n)&&Tu(n.length)&&!!Qt[Nt(n)]},Ta=ke(xr),Da=ke((function(n,t){return n<=t})),Ma=he((function(n,t){if(Xe(t)||Su(t))return le(t,Xu(t),n),Z;for(var r in t)ki.call(t,r)&&It(n,r,t[r])})),Ua=he((function(n,t){le(t,ni(t),n)})),Pa=he((function(n,t,r,e){le(t,ni(t),n,e)})),qa=he((function(n,t,r,e){le(t,Xu(t),n,e)})),$a=Te(Ot),Na=Lr((function(n,t){n=mi(n);var r=-1,e=t.length,u=e>2?t[2]:Z;for(u&&Je(t[0],t[1],u)&&(e=1);++r1),t})),le(n,Me(n),r),e&&(r=zt(r,7,Ce));for(var u=t.length;u--;)Vr(r,t[u]);return r})),Qa=Te((function(n,t){return null==n?{}:function(n,t){return Or(n,t,(function(t,r){return Qu(n,r)}))}(n,t)})),Xa=ze(Xu),nf=ze(ni),tf=_e((function(n,t,r){return t=t.toLowerCase(),n+(r?ei(t):t)})),rf=_e((function(n,t,r){return n+(r?"-":"")+t.toLowerCase()})),ef=_e((function(n,t,r){return n+(r?" ":"")+t.toLowerCase()})),uf=ge("toLowerCase"),of=_e((function(n,t,r){return n+(r?"_":"")+t.toLowerCase()})),af=_e((function(n,t,r){return n+(r?" ":"")+cf(t)})),ff=_e((function(n,t,r){return n+(r?" ":"")+t.toUpperCase()})),cf=ge("toUpperCase"),lf=Lr((function(n,t){try{return u(n,Z,t)}catch(n){return Lu(n)?n:new _i(n)}})),sf=Te((function(n,t){return o(t,(function(t){t=fu(t),kt(n,t,ya(n[t],n))})),n})),hf=be(),pf=be(!0),vf=Lr((function(n,t){return function(r){return nr(r,n,t)}})),gf=Lr((function(n,t){return function(r){return nr(n,r,t)}})),_f=Ie(h),df=Ie(f),yf=Ie(_),mf=Re(),bf=Re(!0),wf=Ae((function(n,t){return n+t}),0),xf=Ee("ceil"),Af=Ae((function(n,t){return n/t}),1),If=Ee("floor"),Wf=Ae((function(n,t){return n*t}),1),jf=Ee("round"),Rf=Ae((function(n,t){return n-t}),0);return r.after=function(n,t){if("function"!=typeof t)throw new xi(V);return n=Zu(n),function(){if(--n<1)return t.apply(this,arguments)}},r.ary=ju,r.assign=Ma,r.assignIn=Ua,r.assignInWith=Pa,r.assignWith=qa,r.at=$a,r.before=Ru,r.bind=ya,r.bindAll=sf,r.bindKey=ma,r.castArray=function(){if(!arguments.length)return[];var n=arguments[0];return Oa(n)?n:[n]},r.chain=wu,r.chunk=function(n,t,r){t=(r?Je(n,t,r):t===Z)?1:eo(Zu(t),0);var e=null==n?0:n.length;if(!e||t<1)return[];for(var u=0,i=0,o=vi(Ji(e/t));uu?0:u+r),(e=e===Z||e>u?u:Zu(e))<0&&(e+=u),e=r>e?0:Vu(e);r>>0)?(n=Ju(n))&&("string"==typeof t||null!=t&&!La(t))&&(!(t=Kr(t))&&F(n))?re($(n),0,r):n.split(t,r):[]},r.spread=function(n,t){if("function"!=typeof n)throw new xi(V);return t=null==t?0:eo(Zu(t),0),Lr((function(r){var e=r[t],i=re(r,0,t);return e&&p(i,e),u(n,this,i)}))},r.tail=function(n){var t=null==n?0:n.length;return t?Mr(n,1,t):[]},r.take=function(n,t,r){return n&&n.length?Mr(n,0,(t=r||t===Z?1:Zu(t))<0?0:t):[]},r.takeRight=function(n,t,r){var e=null==n?0:n.length;return e?Mr(n,(t=e-(t=r||t===Z?1:Zu(t)))<0?0:t,e):[]},r.takeRightWhile=function(n,t){return n&&n.length?Hr(n,qe(t,3),!1,!0):[]},r.takeWhile=function(n,t){return n&&n.length?Hr(n,qe(t,3)):[]},r.tap=function(n,t){return t(n),n},r.throttle=function(n,t,r){var e=!0,u=!0;if("function"!=typeof n)throw new xi(V);return Du(r)&&(e="leading"in r?!!r.leading:e,u="trailing"in r?!!r.trailing:u),ku(n,t,{leading:e,maxWait:t,trailing:u})},r.thru=xu,r.toArray=Nu,r.toPairs=Xa,r.toPairsIn=nf,r.toPath=function(n){return Oa(n)?h(n,fu):$u(n)?[n]:ce(No(Ju(n)))},r.toPlainObject=Hu,r.transform=function(n,t,r){var e=Oa(n),u=e||za(n)||Fa(n);if(t=qe(t,4),null==r){var i=n&&n.constructor;r=u?e?new i:[]:Du(n)&&Cu(i)?jo(Mi(n)):{}}return(u?o:Mt)(n,(function(n,e,u){return t(r,n,e,u)})),r},r.unary=function(n){return ju(n,1)},r.union=Xo,r.unionBy=na,r.unionWith=ta,r.uniq=function(n){return n&&n.length?Zr(n):[]},r.uniqBy=function(n,t){return n&&n.length?Zr(n,qe(t,2)):[]},r.uniqWith=function(n,t){return t="function"==typeof t?t:Z,n&&n.length?Zr(n,Z,t):[]},r.unset=function(n,t){return null==n||Vr(n,t)},r.unzip=mu,r.unzipWith=bu,r.update=function(n,t,r){return null==n?n:Gr(n,t,ne(r))},r.updateWith=function(n,t,r,e){return e="function"==typeof e?e:Z,null==n?n:Gr(n,t,ne(r),e)},r.values=ri,r.valuesIn=function(n){return null==n?[]:z(n,ni(n))},r.without=ra,r.words=ii,r.wrap=function(n,t){return Aa(ne(t),n)},r.xor=ea,r.xorBy=ua,r.xorWith=ia,r.zip=oa,r.zipObject=function(n,t){return Qr(n||[],t||[],It)},r.zipObjectDeep=function(n,t){return Qr(n||[],t||[],Tr)},r.zipWith=aa,r.entries=Xa,r.entriesIn=nf,r.extend=Ua,r.extendWith=Pa,ci(r,r),r.add=wf,r.attempt=lf,r.camelCase=tf,r.capitalize=ei,r.ceil=xf,r.clamp=function(n,t,r){return r===Z&&(r=t,t=Z),r!==Z&&(r=(r=Gu(r))==r?r:0),t!==Z&&(t=(t=Gu(t))==t?t:0),Et(Gu(n),t,r)},r.clone=function(n){return zt(n,4)},r.cloneDeep=function(n){return zt(n,5)},r.cloneDeepWith=function(n,t){return zt(n,5,t="function"==typeof t?t:Z)},r.cloneWith=function(n,t){return zt(n,4,t="function"==typeof t?t:Z)},r.conformsTo=function(n,t){return null==t||St(n,t,Xu(t))},r.deburr=ui,r.defaultTo=function(n,t){return null==n||n!=n?t:n},r.divide=Af,r.endsWith=function(n,t,r){n=Ju(n),t=Kr(t);var e=n.length,u=r=r===Z?e:Et(Zu(r),0,e);return(r-=t.length)>=0&&n.slice(r,u)==t},r.eq=zu,r.escape=function(n){return(n=Ju(n))&&qn.test(n)?n.replace(Un,mr):n},r.escapeRegExp=function(n){return(n=Ju(n))&&Jn.test(n)?n.replace(Hn,"\\$&"):n},r.every=function(n,t,r){var e=Oa(n)?f:Ct;return r&&Je(n,t,r)&&(t=Z),e(n,qe(t,3))},r.find=la,r.findIndex=hu,r.findKey=function(n,t){return y(n,qe(t,3),Mt)},r.findLast=sa,r.findLastIndex=pu,r.findLastKey=function(n,t){return y(n,qe(t,3),Ut)},r.floor=If,r.forEach=Au,r.forEachRight=Iu,r.forIn=function(n,t){return null==n?n:Oo(n,qe(t,3),ni)},r.forInRight=function(n,t){return null==n?n:Eo(n,qe(t,3),ni)},r.forOwn=function(n,t){return n&&Mt(n,qe(t,3))},r.forOwnRight=function(n,t){return n&&Ut(n,qe(t,3))},r.get=Yu,r.gt=ja,r.gte=Ra,r.has=function(n,t){return null!=n&&Ze(n,t,Gt)},r.hasIn=Qu,r.head=gu,r.identity=ai,r.includes=function(n,t,r,e){n=Su(n)?n:ri(n),r=r&&!e?Zu(r):0;var u=n.length;return r<0&&(r=eo(u+r,0)),qu(n)?r<=u&&n.indexOf(t,r)>-1:!!u&&b(n,t,r)>-1},r.indexOf=function(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=null==r?0:Zu(r);return u<0&&(u=eo(e+u,0)),b(n,t,u)},r.inRange=function(n,t,r){return t=Ku(t),r===Z?(r=t,t=0):r=Ku(r),function(n,t,r){return n>=uo(t,r)&&n=-rn&&n<=rn},r.isSet=Ca,r.isString=qu,r.isSymbol=$u,r.isTypedArray=Fa,r.isUndefined=function(n){return n===Z},r.isWeakMap=function(n){return Mu(n)&&Mo(n)==In},r.isWeakSet=function(n){return Mu(n)&&"[object WeakSet]"==Nt(n)},r.join=function(n,t){return null==n?"":to.call(n,t)},r.kebabCase=rf,r.last=_u,r.lastIndexOf=function(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=e;return r!==Z&&(u=(u=Zu(r))<0?eo(e+u,0):uo(u,e-1)),t==t?function(n,t,r){for(var e=r+1;e--;)if(n[e]===t)return e;return e}(n,t,u):m(n,x,u,!0)},r.lowerCase=ef,r.lowerFirst=uf,r.lt=Ta,r.lte=Da,r.max=function(n){return n&&n.length?Ft(n,ai,Vt):Z},r.maxBy=function(n,t){return n&&n.length?Ft(n,qe(t,2),Vt):Z},r.mean=function(n){return A(n,ai)},r.meanBy=function(n,t){return A(n,qe(t,2))},r.min=function(n){return n&&n.length?Ft(n,ai,xr):Z},r.minBy=function(n,t){return n&&n.length?Ft(n,qe(t,2),xr):Z},r.stubArray=hi,r.stubFalse=pi,r.stubObject=function(){return{}},r.stubString=function(){return""},r.stubTrue=function(){return!0},r.multiply=Wf,r.nth=function(n,t){return n&&n.length?Rr(n,Zu(t)):Z},r.noConflict=function(){return ir._===this&&(ir._=Bi),this},r.noop=li,r.now=da,r.pad=function(n,t,r){n=Ju(n);var e=(t=Zu(t))?q(n):0;if(!t||e>=t)return n;var u=(t-e)/2;return We(Yi(u),r)+n+We(Ji(u),r)},r.padEnd=function(n,t,r){n=Ju(n);var e=(t=Zu(t))?q(n):0;return t&&et){var e=n;n=t,t=e}if(r||n%1||t%1){var u=ao();return uo(n+u*(t-n+tr("1e-"+((u+"").length-1))),t)}return Sr(n,t)},r.reduce=function(n,t,r){var e=Oa(n)?v:j,u=arguments.length<3;return e(n,qe(t,4),r,u,Ro)},r.reduceRight=function(n,t,r){var e=Oa(n)?g:j,u=arguments.length<3;return e(n,qe(t,4),r,u,ko)},r.repeat=function(n,t,r){return t=(r?Je(n,t,r):t===Z)?1:Zu(t),Br(Ju(n),t)},r.replace=function(){var n=arguments,t=Ju(n[0]);return n.length<3?t:t.replace(n[1],n[2])},r.result=function(n,t,r){var e=-1,u=(t=te(t,n)).length;for(u||(u=1,n=Z);++ern)return[];var r=un,e=uo(n,un);t=qe(t),n-=un;for(var u=k(e,t);++r=i)return n;var a=r-q(e);if(a<1)return e;var f=o?re(o,0,a).join(""):n.slice(0,a);if(u===Z)return f+e;if(o&&(a+=f.length-a),La(u)){if(n.slice(a).search(u)){var c,l=f;for(u.global||(u=bi(u.source,Ju(ot.exec(u))+"g")),u.lastIndex=0;c=u.exec(l);)var s=c.index;f=f.slice(0,s===Z?a:s)}}else if(n.indexOf(Kr(u),a)!=a){var h=f.lastIndexOf(u);h>-1&&(f=f.slice(0,h))}return f+e},r.unescape=function(n){return(n=Ju(n))&&Pn.test(n)?n.replace(Mn,br):n},r.uniqueId=function(n){var t=++Oi;return Ju(n)+t},r.upperCase=ff,r.upperFirst=cf,r.each=Au,r.eachRight=Iu,r.first=gu,ci(r,function(){var n={};return Mt(r,(function(t,e){ki.call(r.prototype,e)||(n[e]=t)})),n}(),{chain:!1}),r.VERSION="4.18.1",o(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(n){r[n].placeholder=r})),o(["drop","take"],(function(n,t){Qn.prototype[n]=function(r){r=r===Z?1:eo(Zu(r),0);var e=this.__filtered__&&!t?new Qn(this):this.clone();return e.__filtered__?e.__takeCount__=uo(r,e.__takeCount__):e.__views__.push({size:uo(r,un),type:n+(e.__dir__<0?"Right":"")}),e},Qn.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}})),o(["filter","map","takeWhile"],(function(n,t){var r=t+1,e=1==r||3==r;Qn.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:qe(n,3),type:r}),t.__filtered__=t.__filtered__||e,t}})),o(["head","last"],(function(n,t){var r="take"+(t?"Right":"");Qn.prototype[n]=function(){return this[r](1).value()[0]}})),o(["initial","tail"],(function(n,t){var r="drop"+(t?"":"Right");Qn.prototype[n]=function(){return this.__filtered__?new Qn(this):this[r](1)}})),Qn.prototype.compact=function(){return this.filter(ai)},Qn.prototype.find=function(n){return this.filter(n).head()},Qn.prototype.findLast=function(n){return this.reverse().find(n)},Qn.prototype.invokeMap=Lr((function(n,t){return"function"==typeof n?new Qn(this):this.map((function(r){return nr(r,n,t)}))})),Qn.prototype.reject=function(n){return this.filter(Eu(qe(n)))},Qn.prototype.slice=function(n,t){n=Zu(n);var r=this;return r.__filtered__&&(n>0||t<0)?new Qn(r):(n<0?r=r.takeRight(-n):n&&(r=r.drop(n)),t!==Z&&(r=(t=Zu(t))<0?r.dropRight(-t):r.take(t-n)),r)},Qn.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},Qn.prototype.toArray=function(){return this.take(un)},Mt(Qn.prototype,(function(n,t){var e=/^(?:filter|find|map|reject)|While$/.test(t),u=/^(?:head|last)$/.test(t),i=r[u?"take"+("last"==t?"Right":""):t],o=u||/^find/.test(t);i&&(r.prototype[t]=function(){var t=this.__wrapped__,a=u?[1]:arguments,f=t instanceof Qn,c=a[0],l=f||Oa(t),s=function(n){var t=i.apply(r,p([n],a));return u&&h?t[0]:t};l&&e&&"function"==typeof c&&1!=c.length&&(f=l=!1);var h=this.__chain__,v=!!this.__actions__.length,g=o&&!h,_=f&&!v;if(!o&&l){t=_?t:new Qn(this);var d=n.apply(t,a);return d.__actions__.push({func:xu,args:[s],thisArg:Z}),new W(d,h)}return g&&_?n.apply(this,a):(d=this.thru(s),g?u?d.value()[0]:d.value():d)})})),o(["pop","push","shift","sort","splice","unshift"],(function(n){var t=Ai[n],e=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",u=/^(?:pop|shift)$/.test(n);r.prototype[n]=function(){var n=arguments;if(u&&!this.__chain__){var r=this.value();return t.apply(Oa(r)?r:[],n)}return this[e]((function(r){return t.apply(Oa(r)?r:[],n)}))}})),Mt(Qn.prototype,(function(n,t){var e=r[t];if(e){var u=e.name+"";ki.call(_o,u)||(_o[u]=[]),_o[u].push({name:t,func:e})}})),_o[we(Z,2).name]=[{name:"wrapper",func:Z}],Qn.prototype.clone=function(){var n=new Qn(this.__wrapped__);return n.__actions__=ce(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=ce(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=ce(this.__views__),n},Qn.prototype.reverse=function(){if(this.__filtered__){var n=new Qn(this);n.__dir__=-1,n.__filtered__=!0}else(n=this.clone()).__dir__*=-1;return n},Qn.prototype.value=function(){var n=this.__wrapped__.value(),t=this.__dir__,r=Oa(n),e=t<0,u=r?n.length:0,i=function(n,t,r){for(var e=-1,u=r.length;++e=this.__values__.length;return{done:n,value:n?Z:this.__values__[this.__index__++]}},r.prototype.plant=function(n){for(var t,r=this;r instanceof e;){var u=su(r);u.__index__=0,u.__values__=Z,t?i.__wrapped__=u:t=u;var i=u;r=r.__wrapped__}return i.__wrapped__=n,t},r.prototype.reverse=function(){var n=this.__wrapped__;if(n instanceof Qn){var t=n;return this.__actions__.length&&(t=new Qn(this)),(t=t.reverse()).__actions__.push({func:xu,args:[yu],thisArg:Z}),new W(t,this.__chain__)}return this.thru(yu)},r.prototype.toJSON=r.prototype.valueOf=r.prototype.value=function(){return Jr(this.__wrapped__,this.__actions__)},r.prototype.first=r.prototype.head,Ni&&(r.prototype[Ni]=function(){return this}),r}();ir._=wr,void 0===(e=function(){return wr}.call(t,r,t,n))||(n.exports=e)}.call(this)},6877(n,t,r){n.exports=r(4480)}},t={};function r(e){var u=t[e];if(void 0!==u)return u.exports;var i=t[e]={id:e,loaded:!1,exports:{}};return n[e].call(i.exports,i,i.exports,r),i.loaded=!0,i.exports}return r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(n){if("object"==typeof window)return window}}(),r.nmd=n=>(n.paths=[],n.children||(n.children=[]),n),r(6877)})())); \ No newline at end of file diff --git a/src/modules/Elsa.Expressions.JavaScript.Libraries/ClientLib/dist/moment.js b/src/modules/Elsa.Expressions.JavaScript.Libraries/ClientLib/dist/moment.js index 377cea4d1..10a5346e0 100644 --- a/src/modules/Elsa.Expressions.JavaScript.Libraries/ClientLib/dist/moment.js +++ b/src/modules/Elsa.Expressions.JavaScript.Libraries/ClientLib/dist/moment.js @@ -1,277 +1,277 @@ -!function(e,a){"object"==typeof exports&&"object"==typeof module?module.exports=a():"function"==typeof define&&define.amd?define([],a):"object"==typeof exports?exports.moment=a():e.moment=a()}(this,(()=>(()=>{var e={5177:function(e,a,t){!function(e){"use strict"; +!function(e,a){"object"==typeof exports&&"object"==typeof module?module.exports=a():"function"==typeof define&&define.amd?define([],a):"object"==typeof exports?exports.moment=a():e.moment=a()}(this,(()=>(()=>{var e={5177(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("af",{months:"Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Oktober_November_Desember".split("_"),monthsShort:"Jan_Feb_Mrt_Apr_Mei_Jun_Jul_Aug_Sep_Okt_Nov_Des".split("_"),weekdays:"Sondag_Maandag_Dinsdag_Woensdag_Donderdag_Vrydag_Saterdag".split("_"),weekdaysShort:"Son_Maa_Din_Woe_Don_Vry_Sat".split("_"),weekdaysMin:"So_Ma_Di_Wo_Do_Vr_Sa".split("_"),meridiemParse:/vm|nm/i,isPM:function(e){return/^nm$/i.test(e)},meridiem:function(e,a,t){return e<12?t?"vm":"VM":t?"nm":"NM"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Vandag om] LT",nextDay:"[Môre om] LT",nextWeek:"dddd [om] LT",lastDay:"[Gister om] LT",lastWeek:"[Laas] dddd [om] LT",sameElse:"L"},relativeTime:{future:"oor %s",past:"%s gelede",s:"'n paar sekondes",ss:"%d sekondes",m:"'n minuut",mm:"%d minute",h:"'n uur",hh:"%d ure",d:"'n dag",dd:"%d dae",M:"'n maand",MM:"%d maande",y:"'n jaar",yy:"%d jaar"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})}(t(5093))},1488:function(e,a,t){!function(e){"use strict"; +e.defineLocale("af",{months:"Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Oktober_November_Desember".split("_"),monthsShort:"Jan_Feb_Mrt_Apr_Mei_Jun_Jul_Aug_Sep_Okt_Nov_Des".split("_"),weekdays:"Sondag_Maandag_Dinsdag_Woensdag_Donderdag_Vrydag_Saterdag".split("_"),weekdaysShort:"Son_Maa_Din_Woe_Don_Vry_Sat".split("_"),weekdaysMin:"So_Ma_Di_Wo_Do_Vr_Sa".split("_"),meridiemParse:/vm|nm/i,isPM:function(e){return/^nm$/i.test(e)},meridiem:function(e,a,t){return e<12?t?"vm":"VM":t?"nm":"NM"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Vandag om] LT",nextDay:"[Môre om] LT",nextWeek:"dddd [om] LT",lastDay:"[Gister om] LT",lastWeek:"[Laas] dddd [om] LT",sameElse:"L"},relativeTime:{future:"oor %s",past:"%s gelede",s:"'n paar sekondes",ss:"%d sekondes",m:"'n minuut",mm:"%d minute",h:"'n uur",hh:"%d ure",d:"'n dag",dd:"%d dae",M:"'n maand",MM:"%d maande",y:"'n jaar",yy:"%d jaar"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})}(t(5093))},1488(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a=function(e){return 0===e?0:1===e?1:2===e?2:e%100>=3&&e%100<=10?3:e%100>=11?4:5},t={s:["أقل من ثانية","ثانية واحدة",["ثانيتان","ثانيتين"],"%d ثوان","%d ثانية","%d ثانية"],m:["أقل من دقيقة","دقيقة واحدة",["دقيقتان","دقيقتين"],"%d دقائق","%d دقيقة","%d دقيقة"],h:["أقل من ساعة","ساعة واحدة",["ساعتان","ساعتين"],"%d ساعات","%d ساعة","%d ساعة"],d:["أقل من يوم","يوم واحد",["يومان","يومين"],"%d أيام","%d يومًا","%d يوم"],M:["أقل من شهر","شهر واحد",["شهران","شهرين"],"%d أشهر","%d شهرا","%d شهر"],y:["أقل من عام","عام واحد",["عامان","عامين"],"%d أعوام","%d عامًا","%d عام"]},s=function(e){return function(s,n,r,i){var d=a(s),_=t[e][a(s)];return 2===d&&(_=_[n?0:1]),_.replace(/%d/i,s)}},n=["جانفي","فيفري","مارس","أفريل","ماي","جوان","جويلية","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر"];e.defineLocale("ar-dz",{months:n,monthsShort:n,weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/‏M/‏YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(e){return"م"===e},meridiem:function(e,a,t){return e<12?"ص":"م"},calendar:{sameDay:"[اليوم عند الساعة] LT",nextDay:"[غدًا عند الساعة] LT",nextWeek:"dddd [عند الساعة] LT",lastDay:"[أمس عند الساعة] LT",lastWeek:"dddd [عند الساعة] LT",sameElse:"L"},relativeTime:{future:"بعد %s",past:"منذ %s",s:s("s"),ss:s("s"),m:s("m"),mm:s("m"),h:s("h"),hh:s("h"),d:s("d"),dd:s("d"),M:s("M"),MM:s("M"),y:s("y"),yy:s("y")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:0,doy:4}})}(t(5093))},8676:function(e,a,t){!function(e){"use strict"; +var a=function(e){return 0===e?0:1===e?1:2===e?2:e%100>=3&&e%100<=10?3:e%100>=11?4:5},t={s:["أقل من ثانية","ثانية واحدة",["ثانيتان","ثانيتين"],"%d ثوان","%d ثانية","%d ثانية"],m:["أقل من دقيقة","دقيقة واحدة",["دقيقتان","دقيقتين"],"%d دقائق","%d دقيقة","%d دقيقة"],h:["أقل من ساعة","ساعة واحدة",["ساعتان","ساعتين"],"%d ساعات","%d ساعة","%d ساعة"],d:["أقل من يوم","يوم واحد",["يومان","يومين"],"%d أيام","%d يومًا","%d يوم"],M:["أقل من شهر","شهر واحد",["شهران","شهرين"],"%d أشهر","%d شهرا","%d شهر"],y:["أقل من عام","عام واحد",["عامان","عامين"],"%d أعوام","%d عامًا","%d عام"]},s=function(e){return function(s,n,r,d){var i=a(s),_=t[e][a(s)];return 2===i&&(_=_[n?0:1]),_.replace(/%d/i,s)}},n=["جانفي","فيفري","مارس","أفريل","ماي","جوان","جويلية","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر"];e.defineLocale("ar-dz",{months:n,monthsShort:n,weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/‏M/‏YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(e){return"م"===e},meridiem:function(e,a,t){return e<12?"ص":"م"},calendar:{sameDay:"[اليوم عند الساعة] LT",nextDay:"[غدًا عند الساعة] LT",nextWeek:"dddd [عند الساعة] LT",lastDay:"[أمس عند الساعة] LT",lastWeek:"dddd [عند الساعة] LT",sameElse:"L"},relativeTime:{future:"بعد %s",past:"منذ %s",s:s("s"),ss:s("s"),m:s("m"),mm:s("m"),h:s("h"),hh:s("h"),d:s("d"),dd:s("d"),M:s("M"),MM:s("M"),y:s("y"),yy:s("y")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:0,doy:4}})}(t(5093))},8676(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("ar-kw",{months:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),monthsShort:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),weekdays:"الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",ss:"%d ثانية",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},week:{dow:0,doy:12}})}(t(5093))},2353:function(e,a,t){!function(e){"use strict"; +e.defineLocale("ar-kw",{months:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),monthsShort:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),weekdays:"الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",ss:"%d ثانية",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},week:{dow:0,doy:12}})}(t(5093))},2353(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",0:"0"},t=function(e){return 0===e?0:1===e?1:2===e?2:e%100>=3&&e%100<=10?3:e%100>=11?4:5},s={s:["أقل من ثانية","ثانية واحدة",["ثانيتان","ثانيتين"],"%d ثوان","%d ثانية","%d ثانية"],m:["أقل من دقيقة","دقيقة واحدة",["دقيقتان","دقيقتين"],"%d دقائق","%d دقيقة","%d دقيقة"],h:["أقل من ساعة","ساعة واحدة",["ساعتان","ساعتين"],"%d ساعات","%d ساعة","%d ساعة"],d:["أقل من يوم","يوم واحد",["يومان","يومين"],"%d أيام","%d يومًا","%d يوم"],M:["أقل من شهر","شهر واحد",["شهران","شهرين"],"%d أشهر","%d شهرا","%d شهر"],y:["أقل من عام","عام واحد",["عامان","عامين"],"%d أعوام","%d عامًا","%d عام"]},n=function(e){return function(a,n,r,i){var d=t(a),_=s[e][t(a)];return 2===d&&(_=_[n?0:1]),_.replace(/%d/i,a)}},r=["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر"];e.defineLocale("ar-ly",{months:r,monthsShort:r,weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/‏M/‏YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(e){return"م"===e},meridiem:function(e,a,t){return e<12?"ص":"م"},calendar:{sameDay:"[اليوم عند الساعة] LT",nextDay:"[غدًا عند الساعة] LT",nextWeek:"dddd [عند الساعة] LT",lastDay:"[أمس عند الساعة] LT",lastWeek:"dddd [عند الساعة] LT",sameElse:"L"},relativeTime:{future:"بعد %s",past:"منذ %s",s:n("s"),ss:n("s"),m:n("m"),mm:n("m"),h:n("h"),hh:n("h"),d:n("d"),dd:n("d"),M:n("M"),MM:n("M"),y:n("y"),yy:n("y")},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]})).replace(/,/g,"،")},week:{dow:6,doy:12}})}(t(5093))},4496:function(e,a,t){!function(e){"use strict"; +var a={1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",0:"0"},t=function(e){return 0===e?0:1===e?1:2===e?2:e%100>=3&&e%100<=10?3:e%100>=11?4:5},s={s:["أقل من ثانية","ثانية واحدة",["ثانيتان","ثانيتين"],"%d ثوان","%d ثانية","%d ثانية"],m:["أقل من دقيقة","دقيقة واحدة",["دقيقتان","دقيقتين"],"%d دقائق","%d دقيقة","%d دقيقة"],h:["أقل من ساعة","ساعة واحدة",["ساعتان","ساعتين"],"%d ساعات","%d ساعة","%d ساعة"],d:["أقل من يوم","يوم واحد",["يومان","يومين"],"%d أيام","%d يومًا","%d يوم"],M:["أقل من شهر","شهر واحد",["شهران","شهرين"],"%d أشهر","%d شهرا","%d شهر"],y:["أقل من عام","عام واحد",["عامان","عامين"],"%d أعوام","%d عامًا","%d عام"]},n=function(e){return function(a,n,r,d){var i=t(a),_=s[e][t(a)];return 2===i&&(_=_[n?0:1]),_.replace(/%d/i,a)}},r=["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر"];e.defineLocale("ar-ly",{months:r,monthsShort:r,weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/‏M/‏YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(e){return"م"===e},meridiem:function(e,a,t){return e<12?"ص":"م"},calendar:{sameDay:"[اليوم عند الساعة] LT",nextDay:"[غدًا عند الساعة] LT",nextWeek:"dddd [عند الساعة] LT",lastDay:"[أمس عند الساعة] LT",lastWeek:"dddd [عند الساعة] LT",sameElse:"L"},relativeTime:{future:"بعد %s",past:"منذ %s",s:n("s"),ss:n("s"),m:n("m"),mm:n("m"),h:n("h"),hh:n("h"),d:n("d"),dd:n("d"),M:n("M"),MM:n("M"),y:n("y"),yy:n("y")},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]})).replace(/,/g,"،")},week:{dow:6,doy:12}})}(t(5093))},4496(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("ar-ma",{months:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),monthsShort:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"احد_اثنين_ثلاثاء_اربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",ss:"%d ثانية",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},week:{dow:1,doy:4}})}(t(5093))},6947:function(e,a,t){!function(e){"use strict"; +e.defineLocale("ar-ma",{months:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),monthsShort:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"احد_اثنين_ثلاثاء_اربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",ss:"%d ثانية",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},week:{dow:1,doy:4}})}(t(5093))},6947(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"١",2:"٢",3:"٣",4:"٤",5:"٥",6:"٦",7:"٧",8:"٨",9:"٩",0:"٠"},t={"١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","٠":"0"};e.defineLocale("ar-ps",{months:"كانون الثاني_شباط_آذار_نيسان_أيّار_حزيران_تمّوز_آب_أيلول_تشري الأوّل_تشرين الثاني_كانون الأوّل".split("_"),monthsShort:"ك٢_شباط_آذار_نيسان_أيّار_حزيران_تمّوز_آب_أيلول_ت١_ت٢_ك١".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(e){return"م"===e},meridiem:function(e,a,t){return e<12?"ص":"م"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",ss:"%d ثانية",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},preparse:function(e){return e.replace(/[٣٤٥٦٧٨٩٠]/g,(function(e){return t[e]})).split("").reverse().join("").replace(/[١٢](?![\u062a\u0643])/g,(function(e){return t[e]})).split("").reverse().join("").replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]})).replace(/,/g,"،")},week:{dow:0,doy:6}})}(t(5093))},2682:function(e,a,t){!function(e){"use strict"; +var a={1:"١",2:"٢",3:"٣",4:"٤",5:"٥",6:"٦",7:"٧",8:"٨",9:"٩",0:"٠"},t={"١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","٠":"0"};e.defineLocale("ar-ps",{months:"كانون الثاني_شباط_آذار_نيسان_أيّار_حزيران_تمّوز_آب_أيلول_تشري الأوّل_تشرين الثاني_كانون الأوّل".split("_"),monthsShort:"ك٢_شباط_آذار_نيسان_أيّار_حزيران_تمّوز_آب_أيلول_ت١_ت٢_ك١".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(e){return"م"===e},meridiem:function(e,a,t){return e<12?"ص":"م"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",ss:"%d ثانية",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},preparse:function(e){return e.replace(/[٣٤٥٦٧٨٩٠]/g,(function(e){return t[e]})).split("").reverse().join("").replace(/[١٢](?![\u062a\u0643])/g,(function(e){return t[e]})).split("").reverse().join("").replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]})).replace(/,/g,"،")},week:{dow:0,doy:6}})}(t(5093))},2682(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"١",2:"٢",3:"٣",4:"٤",5:"٥",6:"٦",7:"٧",8:"٨",9:"٩",0:"٠"},t={"١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","٠":"0"};e.defineLocale("ar-sa",{months:"يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),monthsShort:"يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(e){return"م"===e},meridiem:function(e,a,t){return e<12?"ص":"م"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",ss:"%d ثانية",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},preparse:function(e){return e.replace(/[١٢٣٤٥٦٧٨٩٠]/g,(function(e){return t[e]})).replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]})).replace(/,/g,"،")},week:{dow:0,doy:6}})}(t(5093))},9756:function(e,a,t){!function(e){"use strict"; +var a={1:"١",2:"٢",3:"٣",4:"٤",5:"٥",6:"٦",7:"٧",8:"٨",9:"٩",0:"٠"},t={"١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","٠":"0"};e.defineLocale("ar-sa",{months:"يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),monthsShort:"يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(e){return"م"===e},meridiem:function(e,a,t){return e<12?"ص":"م"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",ss:"%d ثانية",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},preparse:function(e){return e.replace(/[١٢٣٤٥٦٧٨٩٠]/g,(function(e){return t[e]})).replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]})).replace(/,/g,"،")},week:{dow:0,doy:6}})}(t(5093))},9756(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("ar-tn",{months:"جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),monthsShort:"جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",ss:"%d ثانية",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},week:{dow:1,doy:4}})}(t(5093))},1509:function(e,a,t){!function(e){"use strict"; +e.defineLocale("ar-tn",{months:"جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),monthsShort:"جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",ss:"%d ثانية",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},week:{dow:1,doy:4}})}(t(5093))},1509(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"١",2:"٢",3:"٣",4:"٤",5:"٥",6:"٦",7:"٧",8:"٨",9:"٩",0:"٠"},t={"١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","٠":"0"},s=function(e){return 0===e?0:1===e?1:2===e?2:e%100>=3&&e%100<=10?3:e%100>=11?4:5},n={s:["أقل من ثانية","ثانية واحدة",["ثانيتان","ثانيتين"],"%d ثوان","%d ثانية","%d ثانية"],m:["أقل من دقيقة","دقيقة واحدة",["دقيقتان","دقيقتين"],"%d دقائق","%d دقيقة","%d دقيقة"],h:["أقل من ساعة","ساعة واحدة",["ساعتان","ساعتين"],"%d ساعات","%d ساعة","%d ساعة"],d:["أقل من يوم","يوم واحد",["يومان","يومين"],"%d أيام","%d يومًا","%d يوم"],M:["أقل من شهر","شهر واحد",["شهران","شهرين"],"%d أشهر","%d شهرا","%d شهر"],y:["أقل من عام","عام واحد",["عامان","عامين"],"%d أعوام","%d عامًا","%d عام"]},r=function(e){return function(a,t,r,i){var d=s(a),_=n[e][s(a)];return 2===d&&(_=_[t?0:1]),_.replace(/%d/i,a)}},i=["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر"];e.defineLocale("ar",{months:i,monthsShort:i,weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/‏M/‏YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(e){return"م"===e},meridiem:function(e,a,t){return e<12?"ص":"م"},calendar:{sameDay:"[اليوم عند الساعة] LT",nextDay:"[غدًا عند الساعة] LT",nextWeek:"dddd [عند الساعة] LT",lastDay:"[أمس عند الساعة] LT",lastWeek:"dddd [عند الساعة] LT",sameElse:"L"},relativeTime:{future:"بعد %s",past:"منذ %s",s:r("s"),ss:r("s"),m:r("m"),mm:r("m"),h:r("h"),hh:r("h"),d:r("d"),dd:r("d"),M:r("M"),MM:r("M"),y:r("y"),yy:r("y")},preparse:function(e){return e.replace(/[١٢٣٤٥٦٧٨٩٠]/g,(function(e){return t[e]})).replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]})).replace(/,/g,"،")},week:{dow:6,doy:12}})}(t(5093))},5533:function(e,a,t){!function(e){"use strict"; +var a={1:"١",2:"٢",3:"٣",4:"٤",5:"٥",6:"٦",7:"٧",8:"٨",9:"٩",0:"٠"},t={"١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","٠":"0"},s=function(e){return 0===e?0:1===e?1:2===e?2:e%100>=3&&e%100<=10?3:e%100>=11?4:5},n={s:["أقل من ثانية","ثانية واحدة",["ثانيتان","ثانيتين"],"%d ثوان","%d ثانية","%d ثانية"],m:["أقل من دقيقة","دقيقة واحدة",["دقيقتان","دقيقتين"],"%d دقائق","%d دقيقة","%d دقيقة"],h:["أقل من ساعة","ساعة واحدة",["ساعتان","ساعتين"],"%d ساعات","%d ساعة","%d ساعة"],d:["أقل من يوم","يوم واحد",["يومان","يومين"],"%d أيام","%d يومًا","%d يوم"],M:["أقل من شهر","شهر واحد",["شهران","شهرين"],"%d أشهر","%d شهرا","%d شهر"],y:["أقل من عام","عام واحد",["عامان","عامين"],"%d أعوام","%d عامًا","%d عام"]},r=function(e){return function(a,t,r,d){var i=s(a),_=n[e][s(a)];return 2===i&&(_=_[t?0:1]),_.replace(/%d/i,a)}},d=["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر"];e.defineLocale("ar",{months:d,monthsShort:d,weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/‏M/‏YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(e){return"م"===e},meridiem:function(e,a,t){return e<12?"ص":"م"},calendar:{sameDay:"[اليوم عند الساعة] LT",nextDay:"[غدًا عند الساعة] LT",nextWeek:"dddd [عند الساعة] LT",lastDay:"[أمس عند الساعة] LT",lastWeek:"dddd [عند الساعة] LT",sameElse:"L"},relativeTime:{future:"بعد %s",past:"منذ %s",s:r("s"),ss:r("s"),m:r("m"),mm:r("m"),h:r("h"),hh:r("h"),d:r("d"),dd:r("d"),M:r("M"),MM:r("M"),y:r("y"),yy:r("y")},preparse:function(e){return e.replace(/[١٢٣٤٥٦٧٨٩٠]/g,(function(e){return t[e]})).replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]})).replace(/,/g,"،")},week:{dow:6,doy:12}})}(t(5093))},5533(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"-inci",5:"-inci",8:"-inci",70:"-inci",80:"-inci",2:"-nci",7:"-nci",20:"-nci",50:"-nci",3:"-üncü",4:"-üncü",100:"-üncü",6:"-ncı",9:"-uncu",10:"-uncu",30:"-uncu",60:"-ıncı",90:"-ıncı"};e.defineLocale("az",{months:"yanvar_fevral_mart_aprel_may_iyun_iyul_avqust_sentyabr_oktyabr_noyabr_dekabr".split("_"),monthsShort:"yan_fev_mar_apr_may_iyn_iyl_avq_sen_okt_noy_dek".split("_"),weekdays:"Bazar_Bazar ertəsi_Çərşənbə axşamı_Çərşənbə_Cümə axşamı_Cümə_Şənbə".split("_"),weekdaysShort:"Baz_BzE_ÇAx_Çər_CAx_Cüm_Şən".split("_"),weekdaysMin:"Bz_BE_ÇA_Çə_CA_Cü_Şə".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bugün saat] LT",nextDay:"[sabah saat] LT",nextWeek:"[gələn həftə] dddd [saat] LT",lastDay:"[dünən] LT",lastWeek:"[keçən həftə] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s sonra",past:"%s əvvəl",s:"bir neçə saniyə",ss:"%d saniyə",m:"bir dəqiqə",mm:"%d dəqiqə",h:"bir saat",hh:"%d saat",d:"bir gün",dd:"%d gün",M:"bir ay",MM:"%d ay",y:"bir il",yy:"%d il"},meridiemParse:/gecə|səhər|gündüz|axşam/,isPM:function(e){return/^(gündüz|axşam)$/.test(e)},meridiem:function(e,a,t){return e<4?"gecə":e<12?"səhər":e<17?"gündüz":"axşam"},dayOfMonthOrdinalParse:/\d{1,2}-(ıncı|inci|nci|üncü|ncı|uncu)/,ordinal:function(e){if(0===e)return e+"-ıncı";var t=e%10,s=e%100-t,n=e>=100?100:null;return e+(a[t]||a[s]||a[n])},week:{dow:1,doy:7}})}(t(5093))},8959:function(e,a,t){!function(e){"use strict"; +var a={1:"-inci",5:"-inci",8:"-inci",70:"-inci",80:"-inci",2:"-nci",7:"-nci",20:"-nci",50:"-nci",3:"-üncü",4:"-üncü",100:"-üncü",6:"-ncı",9:"-uncu",10:"-uncu",30:"-uncu",60:"-ıncı",90:"-ıncı"};e.defineLocale("az",{months:"yanvar_fevral_mart_aprel_may_iyun_iyul_avqust_sentyabr_oktyabr_noyabr_dekabr".split("_"),monthsShort:"yan_fev_mar_apr_may_iyn_iyl_avq_sen_okt_noy_dek".split("_"),weekdays:"Bazar_Bazar ertəsi_Çərşənbə axşamı_Çərşənbə_Cümə axşamı_Cümə_Şənbə".split("_"),weekdaysShort:"Baz_BzE_ÇAx_Çər_CAx_Cüm_Şən".split("_"),weekdaysMin:"Bz_BE_ÇA_Çə_CA_Cü_Şə".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bugün saat] LT",nextDay:"[sabah saat] LT",nextWeek:"[gələn həftə] dddd [saat] LT",lastDay:"[dünən] LT",lastWeek:"[keçən həftə] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s sonra",past:"%s əvvəl",s:"bir neçə saniyə",ss:"%d saniyə",m:"bir dəqiqə",mm:"%d dəqiqə",h:"bir saat",hh:"%d saat",d:"bir gün",dd:"%d gün",M:"bir ay",MM:"%d ay",y:"bir il",yy:"%d il"},meridiemParse:/gecə|səhər|gündüz|axşam/,isPM:function(e){return/^(gündüz|axşam)$/.test(e)},meridiem:function(e,a,t){return e<4?"gecə":e<12?"səhər":e<17?"gündüz":"axşam"},dayOfMonthOrdinalParse:/\d{1,2}-(ıncı|inci|nci|üncü|ncı|uncu)/,ordinal:function(e){if(0===e)return e+"-ıncı";var t=e%10,s=e%100-t,n=e>=100?100:null;return e+(a[t]||a[s]||a[n])},week:{dow:1,doy:7}})}(t(5093))},8959(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e,a){var t=e.split("_");return a%10==1&&a%100!=11?t[0]:a%10>=2&&a%10<=4&&(a%100<10||a%100>=20)?t[1]:t[2]}function t(e,t,s){return"m"===s?t?"хвіліна":"хвіліну":"h"===s?t?"гадзіна":"гадзіну":e+" "+a({ss:t?"секунда_секунды_секунд":"секунду_секунды_секунд",mm:t?"хвіліна_хвіліны_хвілін":"хвіліну_хвіліны_хвілін",hh:t?"гадзіна_гадзіны_гадзін":"гадзіну_гадзіны_гадзін",dd:"дзень_дні_дзён",MM:"месяц_месяцы_месяцаў",yy:"год_гады_гадоў"}[s],+e)}e.defineLocale("be",{months:{format:"студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня".split("_"),standalone:"студзень_люты_сакавік_красавік_травень_чэрвень_ліпень_жнівень_верасень_кастрычнік_лістапад_снежань".split("_")},monthsShort:"студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж".split("_"),weekdays:{format:"нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу".split("_"),standalone:"нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота".split("_"),isFormat:/\[ ?[Ууў] ?(?:мінулую|наступную)? ?\] ?dddd/},weekdaysShort:"нд_пн_ат_ср_чц_пт_сб".split("_"),weekdaysMin:"нд_пн_ат_ср_чц_пт_сб".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY г.",LLL:"D MMMM YYYY г., HH:mm",LLLL:"dddd, D MMMM YYYY г., HH:mm"},calendar:{sameDay:"[Сёння ў] LT",nextDay:"[Заўтра ў] LT",lastDay:"[Учора ў] LT",nextWeek:function(){return"[У] dddd [ў] LT"},lastWeek:function(){switch(this.day()){case 0:case 3:case 5:case 6:return"[У мінулую] dddd [ў] LT";case 1:case 2:case 4:return"[У мінулы] dddd [ў] LT"}},sameElse:"L"},relativeTime:{future:"праз %s",past:"%s таму",s:"некалькі секунд",m:t,mm:t,h:t,hh:t,d:"дзень",dd:t,M:"месяц",MM:t,y:"год",yy:t},meridiemParse:/ночы|раніцы|дня|вечара/,isPM:function(e){return/^(дня|вечара)$/.test(e)},meridiem:function(e,a,t){return e<4?"ночы":e<12?"раніцы":e<17?"дня":"вечара"},dayOfMonthOrdinalParse:/\d{1,2}-(і|ы|га)/,ordinal:function(e,a){switch(a){case"M":case"d":case"DDD":case"w":case"W":return e%10!=2&&e%10!=3||e%100==12||e%100==13?e+"-ы":e+"-і";case"D":return e+"-га";default:return e}},week:{dow:1,doy:7}})}(t(5093))},7777:function(e,a,t){!function(e){"use strict"; +function a(e,a){var t=e.split("_");return a%10==1&&a%100!=11?t[0]:a%10>=2&&a%10<=4&&(a%100<10||a%100>=20)?t[1]:t[2]}function t(e,t,s){return"m"===s?t?"хвіліна":"хвіліну":"h"===s?t?"гадзіна":"гадзіну":e+" "+a({ss:t?"секунда_секунды_секунд":"секунду_секунды_секунд",mm:t?"хвіліна_хвіліны_хвілін":"хвіліну_хвіліны_хвілін",hh:t?"гадзіна_гадзіны_гадзін":"гадзіну_гадзіны_гадзін",dd:"дзень_дні_дзён",MM:"месяц_месяцы_месяцаў",yy:"год_гады_гадоў"}[s],+e)}e.defineLocale("be",{months:{format:"студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня".split("_"),standalone:"студзень_люты_сакавік_красавік_травень_чэрвень_ліпень_жнівень_верасень_кастрычнік_лістапад_снежань".split("_")},monthsShort:"студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж".split("_"),weekdays:{format:"нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу".split("_"),standalone:"нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота".split("_"),isFormat:/\[ ?[Ууў] ?(?:мінулую|наступную)? ?\] ?dddd/},weekdaysShort:"нд_пн_ат_ср_чц_пт_сб".split("_"),weekdaysMin:"нд_пн_ат_ср_чц_пт_сб".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY г.",LLL:"D MMMM YYYY г., HH:mm",LLLL:"dddd, D MMMM YYYY г., HH:mm"},calendar:{sameDay:"[Сёння ў] LT",nextDay:"[Заўтра ў] LT",lastDay:"[Учора ў] LT",nextWeek:function(){return"[У] dddd [ў] LT"},lastWeek:function(){switch(this.day()){case 0:case 3:case 5:case 6:return"[У мінулую] dddd [ў] LT";case 1:case 2:case 4:return"[У мінулы] dddd [ў] LT"}},sameElse:"L"},relativeTime:{future:"праз %s",past:"%s таму",s:"некалькі секунд",m:t,mm:t,h:t,hh:t,d:"дзень",dd:t,M:"месяц",MM:t,y:"год",yy:t},meridiemParse:/ночы|раніцы|дня|вечара/,isPM:function(e){return/^(дня|вечара)$/.test(e)},meridiem:function(e,a,t){return e<4?"ночы":e<12?"раніцы":e<17?"дня":"вечара"},dayOfMonthOrdinalParse:/\d{1,2}-(і|ы|га)/,ordinal:function(e,a){switch(a){case"M":case"d":case"DDD":case"w":case"W":return e%10!=2&&e%10!=3||e%100==12||e%100==13?e+"-ы":e+"-і";case"D":return e+"-га";default:return e}},week:{dow:1,doy:7}})}(t(5093))},7777(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("bg",{months:"януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември".split("_"),monthsShort:"яну_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек".split("_"),weekdays:"неделя_понеделник_вторник_сряда_четвъртък_петък_събота".split("_"),weekdaysShort:"нед_пон_вто_сря_чет_пет_съб".split("_"),weekdaysMin:"нд_пн_вт_ср_чт_пт_сб".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[Днес в] LT",nextDay:"[Утре в] LT",nextWeek:"dddd [в] LT",lastDay:"[Вчера в] LT",lastWeek:function(){switch(this.day()){case 0:case 3:case 6:return"[Миналата] dddd [в] LT";case 1:case 2:case 4:case 5:return"[Миналия] dddd [в] LT"}},sameElse:"L"},relativeTime:{future:"след %s",past:"преди %s",s:"няколко секунди",ss:"%d секунди",m:"минута",mm:"%d минути",h:"час",hh:"%d часа",d:"ден",dd:"%d дена",w:"седмица",ww:"%d седмици",M:"месец",MM:"%d месеца",y:"година",yy:"%d години"},dayOfMonthOrdinalParse:/\d{1,2}-(ев|ен|ти|ви|ри|ми)/,ordinal:function(e){var a=e%10,t=e%100;return 0===e?e+"-ев":0===t?e+"-ен":t>10&&t<20?e+"-ти":1===a?e+"-ви":2===a?e+"-ри":7===a||8===a?e+"-ми":e+"-ти"},week:{dow:1,doy:7}})}(t(5093))},4903:function(e,a,t){!function(e){"use strict"; +e.defineLocale("bg",{months:"януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември".split("_"),monthsShort:"яну_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек".split("_"),weekdays:"неделя_понеделник_вторник_сряда_четвъртък_петък_събота".split("_"),weekdaysShort:"нед_пон_вто_сря_чет_пет_съб".split("_"),weekdaysMin:"нд_пн_вт_ср_чт_пт_сб".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[Днес в] LT",nextDay:"[Утре в] LT",nextWeek:"dddd [в] LT",lastDay:"[Вчера в] LT",lastWeek:function(){switch(this.day()){case 0:case 3:case 6:return"[Миналата] dddd [в] LT";case 1:case 2:case 4:case 5:return"[Миналия] dddd [в] LT"}},sameElse:"L"},relativeTime:{future:"след %s",past:"преди %s",s:"няколко секунди",ss:"%d секунди",m:"минута",mm:"%d минути",h:"час",hh:"%d часа",d:"ден",dd:"%d дена",w:"седмица",ww:"%d седмици",M:"месец",MM:"%d месеца",y:"година",yy:"%d години"},dayOfMonthOrdinalParse:/\d{1,2}-(ев|ен|ти|ви|ри|ми)/,ordinal:function(e){var a=e%10,t=e%100;return 0===e?e+"-ев":0===t?e+"-ен":t>10&&t<20?e+"-ти":1===a?e+"-ви":2===a?e+"-ри":7===a||8===a?e+"-ми":e+"-ти"},week:{dow:1,doy:7}})}(t(5093))},4903(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("bm",{months:"Zanwuyekalo_Fewuruyekalo_Marisikalo_Awirilikalo_Mɛkalo_Zuwɛnkalo_Zuluyekalo_Utikalo_Sɛtanburukalo_ɔkutɔburukalo_Nowanburukalo_Desanburukalo".split("_"),monthsShort:"Zan_Few_Mar_Awi_Mɛ_Zuw_Zul_Uti_Sɛt_ɔku_Now_Des".split("_"),weekdays:"Kari_Ntɛnɛn_Tarata_Araba_Alamisa_Juma_Sibiri".split("_"),weekdaysShort:"Kar_Ntɛ_Tar_Ara_Ala_Jum_Sib".split("_"),weekdaysMin:"Ka_Nt_Ta_Ar_Al_Ju_Si".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"MMMM [tile] D [san] YYYY",LLL:"MMMM [tile] D [san] YYYY [lɛrɛ] HH:mm",LLLL:"dddd MMMM [tile] D [san] YYYY [lɛrɛ] HH:mm"},calendar:{sameDay:"[Bi lɛrɛ] LT",nextDay:"[Sini lɛrɛ] LT",nextWeek:"dddd [don lɛrɛ] LT",lastDay:"[Kunu lɛrɛ] LT",lastWeek:"dddd [tɛmɛnen lɛrɛ] LT",sameElse:"L"},relativeTime:{future:"%s kɔnɔ",past:"a bɛ %s bɔ",s:"sanga dama dama",ss:"sekondi %d",m:"miniti kelen",mm:"miniti %d",h:"lɛrɛ kelen",hh:"lɛrɛ %d",d:"tile kelen",dd:"tile %d",M:"kalo kelen",MM:"kalo %d",y:"san kelen",yy:"san %d"},week:{dow:1,doy:4}})}(t(5093))},7357:function(e,a,t){!function(e){"use strict"; +e.defineLocale("bm",{months:"Zanwuyekalo_Fewuruyekalo_Marisikalo_Awirilikalo_Mɛkalo_Zuwɛnkalo_Zuluyekalo_Utikalo_Sɛtanburukalo_ɔkutɔburukalo_Nowanburukalo_Desanburukalo".split("_"),monthsShort:"Zan_Few_Mar_Awi_Mɛ_Zuw_Zul_Uti_Sɛt_ɔku_Now_Des".split("_"),weekdays:"Kari_Ntɛnɛn_Tarata_Araba_Alamisa_Juma_Sibiri".split("_"),weekdaysShort:"Kar_Ntɛ_Tar_Ara_Ala_Jum_Sib".split("_"),weekdaysMin:"Ka_Nt_Ta_Ar_Al_Ju_Si".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"MMMM [tile] D [san] YYYY",LLL:"MMMM [tile] D [san] YYYY [lɛrɛ] HH:mm",LLLL:"dddd MMMM [tile] D [san] YYYY [lɛrɛ] HH:mm"},calendar:{sameDay:"[Bi lɛrɛ] LT",nextDay:"[Sini lɛrɛ] LT",nextWeek:"dddd [don lɛrɛ] LT",lastDay:"[Kunu lɛrɛ] LT",lastWeek:"dddd [tɛmɛnen lɛrɛ] LT",sameElse:"L"},relativeTime:{future:"%s kɔnɔ",past:"a bɛ %s bɔ",s:"sanga dama dama",ss:"sekondi %d",m:"miniti kelen",mm:"miniti %d",h:"lɛrɛ kelen",hh:"lɛrɛ %d",d:"tile kelen",dd:"tile %d",M:"kalo kelen",MM:"kalo %d",y:"san kelen",yy:"san %d"},week:{dow:1,doy:4}})}(t(5093))},7357(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"১",2:"২",3:"৩",4:"৪",5:"৫",6:"৬",7:"৭",8:"৮",9:"৯",0:"০"},t={"১":"1","২":"2","৩":"3","৪":"4","৫":"5","৬":"6","৭":"7","৮":"8","৯":"9","০":"0"};e.defineLocale("bn-bd",{months:"জানুয়ারি_ফেব্রুয়ারি_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর".split("_"),monthsShort:"জানু_ফেব্রু_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্ট_অক্টো_নভে_ডিসে".split("_"),weekdays:"রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পতিবার_শুক্রবার_শনিবার".split("_"),weekdaysShort:"রবি_সোম_মঙ্গল_বুধ_বৃহস্পতি_শুক্র_শনি".split("_"),weekdaysMin:"রবি_সোম_মঙ্গল_বুধ_বৃহ_শুক্র_শনি".split("_"),longDateFormat:{LT:"A h:mm সময়",LTS:"A h:mm:ss সময়",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm সময়",LLLL:"dddd, D MMMM YYYY, A h:mm সময়"},calendar:{sameDay:"[আজ] LT",nextDay:"[আগামীকাল] LT",nextWeek:"dddd, LT",lastDay:"[গতকাল] LT",lastWeek:"[গত] dddd, LT",sameElse:"L"},relativeTime:{future:"%s পরে",past:"%s আগে",s:"কয়েক সেকেন্ড",ss:"%d সেকেন্ড",m:"এক মিনিট",mm:"%d মিনিট",h:"এক ঘন্টা",hh:"%d ঘন্টা",d:"এক দিন",dd:"%d দিন",M:"এক মাস",MM:"%d মাস",y:"এক বছর",yy:"%d বছর"},preparse:function(e){return e.replace(/[১২৩৪৫৬৭৮৯০]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/রাত|ভোর|সকাল|দুপুর|বিকাল|সন্ধ্যা|রাত/,meridiemHour:function(e,a){return 12===e&&(e=0),"রাত"===a?e<4?e:e+12:"ভোর"===a||"সকাল"===a?e:"দুপুর"===a?e>=3?e:e+12:"বিকাল"===a||"সন্ধ্যা"===a?e+12:void 0},meridiem:function(e,a,t){return e<4?"রাত":e<6?"ভোর":e<12?"সকাল":e<15?"দুপুর":e<18?"বিকাল":e<20?"সন্ধ্যা":"রাত"},week:{dow:0,doy:6}})}(t(5093))},1290:function(e,a,t){!function(e){"use strict"; +var a={1:"১",2:"২",3:"৩",4:"৪",5:"৫",6:"৬",7:"৭",8:"৮",9:"৯",0:"০"},t={"১":"1","২":"2","৩":"3","৪":"4","৫":"5","৬":"6","৭":"7","৮":"8","৯":"9","০":"0"};e.defineLocale("bn-bd",{months:"জানুয়ারি_ফেব্রুয়ারি_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর".split("_"),monthsShort:"জানু_ফেব্রু_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্ট_অক্টো_নভে_ডিসে".split("_"),weekdays:"রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পতিবার_শুক্রবার_শনিবার".split("_"),weekdaysShort:"রবি_সোম_মঙ্গল_বুধ_বৃহস্পতি_শুক্র_শনি".split("_"),weekdaysMin:"রবি_সোম_মঙ্গল_বুধ_বৃহ_শুক্র_শনি".split("_"),longDateFormat:{LT:"A h:mm সময়",LTS:"A h:mm:ss সময়",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm সময়",LLLL:"dddd, D MMMM YYYY, A h:mm সময়"},calendar:{sameDay:"[আজ] LT",nextDay:"[আগামীকাল] LT",nextWeek:"dddd, LT",lastDay:"[গতকাল] LT",lastWeek:"[গত] dddd, LT",sameElse:"L"},relativeTime:{future:"%s পরে",past:"%s আগে",s:"কয়েক সেকেন্ড",ss:"%d সেকেন্ড",m:"এক মিনিট",mm:"%d মিনিট",h:"এক ঘন্টা",hh:"%d ঘন্টা",d:"এক দিন",dd:"%d দিন",M:"এক মাস",MM:"%d মাস",y:"এক বছর",yy:"%d বছর"},preparse:function(e){return e.replace(/[১২৩৪৫৬৭৮৯০]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/রাত|ভোর|সকাল|দুপুর|বিকাল|সন্ধ্যা|রাত/,meridiemHour:function(e,a){return 12===e&&(e=0),"রাত"===a?e<4?e:e+12:"ভোর"===a||"সকাল"===a?e:"দুপুর"===a?e>=3?e:e+12:"বিকাল"===a||"সন্ধ্যা"===a?e+12:void 0},meridiem:function(e,a,t){return e<4?"রাত":e<6?"ভোর":e<12?"সকাল":e<15?"দুপুর":e<18?"বিকাল":e<20?"সন্ধ্যা":"রাত"},week:{dow:0,doy:6}})}(t(5093))},1290(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"১",2:"২",3:"৩",4:"৪",5:"৫",6:"৬",7:"৭",8:"৮",9:"৯",0:"০"},t={"১":"1","২":"2","৩":"3","৪":"4","৫":"5","৬":"6","৭":"7","৮":"8","৯":"9","০":"0"};e.defineLocale("bn",{months:"জানুয়ারি_ফেব্রুয়ারি_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর".split("_"),monthsShort:"জানু_ফেব্রু_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্ট_অক্টো_নভে_ডিসে".split("_"),weekdays:"রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পতিবার_শুক্রবার_শনিবার".split("_"),weekdaysShort:"রবি_সোম_মঙ্গল_বুধ_বৃহস্পতি_শুক্র_শনি".split("_"),weekdaysMin:"রবি_সোম_মঙ্গল_বুধ_বৃহ_শুক্র_শনি".split("_"),longDateFormat:{LT:"A h:mm সময়",LTS:"A h:mm:ss সময়",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm সময়",LLLL:"dddd, D MMMM YYYY, A h:mm সময়"},calendar:{sameDay:"[আজ] LT",nextDay:"[আগামীকাল] LT",nextWeek:"dddd, LT",lastDay:"[গতকাল] LT",lastWeek:"[গত] dddd, LT",sameElse:"L"},relativeTime:{future:"%s পরে",past:"%s আগে",s:"কয়েক সেকেন্ড",ss:"%d সেকেন্ড",m:"এক মিনিট",mm:"%d মিনিট",h:"এক ঘন্টা",hh:"%d ঘন্টা",d:"এক দিন",dd:"%d দিন",M:"এক মাস",MM:"%d মাস",y:"এক বছর",yy:"%d বছর"},preparse:function(e){return e.replace(/[১২৩৪৫৬৭৮৯০]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/রাত|সকাল|দুপুর|বিকাল|রাত/,meridiemHour:function(e,a){return 12===e&&(e=0),"রাত"===a&&e>=4||"দুপুর"===a&&e<5||"বিকাল"===a?e+12:e},meridiem:function(e,a,t){return e<4?"রাত":e<10?"সকাল":e<17?"দুপুর":e<20?"বিকাল":"রাত"},week:{dow:0,doy:6}})}(t(5093))},1545:function(e,a,t){!function(e){"use strict"; +var a={1:"১",2:"২",3:"৩",4:"৪",5:"৫",6:"৬",7:"৭",8:"৮",9:"৯",0:"০"},t={"১":"1","২":"2","৩":"3","৪":"4","৫":"5","৬":"6","৭":"7","৮":"8","৯":"9","০":"0"};e.defineLocale("bn",{months:"জানুয়ারি_ফেব্রুয়ারি_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর".split("_"),monthsShort:"জানু_ফেব্রু_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্ট_অক্টো_নভে_ডিসে".split("_"),weekdays:"রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পতিবার_শুক্রবার_শনিবার".split("_"),weekdaysShort:"রবি_সোম_মঙ্গল_বুধ_বৃহস্পতি_শুক্র_শনি".split("_"),weekdaysMin:"রবি_সোম_মঙ্গল_বুধ_বৃহ_শুক্র_শনি".split("_"),longDateFormat:{LT:"A h:mm সময়",LTS:"A h:mm:ss সময়",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm সময়",LLLL:"dddd, D MMMM YYYY, A h:mm সময়"},calendar:{sameDay:"[আজ] LT",nextDay:"[আগামীকাল] LT",nextWeek:"dddd, LT",lastDay:"[গতকাল] LT",lastWeek:"[গত] dddd, LT",sameElse:"L"},relativeTime:{future:"%s পরে",past:"%s আগে",s:"কয়েক সেকেন্ড",ss:"%d সেকেন্ড",m:"এক মিনিট",mm:"%d মিনিট",h:"এক ঘন্টা",hh:"%d ঘন্টা",d:"এক দিন",dd:"%d দিন",M:"এক মাস",MM:"%d মাস",y:"এক বছর",yy:"%d বছর"},preparse:function(e){return e.replace(/[১২৩৪৫৬৭৮৯০]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/রাত|সকাল|দুপুর|বিকাল|রাত/,meridiemHour:function(e,a){return 12===e&&(e=0),"রাত"===a&&e>=4||"দুপুর"===a&&e<5||"বিকাল"===a?e+12:e},meridiem:function(e,a,t){return e<4?"রাত":e<10?"সকাল":e<17?"দুপুর":e<20?"বিকাল":"রাত"},week:{dow:0,doy:6}})}(t(5093))},1545(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"༡",2:"༢",3:"༣",4:"༤",5:"༥",6:"༦",7:"༧",8:"༨",9:"༩",0:"༠"},t={"༡":"1","༢":"2","༣":"3","༤":"4","༥":"5","༦":"6","༧":"7","༨":"8","༩":"9","༠":"0"};e.defineLocale("bo",{months:"ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ".split("_"),monthsShort:"ཟླ་1_ཟླ་2_ཟླ་3_ཟླ་4_ཟླ་5_ཟླ་6_ཟླ་7_ཟླ་8_ཟླ་9_ཟླ་10_ཟླ་11_ཟླ་12".split("_"),monthsShortRegex:/^(ཟླ་\d{1,2})/,monthsParseExact:!0,weekdays:"གཟའ་ཉི་མ་_གཟའ་ཟླ་བ་_གཟའ་མིག་དམར་_གཟའ་ལྷག་པ་_གཟའ་ཕུར་བུ_གཟའ་པ་སངས་_གཟའ་སྤེན་པ་".split("_"),weekdaysShort:"ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་".split("_"),weekdaysMin:"ཉི_ཟླ_མིག_ལྷག_ཕུར_སངས_སྤེན".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[དི་རིང] LT",nextDay:"[སང་ཉིན] LT",nextWeek:"[བདུན་ཕྲག་རྗེས་མ], LT",lastDay:"[ཁ་སང] LT",lastWeek:"[བདུན་ཕྲག་མཐའ་མ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s ལ་",past:"%s སྔན་ལ",s:"ལམ་སང",ss:"%d སྐར་ཆ།",m:"སྐར་མ་གཅིག",mm:"%d སྐར་མ",h:"ཆུ་ཚོད་གཅིག",hh:"%d ཆུ་ཚོད",d:"ཉིན་གཅིག",dd:"%d ཉིན་",M:"ཟླ་བ་གཅིག",MM:"%d ཟླ་བ",y:"ལོ་གཅིག",yy:"%d ལོ"},preparse:function(e){return e.replace(/[༡༢༣༤༥༦༧༨༩༠]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/མཚན་མོ|ཞོགས་ཀས|ཉིན་གུང|དགོང་དག|མཚན་མོ/,meridiemHour:function(e,a){return 12===e&&(e=0),"མཚན་མོ"===a&&e>=4||"ཉིན་གུང"===a&&e<5||"དགོང་དག"===a?e+12:e},meridiem:function(e,a,t){return e<4?"མཚན་མོ":e<10?"ཞོགས་ཀས":e<17?"ཉིན་གུང":e<20?"དགོང་དག":"མཚན་མོ"},week:{dow:0,doy:6}})}(t(5093))},1470:function(e,a,t){!function(e){"use strict"; +var a={1:"༡",2:"༢",3:"༣",4:"༤",5:"༥",6:"༦",7:"༧",8:"༨",9:"༩",0:"༠"},t={"༡":"1","༢":"2","༣":"3","༤":"4","༥":"5","༦":"6","༧":"7","༨":"8","༩":"9","༠":"0"};e.defineLocale("bo",{months:"ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ".split("_"),monthsShort:"ཟླ་1_ཟླ་2_ཟླ་3_ཟླ་4_ཟླ་5_ཟླ་6_ཟླ་7_ཟླ་8_ཟླ་9_ཟླ་10_ཟླ་11_ཟླ་12".split("_"),monthsShortRegex:/^(ཟླ་\d{1,2})/,monthsParseExact:!0,weekdays:"གཟའ་ཉི་མ་_གཟའ་ཟླ་བ་_གཟའ་མིག་དམར་_གཟའ་ལྷག་པ་_གཟའ་ཕུར་བུ_གཟའ་པ་སངས་_གཟའ་སྤེན་པ་".split("_"),weekdaysShort:"ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་".split("_"),weekdaysMin:"ཉི_ཟླ_མིག_ལྷག_ཕུར_སངས_སྤེན".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[དི་རིང] LT",nextDay:"[སང་ཉིན] LT",nextWeek:"[བདུན་ཕྲག་རྗེས་མ], LT",lastDay:"[ཁ་སང] LT",lastWeek:"[བདུན་ཕྲག་མཐའ་མ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s ལ་",past:"%s སྔན་ལ",s:"ལམ་སང",ss:"%d སྐར་ཆ།",m:"སྐར་མ་གཅིག",mm:"%d སྐར་མ",h:"ཆུ་ཚོད་གཅིག",hh:"%d ཆུ་ཚོད",d:"ཉིན་གཅིག",dd:"%d ཉིན་",M:"ཟླ་བ་གཅིག",MM:"%d ཟླ་བ",y:"ལོ་གཅིག",yy:"%d ལོ"},preparse:function(e){return e.replace(/[༡༢༣༤༥༦༧༨༩༠]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/མཚན་མོ|ཞོགས་ཀས|ཉིན་གུང|དགོང་དག|མཚན་མོ/,meridiemHour:function(e,a){return 12===e&&(e=0),"མཚན་མོ"===a&&e>=4||"ཉིན་གུང"===a&&e<5||"དགོང་དག"===a?e+12:e},meridiem:function(e,a,t){return e<4?"མཚན་མོ":e<10?"ཞོགས་ཀས":e<17?"ཉིན་གུང":e<20?"དགོང་དག":"མཚན་མོ"},week:{dow:0,doy:6}})}(t(5093))},1470(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e,a,t){return e+" "+n({mm:"munutenn",MM:"miz",dd:"devezh"}[t],e)}function t(e){switch(s(e)){case 1:case 3:case 4:case 5:case 9:return e+" bloaz";default:return e+" vloaz"}}function s(e){return e>9?s(e%10):e}function n(e,a){return 2===a?r(e):e}function r(e){var a={m:"v",b:"v",d:"z"};return void 0===a[e.charAt(0)]?e:a[e.charAt(0)]+e.substring(1)}var i=[/^gen/i,/^c[ʼ\']hwe/i,/^meu/i,/^ebr/i,/^mae/i,/^(mez|eve)/i,/^gou/i,/^eos/i,/^gwe/i,/^her/i,/^du/i,/^ker/i],d=/^(genver|c[ʼ\']hwevrer|meurzh|ebrel|mae|mezheven|gouere|eost|gwengolo|here|du|kerzu|gen|c[ʼ\']hwe|meu|ebr|mae|eve|gou|eos|gwe|her|du|ker)/i,_=/^(genver|c[ʼ\']hwevrer|meurzh|ebrel|mae|mezheven|gouere|eost|gwengolo|here|du|kerzu)/i,o=/^(gen|c[ʼ\']hwe|meu|ebr|mae|eve|gou|eos|gwe|her|du|ker)/i,u=[/^sul/i,/^lun/i,/^meurzh/i,/^merc[ʼ\']her/i,/^yaou/i,/^gwener/i,/^sadorn/i],m=[/^Sul/i,/^Lun/i,/^Meu/i,/^Mer/i,/^Yao/i,/^Gwe/i,/^Sad/i],l=[/^Su/i,/^Lu/i,/^Me([^r]|$)/i,/^Mer/i,/^Ya/i,/^Gw/i,/^Sa/i];e.defineLocale("br",{months:"Genver_Cʼhwevrer_Meurzh_Ebrel_Mae_Mezheven_Gouere_Eost_Gwengolo_Here_Du_Kerzu".split("_"),monthsShort:"Gen_Cʼhwe_Meu_Ebr_Mae_Eve_Gou_Eos_Gwe_Her_Du_Ker".split("_"),weekdays:"Sul_Lun_Meurzh_Mercʼher_Yaou_Gwener_Sadorn".split("_"),weekdaysShort:"Sul_Lun_Meu_Mer_Yao_Gwe_Sad".split("_"),weekdaysMin:"Su_Lu_Me_Mer_Ya_Gw_Sa".split("_"),weekdaysParse:l,fullWeekdaysParse:u,shortWeekdaysParse:m,minWeekdaysParse:l,monthsRegex:d,monthsShortRegex:d,monthsStrictRegex:_,monthsShortStrictRegex:o,monthsParse:i,longMonthsParse:i,shortMonthsParse:i,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [a viz] MMMM YYYY",LLL:"D [a viz] MMMM YYYY HH:mm",LLLL:"dddd, D [a viz] MMMM YYYY HH:mm"},calendar:{sameDay:"[Hiziv da] LT",nextDay:"[Warcʼhoazh da] LT",nextWeek:"dddd [da] LT",lastDay:"[Decʼh da] LT",lastWeek:"dddd [paset da] LT",sameElse:"L"},relativeTime:{future:"a-benn %s",past:"%s ʼzo",s:"un nebeud segondennoù",ss:"%d eilenn",m:"ur vunutenn",mm:a,h:"un eur",hh:"%d eur",d:"un devezh",dd:a,M:"ur miz",MM:a,y:"ur bloaz",yy:t},dayOfMonthOrdinalParse:/\d{1,2}(añ|vet)/,ordinal:function(e){return e+(1===e?"añ":"vet")},week:{dow:1,doy:4},meridiemParse:/a.m.|g.m./,isPM:function(e){return"g.m."===e},meridiem:function(e,a,t){return e<12?"a.m.":"g.m."}})}(t(5093))},4429:function(e,a,t){!function(e){"use strict"; +function a(e,a,t){return e+" "+n({mm:"munutenn",MM:"miz",dd:"devezh"}[t],e)}function t(e){switch(s(e)){case 1:case 3:case 4:case 5:case 9:return e+" bloaz";default:return e+" vloaz"}}function s(e){return e>9?s(e%10):e}function n(e,a){return 2===a?r(e):e}function r(e){var a={m:"v",b:"v",d:"z"};return void 0===a[e.charAt(0)]?e:a[e.charAt(0)]+e.substring(1)}var d=[/^gen/i,/^c[ʼ\']hwe/i,/^meu/i,/^ebr/i,/^mae/i,/^(mez|eve)/i,/^gou/i,/^eos/i,/^gwe/i,/^her/i,/^du/i,/^ker/i],i=/^(genver|c[ʼ\']hwevrer|meurzh|ebrel|mae|mezheven|gouere|eost|gwengolo|here|du|kerzu|gen|c[ʼ\']hwe|meu|ebr|mae|eve|gou|eos|gwe|her|du|ker)/i,_=/^(genver|c[ʼ\']hwevrer|meurzh|ebrel|mae|mezheven|gouere|eost|gwengolo|here|du|kerzu)/i,o=/^(gen|c[ʼ\']hwe|meu|ebr|mae|eve|gou|eos|gwe|her|du|ker)/i,m=[/^sul/i,/^lun/i,/^meurzh/i,/^merc[ʼ\']her/i,/^yaou/i,/^gwener/i,/^sadorn/i],u=[/^Sul/i,/^Lun/i,/^Meu/i,/^Mer/i,/^Yao/i,/^Gwe/i,/^Sad/i],l=[/^Su/i,/^Lu/i,/^Me([^r]|$)/i,/^Mer/i,/^Ya/i,/^Gw/i,/^Sa/i];e.defineLocale("br",{months:"Genver_Cʼhwevrer_Meurzh_Ebrel_Mae_Mezheven_Gouere_Eost_Gwengolo_Here_Du_Kerzu".split("_"),monthsShort:"Gen_Cʼhwe_Meu_Ebr_Mae_Eve_Gou_Eos_Gwe_Her_Du_Ker".split("_"),weekdays:"Sul_Lun_Meurzh_Mercʼher_Yaou_Gwener_Sadorn".split("_"),weekdaysShort:"Sul_Lun_Meu_Mer_Yao_Gwe_Sad".split("_"),weekdaysMin:"Su_Lu_Me_Mer_Ya_Gw_Sa".split("_"),weekdaysParse:l,fullWeekdaysParse:m,shortWeekdaysParse:u,minWeekdaysParse:l,monthsRegex:i,monthsShortRegex:i,monthsStrictRegex:_,monthsShortStrictRegex:o,monthsParse:d,longMonthsParse:d,shortMonthsParse:d,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [a viz] MMMM YYYY",LLL:"D [a viz] MMMM YYYY HH:mm",LLLL:"dddd, D [a viz] MMMM YYYY HH:mm"},calendar:{sameDay:"[Hiziv da] LT",nextDay:"[Warcʼhoazh da] LT",nextWeek:"dddd [da] LT",lastDay:"[Decʼh da] LT",lastWeek:"dddd [paset da] LT",sameElse:"L"},relativeTime:{future:"a-benn %s",past:"%s ʼzo",s:"un nebeud segondennoù",ss:"%d eilenn",m:"ur vunutenn",mm:a,h:"un eur",hh:"%d eur",d:"un devezh",dd:a,M:"ur miz",MM:a,y:"ur bloaz",yy:t},dayOfMonthOrdinalParse:/\d{1,2}(añ|vet)/,ordinal:function(e){return e+(1===e?"añ":"vet")},week:{dow:1,doy:4},meridiemParse:/a.m.|g.m./,isPM:function(e){return"g.m."===e},meridiem:function(e,a,t){return e<12?"a.m.":"g.m."}})}(t(5093))},4429(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e,a,t,s){if("m"===t)return a?"jedna minuta":s?"jednu minutu":"jedne minute"}function t(e,a,t){var s=e+" ";switch(t){case"ss":return s+=1===e?"sekunda":2===e||3===e||4===e?"sekunde":"sekundi";case"mm":return s+=1===e?"minuta":2===e||3===e||4===e?"minute":"minuta";case"h":return"jedan sat";case"hh":return s+=1===e?"sat":2===e||3===e||4===e?"sata":"sati";case"dd":return s+=1===e?"dan":"dana";case"MM":return s+=1===e?"mjesec":2===e||3===e||4===e?"mjeseca":"mjeseci";case"yy":return s+=1===e?"godina":2===e||3===e||4===e?"godine":"godina"}}e.defineLocale("bs",{months:"januar_februar_mart_april_maj_juni_juli_august_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj._jun._jul._aug._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[jučer u] LT",lastWeek:function(){switch(this.day()){case 0:case 3:return"[prošlu] dddd [u] LT";case 6:return"[prošle] [subote] [u] LT";case 1:case 2:case 4:case 5:return"[prošli] dddd [u] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"par sekundi",ss:t,m:a,mm:t,h:t,hh:t,d:"dan",dd:t,M:"mjesec",MM:t,y:"godinu",yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(t(5093))},7306:function(e,a,t){!function(e){"use strict"; +function a(e,a,t,s){if("m"===t)return a?"jedna minuta":s?"jednu minutu":"jedne minute"}function t(e,a,t){var s=e+" ";switch(t){case"ss":return s+=1===e?"sekunda":2===e||3===e||4===e?"sekunde":"sekundi";case"mm":return s+=1===e?"minuta":2===e||3===e||4===e?"minute":"minuta";case"h":return"jedan sat";case"hh":return s+=1===e?"sat":2===e||3===e||4===e?"sata":"sati";case"dd":return s+=1===e?"dan":"dana";case"MM":return s+=1===e?"mjesec":2===e||3===e||4===e?"mjeseca":"mjeseci";case"yy":return s+=1===e?"godina":2===e||3===e||4===e?"godine":"godina"}}e.defineLocale("bs",{months:"januar_februar_mart_april_maj_juni_juli_august_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj._jun._jul._aug._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[jučer u] LT",lastWeek:function(){switch(this.day()){case 0:case 3:return"[prošlu] dddd [u] LT";case 6:return"[prošle] [subote] [u] LT";case 1:case 2:case 4:case 5:return"[prošli] dddd [u] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"par sekundi",ss:t,m:a,mm:t,h:t,hh:t,d:"dan",dd:t,M:"mjesec",MM:t,y:"godinu",yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(t(5093))},7306(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("ca",{months:{standalone:"gener_febrer_març_abril_maig_juny_juliol_agost_setembre_octubre_novembre_desembre".split("_"),format:"de gener_de febrer_de març_d'abril_de maig_de juny_de juliol_d'agost_de setembre_d'octubre_de novembre_de desembre".split("_"),isFormat:/D[oD]?(\s)+MMMM/},monthsShort:"gen._febr._març_abr._maig_juny_jul._ag._set._oct._nov._des.".split("_"),monthsParseExact:!0,weekdays:"diumenge_dilluns_dimarts_dimecres_dijous_divendres_dissabte".split("_"),weekdaysShort:"dg._dl._dt._dc._dj._dv._ds.".split("_"),weekdaysMin:"dg_dl_dt_dc_dj_dv_ds".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM [de] YYYY",ll:"D MMM YYYY",LLL:"D MMMM [de] YYYY [a les] H:mm",lll:"D MMM YYYY, H:mm",LLLL:"dddd D MMMM [de] YYYY [a les] H:mm",llll:"ddd D MMM YYYY, H:mm"},calendar:{sameDay:function(){return"[avui a "+(1!==this.hours()?"les":"la")+"] LT"},nextDay:function(){return"[demà a "+(1!==this.hours()?"les":"la")+"] LT"},nextWeek:function(){return"dddd [a "+(1!==this.hours()?"les":"la")+"] LT"},lastDay:function(){return"[ahir a "+(1!==this.hours()?"les":"la")+"] LT"},lastWeek:function(){return"[el] dddd [passat a "+(1!==this.hours()?"les":"la")+"] LT"},sameElse:"L"},relativeTime:{future:"d'aquí %s",past:"fa %s",s:"uns segons",ss:"%d segons",m:"un minut",mm:"%d minuts",h:"una hora",hh:"%d hores",d:"un dia",dd:"%d dies",M:"un mes",MM:"%d mesos",y:"un any",yy:"%d anys"},dayOfMonthOrdinalParse:/\d{1,2}(r|n|t|è|a)/,ordinal:function(e,a){var t=1===e?"r":2===e?"n":3===e?"r":4===e?"t":"è";return"w"!==a&&"W"!==a||(t="a"),e+t},week:{dow:1,doy:4}})}(t(5093))},6464:function(e,a,t){!function(e){"use strict"; +e.defineLocale("ca",{months:{standalone:"gener_febrer_març_abril_maig_juny_juliol_agost_setembre_octubre_novembre_desembre".split("_"),format:"de gener_de febrer_de març_d'abril_de maig_de juny_de juliol_d'agost_de setembre_d'octubre_de novembre_de desembre".split("_"),isFormat:/D[oD]?(\s)+MMMM/},monthsShort:"gen._febr._març_abr._maig_juny_jul._ag._set._oct._nov._des.".split("_"),monthsParseExact:!0,weekdays:"diumenge_dilluns_dimarts_dimecres_dijous_divendres_dissabte".split("_"),weekdaysShort:"dg._dl._dt._dc._dj._dv._ds.".split("_"),weekdaysMin:"dg_dl_dt_dc_dj_dv_ds".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM [de] YYYY",ll:"D MMM YYYY",LLL:"D MMMM [de] YYYY [a les] H:mm",lll:"D MMM YYYY, H:mm",LLLL:"dddd D MMMM [de] YYYY [a les] H:mm",llll:"ddd D MMM YYYY, H:mm"},calendar:{sameDay:function(){return"[avui a "+(1!==this.hours()?"les":"la")+"] LT"},nextDay:function(){return"[demà a "+(1!==this.hours()?"les":"la")+"] LT"},nextWeek:function(){return"dddd [a "+(1!==this.hours()?"les":"la")+"] LT"},lastDay:function(){return"[ahir a "+(1!==this.hours()?"les":"la")+"] LT"},lastWeek:function(){return"[el] dddd [passat a "+(1!==this.hours()?"les":"la")+"] LT"},sameElse:"L"},relativeTime:{future:"d'aquí %s",past:"fa %s",s:"uns segons",ss:"%d segons",m:"un minut",mm:"%d minuts",h:"una hora",hh:"%d hores",d:"un dia",dd:"%d dies",M:"un mes",MM:"%d mesos",y:"un any",yy:"%d anys"},dayOfMonthOrdinalParse:/\d{1,2}(r|n|t|è|a)/,ordinal:function(e,a){var t=1===e?"r":2===e?"n":3===e?"r":4===e?"t":"è";return"w"!==a&&"W"!==a||(t="a"),e+t},week:{dow:1,doy:4}})}(t(5093))},6464(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={standalone:"leden_únor_březen_duben_květen_červen_červenec_srpen_září_říjen_listopad_prosinec".split("_"),format:"ledna_února_března_dubna_května_června_července_srpna_září_října_listopadu_prosince".split("_"),isFormat:/DD?[o.]?(\[[^\[\]]*\]|\s)+MMMM/},t="led_úno_bře_dub_kvě_čvn_čvc_srp_zář_říj_lis_pro".split("_"),s=[/^led/i,/^úno/i,/^bře/i,/^dub/i,/^kvě/i,/^(čvn|červen$|června)/i,/^(čvc|červenec|července)/i,/^srp/i,/^zář/i,/^říj/i,/^lis/i,/^pro/i],n=/^(leden|únor|březen|duben|květen|červenec|července|červen|června|srpen|září|říjen|listopad|prosinec|led|úno|bře|dub|kvě|čvn|čvc|srp|zář|říj|lis|pro)/i;function r(e){return e>1&&e<5&&1!=~~(e/10)}function i(e,a,t,s){var n=e+" ";switch(t){case"s":return a||s?"pár sekund":"pár sekundami";case"ss":return a||s?n+(r(e)?"sekundy":"sekund"):n+"sekundami";case"m":return a?"minuta":s?"minutu":"minutou";case"mm":return a||s?n+(r(e)?"minuty":"minut"):n+"minutami";case"h":return a?"hodina":s?"hodinu":"hodinou";case"hh":return a||s?n+(r(e)?"hodiny":"hodin"):n+"hodinami";case"d":return a||s?"den":"dnem";case"dd":return a||s?n+(r(e)?"dny":"dní"):n+"dny";case"M":return a||s?"měsíc":"měsícem";case"MM":return a||s?n+(r(e)?"měsíce":"měsíců"):n+"měsíci";case"y":return a||s?"rok":"rokem";case"yy":return a||s?n+(r(e)?"roky":"let"):n+"lety"}}e.defineLocale("cs",{months:a,monthsShort:t,monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(leden|ledna|února|únor|březen|března|duben|dubna|květen|května|červenec|července|červen|června|srpen|srpna|září|říjen|října|listopadu|listopad|prosinec|prosince)/i,monthsShortStrictRegex:/^(led|úno|bře|dub|kvě|čvn|čvc|srp|zář|říj|lis|pro)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"neděle_pondělí_úterý_středa_čtvrtek_pátek_sobota".split("_"),weekdaysShort:"ne_po_út_st_čt_pá_so".split("_"),weekdaysMin:"ne_po_út_st_čt_pá_so".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd D. MMMM YYYY H:mm",l:"D. M. YYYY"},calendar:{sameDay:"[dnes v] LT",nextDay:"[zítra v] LT",nextWeek:function(){switch(this.day()){case 0:return"[v neděli v] LT";case 1:case 2:return"[v] dddd [v] LT";case 3:return"[ve středu v] LT";case 4:return"[ve čtvrtek v] LT";case 5:return"[v pátek v] LT";case 6:return"[v sobotu v] LT"}},lastDay:"[včera v] LT",lastWeek:function(){switch(this.day()){case 0:return"[minulou neděli v] LT";case 1:case 2:return"[minulé] dddd [v] LT";case 3:return"[minulou středu v] LT";case 4:case 5:return"[minulý] dddd [v] LT";case 6:return"[minulou sobotu v] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"před %s",s:i,ss:i,m:i,mm:i,h:i,hh:i,d:i,dd:i,M:i,MM:i,y:i,yy:i},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},3635:function(e,a,t){!function(e){"use strict"; +var a={standalone:"leden_únor_březen_duben_květen_červen_červenec_srpen_září_říjen_listopad_prosinec".split("_"),format:"ledna_února_března_dubna_května_června_července_srpna_září_října_listopadu_prosince".split("_"),isFormat:/DD?[o.]?(\[[^\[\]]*\]|\s)+MMMM/},t="led_úno_bře_dub_kvě_čvn_čvc_srp_zář_říj_lis_pro".split("_"),s=[/^led/i,/^úno/i,/^bře/i,/^dub/i,/^kvě/i,/^(čvn|červen$|června)/i,/^(čvc|červenec|července)/i,/^srp/i,/^zář/i,/^říj/i,/^lis/i,/^pro/i],n=/^(leden|únor|březen|duben|květen|červenec|července|červen|června|srpen|září|říjen|listopad|prosinec|led|úno|bře|dub|kvě|čvn|čvc|srp|zář|říj|lis|pro)/i;function r(e){return e>1&&e<5&&1!=~~(e/10)}function d(e,a,t,s){var n=e+" ";switch(t){case"s":return a||s?"pár sekund":"pár sekundami";case"ss":return a||s?n+(r(e)?"sekundy":"sekund"):n+"sekundami";case"m":return a?"minuta":s?"minutu":"minutou";case"mm":return a||s?n+(r(e)?"minuty":"minut"):n+"minutami";case"h":return a?"hodina":s?"hodinu":"hodinou";case"hh":return a||s?n+(r(e)?"hodiny":"hodin"):n+"hodinami";case"d":return a||s?"den":"dnem";case"dd":return a||s?n+(r(e)?"dny":"dní"):n+"dny";case"M":return a||s?"měsíc":"měsícem";case"MM":return a||s?n+(r(e)?"měsíce":"měsíců"):n+"měsíci";case"y":return a||s?"rok":"rokem";case"yy":return a||s?n+(r(e)?"roky":"let"):n+"lety"}}e.defineLocale("cs",{months:a,monthsShort:t,monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(leden|ledna|února|únor|březen|března|duben|dubna|květen|května|červenec|července|červen|června|srpen|srpna|září|říjen|října|listopadu|listopad|prosinec|prosince)/i,monthsShortStrictRegex:/^(led|úno|bře|dub|kvě|čvn|čvc|srp|zář|říj|lis|pro)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"neděle_pondělí_úterý_středa_čtvrtek_pátek_sobota".split("_"),weekdaysShort:"ne_po_út_st_čt_pá_so".split("_"),weekdaysMin:"ne_po_út_st_čt_pá_so".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd D. MMMM YYYY H:mm",l:"D. M. YYYY"},calendar:{sameDay:"[dnes v] LT",nextDay:"[zítra v] LT",nextWeek:function(){switch(this.day()){case 0:return"[v neděli v] LT";case 1:case 2:return"[v] dddd [v] LT";case 3:return"[ve středu v] LT";case 4:return"[ve čtvrtek v] LT";case 5:return"[v pátek v] LT";case 6:return"[v sobotu v] LT"}},lastDay:"[včera v] LT",lastWeek:function(){switch(this.day()){case 0:return"[minulou neděli v] LT";case 1:case 2:return"[minulé] dddd [v] LT";case 3:return"[minulou středu v] LT";case 4:case 5:return"[minulý] dddd [v] LT";case 6:return"[minulou sobotu v] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"před %s",s:d,ss:d,m:d,mm:d,h:d,hh:d,d,dd:d,M:d,MM:d,y:d,yy:d},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},3635(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("cv",{months:"кӑрлач_нарӑс_пуш_ака_май_ҫӗртме_утӑ_ҫурла_авӑн_юпа_чӳк_раштав".split("_"),monthsShort:"кӑр_нар_пуш_ака_май_ҫӗр_утӑ_ҫур_авн_юпа_чӳк_раш".split("_"),weekdays:"вырсарникун_тунтикун_ытларикун_юнкун_кӗҫнерникун_эрнекун_шӑматкун".split("_"),weekdaysShort:"выр_тун_ытл_юн_кӗҫ_эрн_шӑм".split("_"),weekdaysMin:"вр_тн_ыт_юн_кҫ_эр_шм".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ]",LLL:"YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm",LLLL:"dddd, YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm"},calendar:{sameDay:"[Паян] LT [сехетре]",nextDay:"[Ыран] LT [сехетре]",lastDay:"[Ӗнер] LT [сехетре]",nextWeek:"[Ҫитес] dddd LT [сехетре]",lastWeek:"[Иртнӗ] dddd LT [сехетре]",sameElse:"L"},relativeTime:{future:function(e){return e+(/сехет$/i.exec(e)?"рен":/ҫул$/i.exec(e)?"тан":"ран")},past:"%s каялла",s:"пӗр-ик ҫеккунт",ss:"%d ҫеккунт",m:"пӗр минут",mm:"%d минут",h:"пӗр сехет",hh:"%d сехет",d:"пӗр кун",dd:"%d кун",M:"пӗр уйӑх",MM:"%d уйӑх",y:"пӗр ҫул",yy:"%d ҫул"},dayOfMonthOrdinalParse:/\d{1,2}-мӗш/,ordinal:"%d-мӗш",week:{dow:1,doy:7}})}(t(5093))},4226:function(e,a,t){!function(e){"use strict"; +e.defineLocale("cv",{months:"кӑрлач_нарӑс_пуш_ака_май_ҫӗртме_утӑ_ҫурла_авӑн_юпа_чӳк_раштав".split("_"),monthsShort:"кӑр_нар_пуш_ака_май_ҫӗр_утӑ_ҫур_авн_юпа_чӳк_раш".split("_"),weekdays:"вырсарникун_тунтикун_ытларикун_юнкун_кӗҫнерникун_эрнекун_шӑматкун".split("_"),weekdaysShort:"выр_тун_ытл_юн_кӗҫ_эрн_шӑм".split("_"),weekdaysMin:"вр_тн_ыт_юн_кҫ_эр_шм".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ]",LLL:"YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm",LLLL:"dddd, YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm"},calendar:{sameDay:"[Паян] LT [сехетре]",nextDay:"[Ыран] LT [сехетре]",lastDay:"[Ӗнер] LT [сехетре]",nextWeek:"[Ҫитес] dddd LT [сехетре]",lastWeek:"[Иртнӗ] dddd LT [сехетре]",sameElse:"L"},relativeTime:{future:function(e){return e+(/сехет$/i.exec(e)?"рен":/ҫул$/i.exec(e)?"тан":"ран")},past:"%s каялла",s:"пӗр-ик ҫеккунт",ss:"%d ҫеккунт",m:"пӗр минут",mm:"%d минут",h:"пӗр сехет",hh:"%d сехет",d:"пӗр кун",dd:"%d кун",M:"пӗр уйӑх",MM:"%d уйӑх",y:"пӗр ҫул",yy:"%d ҫул"},dayOfMonthOrdinalParse:/\d{1,2}-мӗш/,ordinal:"%d-мӗш",week:{dow:1,doy:7}})}(t(5093))},4226(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("cy",{months:"Ionawr_Chwefror_Mawrth_Ebrill_Mai_Mehefin_Gorffennaf_Awst_Medi_Hydref_Tachwedd_Rhagfyr".split("_"),monthsShort:"Ion_Chwe_Maw_Ebr_Mai_Meh_Gor_Aws_Med_Hyd_Tach_Rhag".split("_"),weekdays:"Dydd Sul_Dydd Llun_Dydd Mawrth_Dydd Mercher_Dydd Iau_Dydd Gwener_Dydd Sadwrn".split("_"),weekdaysShort:"Sul_Llun_Maw_Mer_Iau_Gwe_Sad".split("_"),weekdaysMin:"Su_Ll_Ma_Me_Ia_Gw_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Heddiw am] LT",nextDay:"[Yfory am] LT",nextWeek:"dddd [am] LT",lastDay:"[Ddoe am] LT",lastWeek:"dddd [diwethaf am] LT",sameElse:"L"},relativeTime:{future:"mewn %s",past:"%s yn ôl",s:"ychydig eiliadau",ss:"%d eiliad",m:"munud",mm:"%d munud",h:"awr",hh:"%d awr",d:"diwrnod",dd:"%d diwrnod",M:"mis",MM:"%d mis",y:"blwyddyn",yy:"%d flynedd"},dayOfMonthOrdinalParse:/\d{1,2}(fed|ain|af|il|ydd|ed|eg)/,ordinal:function(e){var a="";return e>20?a=40===e||50===e||60===e||80===e||100===e?"fed":"ain":e>0&&(a=["","af","il","ydd","ydd","ed","ed","ed","fed","fed","fed","eg","fed","eg","eg","fed","eg","eg","fed","eg","fed"][e]),e+a},week:{dow:1,doy:4}})}(t(5093))},3601:function(e,a,t){!function(e){"use strict"; +e.defineLocale("cy",{months:"Ionawr_Chwefror_Mawrth_Ebrill_Mai_Mehefin_Gorffennaf_Awst_Medi_Hydref_Tachwedd_Rhagfyr".split("_"),monthsShort:"Ion_Chwe_Maw_Ebr_Mai_Meh_Gor_Aws_Med_Hyd_Tach_Rhag".split("_"),weekdays:"Dydd Sul_Dydd Llun_Dydd Mawrth_Dydd Mercher_Dydd Iau_Dydd Gwener_Dydd Sadwrn".split("_"),weekdaysShort:"Sul_Llun_Maw_Mer_Iau_Gwe_Sad".split("_"),weekdaysMin:"Su_Ll_Ma_Me_Ia_Gw_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Heddiw am] LT",nextDay:"[Yfory am] LT",nextWeek:"dddd [am] LT",lastDay:"[Ddoe am] LT",lastWeek:"dddd [diwethaf am] LT",sameElse:"L"},relativeTime:{future:"mewn %s",past:"%s yn ôl",s:"ychydig eiliadau",ss:"%d eiliad",m:"munud",mm:"%d munud",h:"awr",hh:"%d awr",d:"diwrnod",dd:"%d diwrnod",M:"mis",MM:"%d mis",y:"blwyddyn",yy:"%d flynedd"},dayOfMonthOrdinalParse:/\d{1,2}(fed|ain|af|il|ydd|ed|eg)/,ordinal:function(e){var a="";return e>20?a=40===e||50===e||60===e||80===e||100===e?"fed":"ain":e>0&&(a=["","af","il","ydd","ydd","ed","ed","ed","fed","fed","fed","eg","fed","eg","eg","fed","eg","eg","fed","eg","fed"][e]),e+a},week:{dow:1,doy:4}})}(t(5093))},3601(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("da",{months:"januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december".split("_"),monthsShort:"jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec".split("_"),weekdays:"søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag".split("_"),weekdaysShort:"søn_man_tir_ons_tor_fre_lør".split("_"),weekdaysMin:"sø_ma_ti_on_to_fr_lø".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd [d.] D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[i dag kl.] LT",nextDay:"[i morgen kl.] LT",nextWeek:"på dddd [kl.] LT",lastDay:"[i går kl.] LT",lastWeek:"[i] dddd[s kl.] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s siden",s:"få sekunder",ss:"%d sekunder",m:"et minut",mm:"%d minutter",h:"en time",hh:"%d timer",d:"en dag",dd:"%d dage",M:"en måned",MM:"%d måneder",y:"et år",yy:"%d år"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},6111:function(e,a,t){!function(e){"use strict"; +e.defineLocale("da",{months:"januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december".split("_"),monthsShort:"jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec".split("_"),weekdays:"søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag".split("_"),weekdaysShort:"søn_man_tir_ons_tor_fre_lør".split("_"),weekdaysMin:"sø_ma_ti_on_to_fr_lø".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd [d.] D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[i dag kl.] LT",nextDay:"[i morgen kl.] LT",nextWeek:"på dddd [kl.] LT",lastDay:"[i går kl.] LT",lastWeek:"[i] dddd[s kl.] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s siden",s:"få sekunder",ss:"%d sekunder",m:"et minut",mm:"%d minutter",h:"en time",hh:"%d timer",d:"en dag",dd:"%d dage",M:"en måned",MM:"%d måneder",y:"et år",yy:"%d år"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},6111(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e,a,t,s){var n={m:["eine Minute","einer Minute"],h:["eine Stunde","einer Stunde"],d:["ein Tag","einem Tag"],dd:[e+" Tage",e+" Tagen"],w:["eine Woche","einer Woche"],M:["ein Monat","einem Monat"],MM:[e+" Monate",e+" Monaten"],y:["ein Jahr","einem Jahr"],yy:[e+" Jahre",e+" Jahren"]};return a?n[t][0]:n[t][1]}e.defineLocale("de-at",{months:"Jänner_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jän._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"),weekdaysShort:"So._Mo._Di._Mi._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd, D. MMMM YYYY HH:mm"},calendar:{sameDay:"[heute um] LT [Uhr]",sameElse:"L",nextDay:"[morgen um] LT [Uhr]",nextWeek:"dddd [um] LT [Uhr]",lastDay:"[gestern um] LT [Uhr]",lastWeek:"[letzten] dddd [um] LT [Uhr]"},relativeTime:{future:"in %s",past:"vor %s",s:"ein paar Sekunden",ss:"%d Sekunden",m:a,mm:"%d Minuten",h:a,hh:"%d Stunden",d:a,dd:a,w:a,ww:"%d Wochen",M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},4697:function(e,a,t){!function(e){"use strict"; +function a(e,a,t,s){var n={m:["eine Minute","einer Minute"],h:["eine Stunde","einer Stunde"],d:["ein Tag","einem Tag"],dd:[e+" Tage",e+" Tagen"],w:["eine Woche","einer Woche"],M:["ein Monat","einem Monat"],MM:[e+" Monate",e+" Monaten"],y:["ein Jahr","einem Jahr"],yy:[e+" Jahre",e+" Jahren"]};return a?n[t][0]:n[t][1]}e.defineLocale("de-at",{months:"Jänner_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jän._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"),weekdaysShort:"So._Mo._Di._Mi._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd, D. MMMM YYYY HH:mm"},calendar:{sameDay:"[heute um] LT [Uhr]",sameElse:"L",nextDay:"[morgen um] LT [Uhr]",nextWeek:"dddd [um] LT [Uhr]",lastDay:"[gestern um] LT [Uhr]",lastWeek:"[letzten] dddd [um] LT [Uhr]"},relativeTime:{future:"in %s",past:"vor %s",s:"ein paar Sekunden",ss:"%d Sekunden",m:a,mm:"%d Minuten",h:a,hh:"%d Stunden",d:a,dd:a,w:a,ww:"%d Wochen",M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},4697(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e,a,t,s){var n={m:["eine Minute","einer Minute"],h:["eine Stunde","einer Stunde"],d:["ein Tag","einem Tag"],dd:[e+" Tage",e+" Tagen"],w:["eine Woche","einer Woche"],M:["ein Monat","einem Monat"],MM:[e+" Monate",e+" Monaten"],y:["ein Jahr","einem Jahr"],yy:[e+" Jahre",e+" Jahren"]};return a?n[t][0]:n[t][1]}e.defineLocale("de-ch",{months:"Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"),weekdaysShort:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysMin:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd, D. MMMM YYYY HH:mm"},calendar:{sameDay:"[heute um] LT [Uhr]",sameElse:"L",nextDay:"[morgen um] LT [Uhr]",nextWeek:"dddd [um] LT [Uhr]",lastDay:"[gestern um] LT [Uhr]",lastWeek:"[letzten] dddd [um] LT [Uhr]"},relativeTime:{future:"in %s",past:"vor %s",s:"ein paar Sekunden",ss:"%d Sekunden",m:a,mm:"%d Minuten",h:a,hh:"%d Stunden",d:a,dd:a,w:a,ww:"%d Wochen",M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},7853:function(e,a,t){!function(e){"use strict"; +function a(e,a,t,s){var n={m:["eine Minute","einer Minute"],h:["eine Stunde","einer Stunde"],d:["ein Tag","einem Tag"],dd:[e+" Tage",e+" Tagen"],w:["eine Woche","einer Woche"],M:["ein Monat","einem Monat"],MM:[e+" Monate",e+" Monaten"],y:["ein Jahr","einem Jahr"],yy:[e+" Jahre",e+" Jahren"]};return a?n[t][0]:n[t][1]}e.defineLocale("de-ch",{months:"Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"),weekdaysShort:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysMin:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd, D. MMMM YYYY HH:mm"},calendar:{sameDay:"[heute um] LT [Uhr]",sameElse:"L",nextDay:"[morgen um] LT [Uhr]",nextWeek:"dddd [um] LT [Uhr]",lastDay:"[gestern um] LT [Uhr]",lastWeek:"[letzten] dddd [um] LT [Uhr]"},relativeTime:{future:"in %s",past:"vor %s",s:"ein paar Sekunden",ss:"%d Sekunden",m:a,mm:"%d Minuten",h:a,hh:"%d Stunden",d:a,dd:a,w:a,ww:"%d Wochen",M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},7853(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e,a,t,s){var n={m:["eine Minute","einer Minute"],h:["eine Stunde","einer Stunde"],d:["ein Tag","einem Tag"],dd:[e+" Tage",e+" Tagen"],w:["eine Woche","einer Woche"],M:["ein Monat","einem Monat"],MM:[e+" Monate",e+" Monaten"],y:["ein Jahr","einem Jahr"],yy:[e+" Jahre",e+" Jahren"]};return a?n[t][0]:n[t][1]}e.defineLocale("de",{months:"Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"),weekdaysShort:"So._Mo._Di._Mi._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd, D. MMMM YYYY HH:mm"},calendar:{sameDay:"[heute um] LT [Uhr]",sameElse:"L",nextDay:"[morgen um] LT [Uhr]",nextWeek:"dddd [um] LT [Uhr]",lastDay:"[gestern um] LT [Uhr]",lastWeek:"[letzten] dddd [um] LT [Uhr]"},relativeTime:{future:"in %s",past:"vor %s",s:"ein paar Sekunden",ss:"%d Sekunden",m:a,mm:"%d Minuten",h:a,hh:"%d Stunden",d:a,dd:a,w:a,ww:"%d Wochen",M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},708:function(e,a,t){!function(e){"use strict"; +function a(e,a,t,s){var n={m:["eine Minute","einer Minute"],h:["eine Stunde","einer Stunde"],d:["ein Tag","einem Tag"],dd:[e+" Tage",e+" Tagen"],w:["eine Woche","einer Woche"],M:["ein Monat","einem Monat"],MM:[e+" Monate",e+" Monaten"],y:["ein Jahr","einem Jahr"],yy:[e+" Jahre",e+" Jahren"]};return a?n[t][0]:n[t][1]}e.defineLocale("de",{months:"Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"),weekdaysShort:"So._Mo._Di._Mi._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd, D. MMMM YYYY HH:mm"},calendar:{sameDay:"[heute um] LT [Uhr]",sameElse:"L",nextDay:"[morgen um] LT [Uhr]",nextWeek:"dddd [um] LT [Uhr]",lastDay:"[gestern um] LT [Uhr]",lastWeek:"[letzten] dddd [um] LT [Uhr]"},relativeTime:{future:"in %s",past:"vor %s",s:"ein paar Sekunden",ss:"%d Sekunden",m:a,mm:"%d Minuten",h:a,hh:"%d Stunden",d:a,dd:a,w:a,ww:"%d Wochen",M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},708(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a=["ޖެނުއަރީ","ފެބްރުއަރީ","މާރިޗު","އޭޕްރީލު","މޭ","ޖޫން","ޖުލައި","އޯގަސްޓު","ސެޕްޓެމްބަރު","އޮކްޓޯބަރު","ނޮވެމްބަރު","ޑިސެމްބަރު"],t=["އާދިއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"];e.defineLocale("dv",{months:a,monthsShort:a,weekdays:t,weekdaysShort:t,weekdaysMin:"އާދި_ހޯމަ_އަން_ބުދަ_ބުރާ_ހުކު_ހޮނި".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/M/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/މކ|މފ/,isPM:function(e){return"މފ"===e},meridiem:function(e,a,t){return e<12?"މކ":"މފ"},calendar:{sameDay:"[މިއަދު] LT",nextDay:"[މާދަމާ] LT",nextWeek:"dddd LT",lastDay:"[އިއްޔެ] LT",lastWeek:"[ފާއިތުވި] dddd LT",sameElse:"L"},relativeTime:{future:"ތެރޭގައި %s",past:"ކުރިން %s",s:"ސިކުންތުކޮޅެއް",ss:"d% ސިކުންތު",m:"މިނިޓެއް",mm:"މިނިޓު %d",h:"ގަޑިއިރެއް",hh:"ގަޑިއިރު %d",d:"ދުވަހެއް",dd:"ދުވަސް %d",M:"މަހެއް",MM:"މަސް %d",y:"އަހަރެއް",yy:"އަހަރު %d"},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:7,doy:12}})}(t(5093))},4691:function(e,a,t){!function(e){"use strict"; +var a=["ޖެނުއަރީ","ފެބްރުއަރީ","މާރިޗު","އޭޕްރީލު","މޭ","ޖޫން","ޖުލައި","އޯގަސްޓު","ސެޕްޓެމްބަރު","އޮކްޓޯބަރު","ނޮވެމްބަރު","ޑިސެމްބަރު"],t=["އާދިއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"];e.defineLocale("dv",{months:a,monthsShort:a,weekdays:t,weekdaysShort:t,weekdaysMin:"އާދި_ހޯމަ_އަން_ބުދަ_ބުރާ_ހުކު_ހޮނި".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/M/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/މކ|މފ/,isPM:function(e){return"މފ"===e},meridiem:function(e,a,t){return e<12?"މކ":"މފ"},calendar:{sameDay:"[މިއަދު] LT",nextDay:"[މާދަމާ] LT",nextWeek:"dddd LT",lastDay:"[އިއްޔެ] LT",lastWeek:"[ފާއިތުވި] dddd LT",sameElse:"L"},relativeTime:{future:"ތެރޭގައި %s",past:"ކުރިން %s",s:"ސިކުންތުކޮޅެއް",ss:"d% ސިކުންތު",m:"މިނިޓެއް",mm:"މިނިޓު %d",h:"ގަޑިއިރެއް",hh:"ގަޑިއިރު %d",d:"ދުވަހެއް",dd:"ދުވަސް %d",M:"މަހެއް",MM:"މަސް %d",y:"އަހަރެއް",yy:"އަހަރު %d"},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:7,doy:12}})}(t(5093))},4691(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e){return"undefined"!=typeof Function&&e instanceof Function||"[object Function]"===Object.prototype.toString.call(e)}e.defineLocale("el",{monthsNominativeEl:"Ιανουάριος_Φεβρουάριος_Μάρτιος_Απρίλιος_Μάιος_Ιούνιος_Ιούλιος_Αύγουστος_Σεπτέμβριος_Οκτώβριος_Νοέμβριος_Δεκέμβριος".split("_"),monthsGenitiveEl:"Ιανουαρίου_Φεβρουαρίου_Μαρτίου_Απριλίου_Μαΐου_Ιουνίου_Ιουλίου_Αυγούστου_Σεπτεμβρίου_Οκτωβρίου_Νοεμβρίου_Δεκεμβρίου".split("_"),months:function(e,a){return e?"string"==typeof a&&/D/.test(a.substring(0,a.indexOf("MMMM")))?this._monthsGenitiveEl[e.month()]:this._monthsNominativeEl[e.month()]:this._monthsNominativeEl},monthsShort:"Ιαν_Φεβ_Μαρ_Απρ_Μαϊ_Ιουν_Ιουλ_Αυγ_Σεπ_Οκτ_Νοε_Δεκ".split("_"),weekdays:"Κυριακή_Δευτέρα_Τρίτη_Τετάρτη_Πέμπτη_Παρασκευή_Σάββατο".split("_"),weekdaysShort:"Κυρ_Δευ_Τρι_Τετ_Πεμ_Παρ_Σαβ".split("_"),weekdaysMin:"Κυ_Δε_Τρ_Τε_Πε_Πα_Σα".split("_"),meridiem:function(e,a,t){return e>11?t?"μμ":"ΜΜ":t?"πμ":"ΠΜ"},isPM:function(e){return"μ"===(e+"").toLowerCase()[0]},meridiemParse:/[ΠΜ]\.?Μ?\.?/i,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendarEl:{sameDay:"[Σήμερα {}] LT",nextDay:"[Αύριο {}] LT",nextWeek:"dddd [{}] LT",lastDay:"[Χθες {}] LT",lastWeek:function(){return 6===this.day()?"[το προηγούμενο] dddd [{}] LT":"[την προηγούμενη] dddd [{}] LT"},sameElse:"L"},calendar:function(e,t){var s=this._calendarEl[e],n=t&&t.hours();return a(s)&&(s=s.apply(t)),s.replace("{}",n%12==1?"στη":"στις")},relativeTime:{future:"σε %s",past:"%s πριν",s:"λίγα δευτερόλεπτα",ss:"%d δευτερόλεπτα",m:"ένα λεπτό",mm:"%d λεπτά",h:"μία ώρα",hh:"%d ώρες",d:"μία μέρα",dd:"%d μέρες",M:"ένας μήνας",MM:"%d μήνες",y:"ένας χρόνος",yy:"%d χρόνια"},dayOfMonthOrdinalParse:/\d{1,2}η/,ordinal:"%dη",week:{dow:1,doy:4}})}(t(5093))},3872:function(e,a,t){!function(e){"use strict"; +function a(e){return"undefined"!=typeof Function&&e instanceof Function||"[object Function]"===Object.prototype.toString.call(e)}e.defineLocale("el",{monthsNominativeEl:"Ιανουάριος_Φεβρουάριος_Μάρτιος_Απρίλιος_Μάιος_Ιούνιος_Ιούλιος_Αύγουστος_Σεπτέμβριος_Οκτώβριος_Νοέμβριος_Δεκέμβριος".split("_"),monthsGenitiveEl:"Ιανουαρίου_Φεβρουαρίου_Μαρτίου_Απριλίου_Μαΐου_Ιουνίου_Ιουλίου_Αυγούστου_Σεπτεμβρίου_Οκτωβρίου_Νοεμβρίου_Δεκεμβρίου".split("_"),months:function(e,a){return e?"string"==typeof a&&/D/.test(a.substring(0,a.indexOf("MMMM")))?this._monthsGenitiveEl[e.month()]:this._monthsNominativeEl[e.month()]:this._monthsNominativeEl},monthsShort:"Ιαν_Φεβ_Μαρ_Απρ_Μαϊ_Ιουν_Ιουλ_Αυγ_Σεπ_Οκτ_Νοε_Δεκ".split("_"),weekdays:"Κυριακή_Δευτέρα_Τρίτη_Τετάρτη_Πέμπτη_Παρασκευή_Σάββατο".split("_"),weekdaysShort:"Κυρ_Δευ_Τρι_Τετ_Πεμ_Παρ_Σαβ".split("_"),weekdaysMin:"Κυ_Δε_Τρ_Τε_Πε_Πα_Σα".split("_"),meridiem:function(e,a,t){return e>11?t?"μμ":"ΜΜ":t?"πμ":"ΠΜ"},isPM:function(e){return"μ"===(e+"").toLowerCase()[0]},meridiemParse:/[ΠΜ]\.?Μ?\.?/i,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendarEl:{sameDay:"[Σήμερα {}] LT",nextDay:"[Αύριο {}] LT",nextWeek:"dddd [{}] LT",lastDay:"[Χθες {}] LT",lastWeek:function(){return 6===this.day()?"[το προηγούμενο] dddd [{}] LT":"[την προηγούμενη] dddd [{}] LT"},sameElse:"L"},calendar:function(e,t){var s=this._calendarEl[e],n=t&&t.hours();return a(s)&&(s=s.apply(t)),s.replace("{}",n%12==1?"στη":"στις")},relativeTime:{future:"σε %s",past:"%s πριν",s:"λίγα δευτερόλεπτα",ss:"%d δευτερόλεπτα",m:"ένα λεπτό",mm:"%d λεπτά",h:"μία ώρα",hh:"%d ώρες",d:"μία μέρα",dd:"%d μέρες",M:"ένας μήνας",MM:"%d μήνες",y:"ένας χρόνος",yy:"%d χρόνια"},dayOfMonthOrdinalParse:/\d{1,2}η/,ordinal:"%dη",week:{dow:1,doy:4}})}(t(5093))},3872(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("en-au",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")},week:{dow:0,doy:4}})}(t(5093))},8298:function(e,a,t){!function(e){"use strict"; +e.defineLocale("en-au",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")},week:{dow:0,doy:4}})}(t(5093))},8298(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("en-ca",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"YYYY-MM-DD",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")}})}(t(5093))},6195:function(e,a,t){!function(e){"use strict"; +e.defineLocale("en-ca",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"YYYY-MM-DD",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")}})}(t(5093))},6195(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("en-gb",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")},week:{dow:1,doy:4}})}(t(5093))},6584:function(e,a,t){!function(e){"use strict"; +e.defineLocale("en-gb",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")},week:{dow:1,doy:4}})}(t(5093))},6584(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("en-ie",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")},week:{dow:1,doy:4}})}(t(5093))},5543:function(e,a,t){!function(e){"use strict"; +e.defineLocale("en-ie",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")},week:{dow:1,doy:4}})}(t(5093))},5543(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("en-il",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")}})}(t(5093))},9033:function(e,a,t){!function(e){"use strict"; +e.defineLocale("en-il",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")}})}(t(5093))},9033(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("en-in",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")},week:{dow:0,doy:6}})}(t(5093))},9402:function(e,a,t){!function(e){"use strict"; +e.defineLocale("en-in",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")},week:{dow:0,doy:6}})}(t(5093))},9402(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("en-nz",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")},week:{dow:1,doy:4}})}(t(5093))},3004:function(e,a,t){!function(e){"use strict"; +e.defineLocale("en-nz",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")},week:{dow:1,doy:4}})}(t(5093))},3004(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("en-sg",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")},week:{dow:1,doy:4}})}(t(5093))},2934:function(e,a,t){!function(e){"use strict"; +e.defineLocale("en-sg",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")},week:{dow:1,doy:4}})}(t(5093))},2934(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("eo",{months:"januaro_februaro_marto_aprilo_majo_junio_julio_aŭgusto_septembro_oktobro_novembro_decembro".split("_"),monthsShort:"jan_feb_mart_apr_maj_jun_jul_aŭg_sept_okt_nov_dec".split("_"),weekdays:"dimanĉo_lundo_mardo_merkredo_ĵaŭdo_vendredo_sabato".split("_"),weekdaysShort:"dim_lun_mard_merk_ĵaŭ_ven_sab".split("_"),weekdaysMin:"di_lu_ma_me_ĵa_ve_sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"[la] D[-an de] MMMM, YYYY",LLL:"[la] D[-an de] MMMM, YYYY HH:mm",LLLL:"dddd[n], [la] D[-an de] MMMM, YYYY HH:mm",llll:"ddd, [la] D[-an de] MMM, YYYY HH:mm"},meridiemParse:/[ap]\.t\.m/i,isPM:function(e){return"p"===e.charAt(0).toLowerCase()},meridiem:function(e,a,t){return e>11?t?"p.t.m.":"P.T.M.":t?"a.t.m.":"A.T.M."},calendar:{sameDay:"[Hodiaŭ je] LT",nextDay:"[Morgaŭ je] LT",nextWeek:"dddd[n je] LT",lastDay:"[Hieraŭ je] LT",lastWeek:"[pasintan] dddd[n je] LT",sameElse:"L"},relativeTime:{future:"post %s",past:"antaŭ %s",s:"kelkaj sekundoj",ss:"%d sekundoj",m:"unu minuto",mm:"%d minutoj",h:"unu horo",hh:"%d horoj",d:"unu tago",dd:"%d tagoj",M:"unu monato",MM:"%d monatoj",y:"unu jaro",yy:"%d jaroj"},dayOfMonthOrdinalParse:/\d{1,2}a/,ordinal:"%da",week:{dow:1,doy:7}})}(t(5093))},838:function(e,a,t){!function(e){"use strict"; +e.defineLocale("eo",{months:"januaro_februaro_marto_aprilo_majo_junio_julio_aŭgusto_septembro_oktobro_novembro_decembro".split("_"),monthsShort:"jan_feb_mart_apr_maj_jun_jul_aŭg_sept_okt_nov_dec".split("_"),weekdays:"dimanĉo_lundo_mardo_merkredo_ĵaŭdo_vendredo_sabato".split("_"),weekdaysShort:"dim_lun_mard_merk_ĵaŭ_ven_sab".split("_"),weekdaysMin:"di_lu_ma_me_ĵa_ve_sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"[la] D[-an de] MMMM, YYYY",LLL:"[la] D[-an de] MMMM, YYYY HH:mm",LLLL:"dddd[n], [la] D[-an de] MMMM, YYYY HH:mm",llll:"ddd, [la] D[-an de] MMM, YYYY HH:mm"},meridiemParse:/[ap]\.t\.m/i,isPM:function(e){return"p"===e.charAt(0).toLowerCase()},meridiem:function(e,a,t){return e>11?t?"p.t.m.":"P.T.M.":t?"a.t.m.":"A.T.M."},calendar:{sameDay:"[Hodiaŭ je] LT",nextDay:"[Morgaŭ je] LT",nextWeek:"dddd[n je] LT",lastDay:"[Hieraŭ je] LT",lastWeek:"[pasintan] dddd[n je] LT",sameElse:"L"},relativeTime:{future:"post %s",past:"antaŭ %s",s:"kelkaj sekundoj",ss:"%d sekundoj",m:"unu minuto",mm:"%d minutoj",h:"unu horo",hh:"%d horoj",d:"unu tago",dd:"%d tagoj",M:"unu monato",MM:"%d monatoj",y:"unu jaro",yy:"%d jaroj"},dayOfMonthOrdinalParse:/\d{1,2}a/,ordinal:"%da",week:{dow:1,doy:7}})}(t(5093))},838(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),t="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),s=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i],n=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;e.defineLocale("es-do",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?t[e.month()]:a[e.month()]:a},monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"),weekdaysShort:"dom._lun._mar._mié._jue._vie._sáb.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY h:mm A",LLLL:"dddd, D [de] MMMM [de] YYYY h:mm A"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[mañana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un día",dd:"%d días",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un año",yy:"%d años"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(t(5093))},7730:function(e,a,t){!function(e){"use strict"; +var a="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),t="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),s=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i],n=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;e.defineLocale("es-do",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?t[e.month()]:a[e.month()]:a},monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"),weekdaysShort:"dom._lun._mar._mié._jue._vie._sáb.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY h:mm A",LLLL:"dddd, D [de] MMMM [de] YYYY h:mm A"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[mañana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un día",dd:"%d días",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un año",yy:"%d años"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(t(5093))},7730(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),t="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),s=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i],n=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;e.defineLocale("es-mx",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?t[e.month()]:a[e.month()]:a},monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"),weekdaysShort:"dom._lun._mar._mié._jue._vie._sáb.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY H:mm",LLLL:"dddd, D [de] MMMM [de] YYYY H:mm"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[mañana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un día",dd:"%d días",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un año",yy:"%d años"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:0,doy:4},invalidDate:"Fecha inválida"})}(t(5093))},6575:function(e,a,t){!function(e){"use strict"; +var a="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),t="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),s=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i],n=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;e.defineLocale("es-mx",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?t[e.month()]:a[e.month()]:a},monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"),weekdaysShort:"dom._lun._mar._mié._jue._vie._sáb.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY H:mm",LLLL:"dddd, D [de] MMMM [de] YYYY H:mm"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[mañana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un día",dd:"%d días",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un año",yy:"%d años"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:0,doy:4},invalidDate:"Fecha inválida"})}(t(5093))},6575(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),t="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),s=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i],n=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;e.defineLocale("es-us",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?t[e.month()]:a[e.month()]:a},monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"),weekdaysShort:"dom._lun._mar._mié._jue._vie._sáb.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"MM/DD/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY h:mm A",LLLL:"dddd, D [de] MMMM [de] YYYY h:mm A"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[mañana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un día",dd:"%d días",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un año",yy:"%d años"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:0,doy:6}})}(t(5093))},7650:function(e,a,t){!function(e){"use strict"; +var a="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),t="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),s=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i],n=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;e.defineLocale("es-us",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?t[e.month()]:a[e.month()]:a},monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"),weekdaysShort:"dom._lun._mar._mié._jue._vie._sáb.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"MM/DD/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY h:mm A",LLLL:"dddd, D [de] MMMM [de] YYYY h:mm A"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[mañana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un día",dd:"%d días",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un año",yy:"%d años"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:0,doy:6}})}(t(5093))},7650(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),t="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),s=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i],n=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;e.defineLocale("es",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?t[e.month()]:a[e.month()]:a},monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"),weekdaysShort:"dom._lun._mar._mié._jue._vie._sáb.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY H:mm",LLLL:"dddd, D [de] MMMM [de] YYYY H:mm"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[mañana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un día",dd:"%d días",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un año",yy:"%d años"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4},invalidDate:"Fecha inválida"})}(t(5093))},3035:function(e,a,t){!function(e){"use strict"; +var a="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),t="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),s=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i],n=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;e.defineLocale("es",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?t[e.month()]:a[e.month()]:a},monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"),weekdaysShort:"dom._lun._mar._mié._jue._vie._sáb.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY H:mm",LLLL:"dddd, D [de] MMMM [de] YYYY H:mm"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[mañana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un día",dd:"%d días",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un año",yy:"%d años"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4},invalidDate:"Fecha inválida"})}(t(5093))},3035(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e,a,t,s){var n={s:["mõne sekundi","mõni sekund","paar sekundit"],ss:[e+"sekundi",e+"sekundit"],m:["ühe minuti","üks minut"],mm:[e+" minuti",e+" minutit"],h:["ühe tunni","tund aega","üks tund"],hh:[e+" tunni",e+" tundi"],d:["ühe päeva","üks päev"],M:["kuu aja","kuu aega","üks kuu"],MM:[e+" kuu",e+" kuud"],y:["ühe aasta","aasta","üks aasta"],yy:[e+" aasta",e+" aastat"]};return a?n[t][2]?n[t][2]:n[t][1]:s?n[t][0]:n[t][1]}e.defineLocale("et",{months:"jaanuar_veebruar_märts_aprill_mai_juuni_juuli_august_september_oktoober_november_detsember".split("_"),monthsShort:"jaan_veebr_märts_apr_mai_juuni_juuli_aug_sept_okt_nov_dets".split("_"),weekdays:"pühapäev_esmaspäev_teisipäev_kolmapäev_neljapäev_reede_laupäev".split("_"),weekdaysShort:"P_E_T_K_N_R_L".split("_"),weekdaysMin:"P_E_T_K_N_R_L".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[Täna,] LT",nextDay:"[Homme,] LT",nextWeek:"[Järgmine] dddd LT",lastDay:"[Eile,] LT",lastWeek:"[Eelmine] dddd LT",sameElse:"L"},relativeTime:{future:"%s pärast",past:"%s tagasi",s:a,ss:a,m:a,mm:a,h:a,hh:a,d:a,dd:"%d päeva",M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},3508:function(e,a,t){!function(e){"use strict"; +function a(e,a,t,s){var n={s:["mõne sekundi","mõni sekund","paar sekundit"],ss:[e+"sekundi",e+"sekundit"],m:["ühe minuti","üks minut"],mm:[e+" minuti",e+" minutit"],h:["ühe tunni","tund aega","üks tund"],hh:[e+" tunni",e+" tundi"],d:["ühe päeva","üks päev"],M:["kuu aja","kuu aega","üks kuu"],MM:[e+" kuu",e+" kuud"],y:["ühe aasta","aasta","üks aasta"],yy:[e+" aasta",e+" aastat"]};return a?n[t][2]?n[t][2]:n[t][1]:s?n[t][0]:n[t][1]}e.defineLocale("et",{months:"jaanuar_veebruar_märts_aprill_mai_juuni_juuli_august_september_oktoober_november_detsember".split("_"),monthsShort:"jaan_veebr_märts_apr_mai_juuni_juuli_aug_sept_okt_nov_dets".split("_"),weekdays:"pühapäev_esmaspäev_teisipäev_kolmapäev_neljapäev_reede_laupäev".split("_"),weekdaysShort:"P_E_T_K_N_R_L".split("_"),weekdaysMin:"P_E_T_K_N_R_L".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[Täna,] LT",nextDay:"[Homme,] LT",nextWeek:"[Järgmine] dddd LT",lastDay:"[Eile,] LT",lastWeek:"[Eelmine] dddd LT",sameElse:"L"},relativeTime:{future:"%s pärast",past:"%s tagasi",s:a,ss:a,m:a,mm:a,h:a,hh:a,d:a,dd:"%d päeva",M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},3508(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("eu",{months:"urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua".split("_"),monthsShort:"urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.".split("_"),monthsParseExact:!0,weekdays:"igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata".split("_"),weekdaysShort:"ig._al._ar._az._og._ol._lr.".split("_"),weekdaysMin:"ig_al_ar_az_og_ol_lr".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY[ko] MMMM[ren] D[a]",LLL:"YYYY[ko] MMMM[ren] D[a] HH:mm",LLLL:"dddd, YYYY[ko] MMMM[ren] D[a] HH:mm",l:"YYYY-M-D",ll:"YYYY[ko] MMM D[a]",lll:"YYYY[ko] MMM D[a] HH:mm",llll:"ddd, YYYY[ko] MMM D[a] HH:mm"},calendar:{sameDay:"[gaur] LT[etan]",nextDay:"[bihar] LT[etan]",nextWeek:"dddd LT[etan]",lastDay:"[atzo] LT[etan]",lastWeek:"[aurreko] dddd LT[etan]",sameElse:"L"},relativeTime:{future:"%s barru",past:"duela %s",s:"segundo batzuk",ss:"%d segundo",m:"minutu bat",mm:"%d minutu",h:"ordu bat",hh:"%d ordu",d:"egun bat",dd:"%d egun",M:"hilabete bat",MM:"%d hilabete",y:"urte bat",yy:"%d urte"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(t(5093))},119:function(e,a,t){!function(e){"use strict"; +e.defineLocale("eu",{months:"urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua".split("_"),monthsShort:"urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.".split("_"),monthsParseExact:!0,weekdays:"igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata".split("_"),weekdaysShort:"ig._al._ar._az._og._ol._lr.".split("_"),weekdaysMin:"ig_al_ar_az_og_ol_lr".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY[ko] MMMM[ren] D[a]",LLL:"YYYY[ko] MMMM[ren] D[a] HH:mm",LLLL:"dddd, YYYY[ko] MMMM[ren] D[a] HH:mm",l:"YYYY-M-D",ll:"YYYY[ko] MMM D[a]",lll:"YYYY[ko] MMM D[a] HH:mm",llll:"ddd, YYYY[ko] MMM D[a] HH:mm"},calendar:{sameDay:"[gaur] LT[etan]",nextDay:"[bihar] LT[etan]",nextWeek:"dddd LT[etan]",lastDay:"[atzo] LT[etan]",lastWeek:"[aurreko] dddd LT[etan]",sameElse:"L"},relativeTime:{future:"%s barru",past:"duela %s",s:"segundo batzuk",ss:"%d segundo",m:"minutu bat",mm:"%d minutu",h:"ordu bat",hh:"%d ordu",d:"egun bat",dd:"%d egun",M:"hilabete bat",MM:"%d hilabete",y:"urte bat",yy:"%d urte"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(t(5093))},119(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"۱",2:"۲",3:"۳",4:"۴",5:"۵",6:"۶",7:"۷",8:"۸",9:"۹",0:"۰"},t={"۱":"1","۲":"2","۳":"3","۴":"4","۵":"5","۶":"6","۷":"7","۸":"8","۹":"9","۰":"0"};e.defineLocale("fa",{months:"ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر".split("_"),monthsShort:"ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر".split("_"),weekdays:"یک‌شنبه_دوشنبه_سه‌شنبه_چهارشنبه_پنج‌شنبه_جمعه_شنبه".split("_"),weekdaysShort:"یک‌شنبه_دوشنبه_سه‌شنبه_چهارشنبه_پنج‌شنبه_جمعه_شنبه".split("_"),weekdaysMin:"ی_د_س_چ_پ_ج_ش".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},meridiemParse:/قبل از ظهر|بعد از ظهر/,isPM:function(e){return/بعد از ظهر/.test(e)},meridiem:function(e,a,t){return e<12?"قبل از ظهر":"بعد از ظهر"},calendar:{sameDay:"[امروز ساعت] LT",nextDay:"[فردا ساعت] LT",nextWeek:"dddd [ساعت] LT",lastDay:"[دیروز ساعت] LT",lastWeek:"dddd [پیش] [ساعت] LT",sameElse:"L"},relativeTime:{future:"در %s",past:"%s پیش",s:"چند ثانیه",ss:"%d ثانیه",m:"یک دقیقه",mm:"%d دقیقه",h:"یک ساعت",hh:"%d ساعت",d:"یک روز",dd:"%d روز",M:"یک ماه",MM:"%d ماه",y:"یک سال",yy:"%d سال"},preparse:function(e){return e.replace(/[۰-۹]/g,(function(e){return t[e]})).replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]})).replace(/,/g,"،")},dayOfMonthOrdinalParse:/\d{1,2}م/,ordinal:"%dم",week:{dow:6,doy:12}})}(t(5093))},527:function(e,a,t){!function(e){"use strict"; +var a={1:"۱",2:"۲",3:"۳",4:"۴",5:"۵",6:"۶",7:"۷",8:"۸",9:"۹",0:"۰"},t={"۱":"1","۲":"2","۳":"3","۴":"4","۵":"5","۶":"6","۷":"7","۸":"8","۹":"9","۰":"0"};e.defineLocale("fa",{months:"ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر".split("_"),monthsShort:"ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر".split("_"),weekdays:"یک‌شنبه_دوشنبه_سه‌شنبه_چهارشنبه_پنج‌شنبه_جمعه_شنبه".split("_"),weekdaysShort:"یک‌شنبه_دوشنبه_سه‌شنبه_چهارشنبه_پنج‌شنبه_جمعه_شنبه".split("_"),weekdaysMin:"ی_د_س_چ_پ_ج_ش".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},meridiemParse:/قبل از ظهر|بعد از ظهر/,isPM:function(e){return/بعد از ظهر/.test(e)},meridiem:function(e,a,t){return e<12?"قبل از ظهر":"بعد از ظهر"},calendar:{sameDay:"[امروز ساعت] LT",nextDay:"[فردا ساعت] LT",nextWeek:"dddd [ساعت] LT",lastDay:"[دیروز ساعت] LT",lastWeek:"dddd [پیش] [ساعت] LT",sameElse:"L"},relativeTime:{future:"در %s",past:"%s پیش",s:"چند ثانیه",ss:"%d ثانیه",m:"یک دقیقه",mm:"%d دقیقه",h:"یک ساعت",hh:"%d ساعت",d:"یک روز",dd:"%d روز",M:"یک ماه",MM:"%d ماه",y:"یک سال",yy:"%d سال"},preparse:function(e){return e.replace(/[۰-۹]/g,(function(e){return t[e]})).replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]})).replace(/,/g,"،")},dayOfMonthOrdinalParse:/\d{1,2}م/,ordinal:"%dم",week:{dow:6,doy:12}})}(t(5093))},527(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a="nolla yksi kaksi kolme neljä viisi kuusi seitsemän kahdeksan yhdeksän".split(" "),t=["nolla","yhden","kahden","kolmen","neljän","viiden","kuuden",a[7],a[8],a[9]];function s(e,a,t,s){var r="";switch(t){case"s":return s?"muutaman sekunnin":"muutama sekunti";case"ss":r=s?"sekunnin":"sekuntia";break;case"m":return s?"minuutin":"minuutti";case"mm":r=s?"minuutin":"minuuttia";break;case"h":return s?"tunnin":"tunti";case"hh":r=s?"tunnin":"tuntia";break;case"d":return s?"päivän":"päivä";case"dd":r=s?"päivän":"päivää";break;case"M":return s?"kuukauden":"kuukausi";case"MM":r=s?"kuukauden":"kuukautta";break;case"y":return s?"vuoden":"vuosi";case"yy":r=s?"vuoden":"vuotta"}return r=n(e,s)+" "+r}function n(e,s){return e<10?s?t[e]:a[e]:e}e.defineLocale("fi",{months:"tammikuu_helmikuu_maaliskuu_huhtikuu_toukokuu_kesäkuu_heinäkuu_elokuu_syyskuu_lokakuu_marraskuu_joulukuu".split("_"),monthsShort:"tammi_helmi_maalis_huhti_touko_kesä_heinä_elo_syys_loka_marras_joulu".split("_"),weekdays:"sunnuntai_maanantai_tiistai_keskiviikko_torstai_perjantai_lauantai".split("_"),weekdaysShort:"su_ma_ti_ke_to_pe_la".split("_"),weekdaysMin:"su_ma_ti_ke_to_pe_la".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD.MM.YYYY",LL:"Do MMMM[ta] YYYY",LLL:"Do MMMM[ta] YYYY, [klo] HH.mm",LLLL:"dddd, Do MMMM[ta] YYYY, [klo] HH.mm",l:"D.M.YYYY",ll:"Do MMM YYYY",lll:"Do MMM YYYY, [klo] HH.mm",llll:"ddd, Do MMM YYYY, [klo] HH.mm"},calendar:{sameDay:"[tänään] [klo] LT",nextDay:"[huomenna] [klo] LT",nextWeek:"dddd [klo] LT",lastDay:"[eilen] [klo] LT",lastWeek:"[viime] dddd[na] [klo] LT",sameElse:"L"},relativeTime:{future:"%s päästä",past:"%s sitten",s,ss:s,m:s,mm:s,h:s,hh:s,d:s,dd:s,M:s,MM:s,y:s,yy:s},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},5995:function(e,a,t){!function(e){"use strict"; +var a="nolla yksi kaksi kolme neljä viisi kuusi seitsemän kahdeksan yhdeksän".split(" "),t=["nolla","yhden","kahden","kolmen","neljän","viiden","kuuden",a[7],a[8],a[9]];function s(e,a,t,s){var r="";switch(t){case"s":return s?"muutaman sekunnin":"muutama sekunti";case"ss":r=s?"sekunnin":"sekuntia";break;case"m":return s?"minuutin":"minuutti";case"mm":r=s?"minuutin":"minuuttia";break;case"h":return s?"tunnin":"tunti";case"hh":r=s?"tunnin":"tuntia";break;case"d":return s?"päivän":"päivä";case"dd":r=s?"päivän":"päivää";break;case"M":return s?"kuukauden":"kuukausi";case"MM":r=s?"kuukauden":"kuukautta";break;case"y":return s?"vuoden":"vuosi";case"yy":r=s?"vuoden":"vuotta"}return r=n(e,s)+" "+r}function n(e,s){return e<10?s?t[e]:a[e]:e}e.defineLocale("fi",{months:"tammikuu_helmikuu_maaliskuu_huhtikuu_toukokuu_kesäkuu_heinäkuu_elokuu_syyskuu_lokakuu_marraskuu_joulukuu".split("_"),monthsShort:"tammi_helmi_maalis_huhti_touko_kesä_heinä_elo_syys_loka_marras_joulu".split("_"),weekdays:"sunnuntai_maanantai_tiistai_keskiviikko_torstai_perjantai_lauantai".split("_"),weekdaysShort:"su_ma_ti_ke_to_pe_la".split("_"),weekdaysMin:"su_ma_ti_ke_to_pe_la".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD.MM.YYYY",LL:"Do MMMM[ta] YYYY",LLL:"Do MMMM[ta] YYYY, [klo] HH.mm",LLLL:"dddd, Do MMMM[ta] YYYY, [klo] HH.mm",l:"D.M.YYYY",ll:"Do MMM YYYY",lll:"Do MMM YYYY, [klo] HH.mm",llll:"ddd, Do MMM YYYY, [klo] HH.mm"},calendar:{sameDay:"[tänään] [klo] LT",nextDay:"[huomenna] [klo] LT",nextWeek:"dddd [klo] LT",lastDay:"[eilen] [klo] LT",lastWeek:"[viime] dddd[na] [klo] LT",sameElse:"L"},relativeTime:{future:"%s päästä",past:"%s sitten",s,ss:s,m:s,mm:s,h:s,hh:s,d:s,dd:s,M:s,MM:s,y:s,yy:s},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},5995(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("fil",{months:"Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre".split("_"),monthsShort:"Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis".split("_"),weekdays:"Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado".split("_"),weekdaysShort:"Lin_Lun_Mar_Miy_Huw_Biy_Sab".split("_"),weekdaysMin:"Li_Lu_Ma_Mi_Hu_Bi_Sab".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"MM/D/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY HH:mm",LLLL:"dddd, MMMM DD, YYYY HH:mm"},calendar:{sameDay:"LT [ngayong araw]",nextDay:"[Bukas ng] LT",nextWeek:"LT [sa susunod na] dddd",lastDay:"LT [kahapon]",lastWeek:"LT [noong nakaraang] dddd",sameElse:"L"},relativeTime:{future:"sa loob ng %s",past:"%s ang nakalipas",s:"ilang segundo",ss:"%d segundo",m:"isang minuto",mm:"%d minuto",h:"isang oras",hh:"%d oras",d:"isang araw",dd:"%d araw",M:"isang buwan",MM:"%d buwan",y:"isang taon",yy:"%d taon"},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:function(e){return e},week:{dow:1,doy:4}})}(t(5093))},2477:function(e,a,t){!function(e){"use strict"; +e.defineLocale("fil",{months:"Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre".split("_"),monthsShort:"Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis".split("_"),weekdays:"Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado".split("_"),weekdaysShort:"Lin_Lun_Mar_Miy_Huw_Biy_Sab".split("_"),weekdaysMin:"Li_Lu_Ma_Mi_Hu_Bi_Sab".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"MM/D/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY HH:mm",LLLL:"dddd, MMMM DD, YYYY HH:mm"},calendar:{sameDay:"LT [ngayong araw]",nextDay:"[Bukas ng] LT",nextWeek:"LT [sa susunod na] dddd",lastDay:"LT [kahapon]",lastWeek:"LT [noong nakaraang] dddd",sameElse:"L"},relativeTime:{future:"sa loob ng %s",past:"%s ang nakalipas",s:"ilang segundo",ss:"%d segundo",m:"isang minuto",mm:"%d minuto",h:"isang oras",hh:"%d oras",d:"isang araw",dd:"%d araw",M:"isang buwan",MM:"%d buwan",y:"isang taon",yy:"%d taon"},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:function(e){return e},week:{dow:1,doy:4}})}(t(5093))},2477(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("fo",{months:"januar_februar_mars_apríl_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_"),weekdays:"sunnudagur_mánadagur_týsdagur_mikudagur_hósdagur_fríggjadagur_leygardagur".split("_"),weekdaysShort:"sun_mán_týs_mik_hós_frí_ley".split("_"),weekdaysMin:"su_má_tý_mi_hó_fr_le".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D. MMMM, YYYY HH:mm"},calendar:{sameDay:"[Í dag kl.] LT",nextDay:"[Í morgin kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[Í gjár kl.] LT",lastWeek:"[síðstu] dddd [kl] LT",sameElse:"L"},relativeTime:{future:"um %s",past:"%s síðani",s:"fá sekund",ss:"%d sekundir",m:"ein minuttur",mm:"%d minuttir",h:"ein tími",hh:"%d tímar",d:"ein dagur",dd:"%d dagar",M:"ein mánaður",MM:"%d mánaðir",y:"eitt ár",yy:"%d ár"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},6435:function(e,a,t){!function(e){"use strict"; +e.defineLocale("fo",{months:"januar_februar_mars_apríl_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_"),weekdays:"sunnudagur_mánadagur_týsdagur_mikudagur_hósdagur_fríggjadagur_leygardagur".split("_"),weekdaysShort:"sun_mán_týs_mik_hós_frí_ley".split("_"),weekdaysMin:"su_má_tý_mi_hó_fr_le".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D. MMMM, YYYY HH:mm"},calendar:{sameDay:"[Í dag kl.] LT",nextDay:"[Í morgin kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[Í gjár kl.] LT",lastWeek:"[síðstu] dddd [kl] LT",sameElse:"L"},relativeTime:{future:"um %s",past:"%s síðani",s:"fá sekund",ss:"%d sekundir",m:"ein minuttur",mm:"%d minuttir",h:"ein tími",hh:"%d tímar",d:"ein dagur",dd:"%d dagar",M:"ein mánaður",MM:"%d mánaðir",y:"eitt ár",yy:"%d ár"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},6435(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("fr-ca",{months:"janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"),monthsShort:"janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"),monthsParseExact:!0,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"di_lu_ma_me_je_ve_sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd’hui à] LT",nextDay:"[Demain à] LT",nextWeek:"dddd [à] LT",lastDay:"[Hier à] LT",lastWeek:"dddd [dernier à] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",ss:"%d secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(er|e)/,ordinal:function(e,a){switch(a){default:case"M":case"Q":case"D":case"DDD":case"d":return e+(1===e?"er":"e");case"w":case"W":return e+(1===e?"re":"e")}}})}(t(5093))},7892:function(e,a,t){!function(e){"use strict"; +e.defineLocale("fr-ca",{months:"janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"),monthsShort:"janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"),monthsParseExact:!0,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"di_lu_ma_me_je_ve_sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd’hui à] LT",nextDay:"[Demain à] LT",nextWeek:"dddd [à] LT",lastDay:"[Hier à] LT",lastWeek:"dddd [dernier à] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",ss:"%d secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(er|e)/,ordinal:function(e,a){switch(a){default:case"M":case"Q":case"D":case"DDD":case"d":return e+(1===e?"er":"e");case"w":case"W":return e+(1===e?"re":"e")}}})}(t(5093))},7892(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("fr-ch",{months:"janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"),monthsShort:"janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"),monthsParseExact:!0,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"di_lu_ma_me_je_ve_sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd’hui à] LT",nextDay:"[Demain à] LT",nextWeek:"dddd [à] LT",lastDay:"[Hier à] LT",lastWeek:"dddd [dernier à] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",ss:"%d secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(er|e)/,ordinal:function(e,a){switch(a){default:case"M":case"Q":case"D":case"DDD":case"d":return e+(1===e?"er":"e");case"w":case"W":return e+(1===e?"re":"e")}},week:{dow:1,doy:4}})}(t(5093))},5498:function(e,a,t){!function(e){"use strict"; +e.defineLocale("fr-ch",{months:"janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"),monthsShort:"janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"),monthsParseExact:!0,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"di_lu_ma_me_je_ve_sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd’hui à] LT",nextDay:"[Demain à] LT",nextWeek:"dddd [à] LT",lastDay:"[Hier à] LT",lastWeek:"dddd [dernier à] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",ss:"%d secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(er|e)/,ordinal:function(e,a){switch(a){default:case"M":case"Q":case"D":case"DDD":case"d":return e+(1===e?"er":"e");case"w":case"W":return e+(1===e?"re":"e")}},week:{dow:1,doy:4}})}(t(5093))},5498(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a=/^(janvier|février|mars|avril|mai|juin|juillet|août|septembre|octobre|novembre|décembre)/i,t=/(janv\.?|févr\.?|mars|avr\.?|mai|juin|juil\.?|août|sept\.?|oct\.?|nov\.?|déc\.?)/i,s=/(janv\.?|févr\.?|mars|avr\.?|mai|juin|juil\.?|août|sept\.?|oct\.?|nov\.?|déc\.?|janvier|février|mars|avril|mai|juin|juillet|août|septembre|octobre|novembre|décembre)/i,n=[/^janv/i,/^févr/i,/^mars/i,/^avr/i,/^mai/i,/^juin/i,/^juil/i,/^août/i,/^sept/i,/^oct/i,/^nov/i,/^déc/i];e.defineLocale("fr",{months:"janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"),monthsShort:"janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"),monthsRegex:s,monthsShortRegex:s,monthsStrictRegex:a,monthsShortStrictRegex:t,monthsParse:n,longMonthsParse:n,shortMonthsParse:n,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"di_lu_ma_me_je_ve_sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd’hui à] LT",nextDay:"[Demain à] LT",nextWeek:"dddd [à] LT",lastDay:"[Hier à] LT",lastWeek:"dddd [dernier à] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",ss:"%d secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",w:"une semaine",ww:"%d semaines",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(er|)/,ordinal:function(e,a){switch(a){case"D":return e+(1===e?"er":"");default:case"M":case"Q":case"DDD":case"d":return e+(1===e?"er":"e");case"w":case"W":return e+(1===e?"re":"e")}},week:{dow:1,doy:4}})}(t(5093))},7071:function(e,a,t){!function(e){"use strict"; +var a=/^(janvier|février|mars|avril|mai|juin|juillet|août|septembre|octobre|novembre|décembre)/i,t=/(janv\.?|févr\.?|mars|avr\.?|mai|juin|juil\.?|août|sept\.?|oct\.?|nov\.?|déc\.?)/i,s=/(janv\.?|févr\.?|mars|avr\.?|mai|juin|juil\.?|août|sept\.?|oct\.?|nov\.?|déc\.?|janvier|février|mars|avril|mai|juin|juillet|août|septembre|octobre|novembre|décembre)/i,n=[/^janv/i,/^févr/i,/^mars/i,/^avr/i,/^mai/i,/^juin/i,/^juil/i,/^août/i,/^sept/i,/^oct/i,/^nov/i,/^déc/i];e.defineLocale("fr",{months:"janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"),monthsShort:"janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"),monthsRegex:s,monthsShortRegex:s,monthsStrictRegex:a,monthsShortStrictRegex:t,monthsParse:n,longMonthsParse:n,shortMonthsParse:n,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"di_lu_ma_me_je_ve_sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd’hui à] LT",nextDay:"[Demain à] LT",nextWeek:"dddd [à] LT",lastDay:"[Hier à] LT",lastWeek:"dddd [dernier à] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",ss:"%d secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",w:"une semaine",ww:"%d semaines",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(er|)/,ordinal:function(e,a){switch(a){case"D":return e+(1===e?"er":"");default:case"M":case"Q":case"DDD":case"d":return e+(1===e?"er":"e");case"w":case"W":return e+(1===e?"re":"e")}},week:{dow:1,doy:4}})}(t(5093))},7071(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a="jan._feb._mrt._apr._mai_jun._jul._aug._sep._okt._nov._des.".split("_"),t="jan_feb_mrt_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_");e.defineLocale("fy",{months:"jannewaris_febrewaris_maart_april_maaie_juny_july_augustus_septimber_oktober_novimber_desimber".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?t[e.month()]:a[e.month()]:a},monthsParseExact:!0,weekdays:"snein_moandei_tiisdei_woansdei_tongersdei_freed_sneon".split("_"),weekdaysShort:"si._mo._ti._wo._to._fr._so.".split("_"),weekdaysMin:"Si_Mo_Ti_Wo_To_Fr_So".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[hjoed om] LT",nextDay:"[moarn om] LT",nextWeek:"dddd [om] LT",lastDay:"[juster om] LT",lastWeek:"[ôfrûne] dddd [om] LT",sameElse:"L"},relativeTime:{future:"oer %s",past:"%s lyn",s:"in pear sekonden",ss:"%d sekonden",m:"ien minút",mm:"%d minuten",h:"ien oere",hh:"%d oeren",d:"ien dei",dd:"%d dagen",M:"ien moanne",MM:"%d moannen",y:"ien jier",yy:"%d jierren"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})}(t(5093))},1734:function(e,a,t){!function(e){"use strict"; +var a="jan._feb._mrt._apr._mai_jun._jul._aug._sep._okt._nov._des.".split("_"),t="jan_feb_mrt_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_");e.defineLocale("fy",{months:"jannewaris_febrewaris_maart_april_maaie_juny_july_augustus_septimber_oktober_novimber_desimber".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?t[e.month()]:a[e.month()]:a},monthsParseExact:!0,weekdays:"snein_moandei_tiisdei_woansdei_tongersdei_freed_sneon".split("_"),weekdaysShort:"si._mo._ti._wo._to._fr._so.".split("_"),weekdaysMin:"Si_Mo_Ti_Wo_To_Fr_So".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[hjoed om] LT",nextDay:"[moarn om] LT",nextWeek:"dddd [om] LT",lastDay:"[juster om] LT",lastWeek:"[ôfrûne] dddd [om] LT",sameElse:"L"},relativeTime:{future:"oer %s",past:"%s lyn",s:"in pear sekonden",ss:"%d sekonden",m:"ien minút",mm:"%d minuten",h:"ien oere",hh:"%d oeren",d:"ien dei",dd:"%d dagen",M:"ien moanne",MM:"%d moannen",y:"ien jier",yy:"%d jierren"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})}(t(5093))},1734(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a=["Eanáir","Feabhra","Márta","Aibreán","Bealtaine","Meitheamh","Iúil","Lúnasa","Meán Fómhair","Deireadh Fómhair","Samhain","Nollaig"],t=["Ean","Feabh","Márt","Aib","Beal","Meith","Iúil","Lún","M.F.","D.F.","Samh","Noll"],s=["Dé Domhnaigh","Dé Luain","Dé Máirt","Dé Céadaoin","Déardaoin","Dé hAoine","Dé Sathairn"],n=["Domh","Luan","Máirt","Céad","Déar","Aoine","Sath"],r=["Do","Lu","Má","Cé","Dé","A","Sa"];e.defineLocale("ga",{months:a,monthsShort:t,monthsParseExact:!0,weekdays:s,weekdaysShort:n,weekdaysMin:r,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Inniu ag] LT",nextDay:"[Amárach ag] LT",nextWeek:"dddd [ag] LT",lastDay:"[Inné ag] LT",lastWeek:"dddd [seo caite] [ag] LT",sameElse:"L"},relativeTime:{future:"i %s",past:"%s ó shin",s:"cúpla soicind",ss:"%d soicind",m:"nóiméad",mm:"%d nóiméad",h:"uair an chloig",hh:"%d uair an chloig",d:"lá",dd:"%d lá",M:"mí",MM:"%d míonna",y:"bliain",yy:"%d bliain"},dayOfMonthOrdinalParse:/\d{1,2}(d|na|mh)/,ordinal:function(e){return e+(1===e?"d":e%10==2?"na":"mh")},week:{dow:1,doy:4}})}(t(5093))},217:function(e,a,t){!function(e){"use strict"; +var a=["Eanáir","Feabhra","Márta","Aibreán","Bealtaine","Meitheamh","Iúil","Lúnasa","Meán Fómhair","Deireadh Fómhair","Samhain","Nollaig"],t=["Ean","Feabh","Márt","Aib","Beal","Meith","Iúil","Lún","M.F.","D.F.","Samh","Noll"],s=["Dé Domhnaigh","Dé Luain","Dé Máirt","Dé Céadaoin","Déardaoin","Dé hAoine","Dé Sathairn"],n=["Domh","Luan","Máirt","Céad","Déar","Aoine","Sath"],r=["Do","Lu","Má","Cé","Dé","A","Sa"];e.defineLocale("ga",{months:a,monthsShort:t,monthsParseExact:!0,weekdays:s,weekdaysShort:n,weekdaysMin:r,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Inniu ag] LT",nextDay:"[Amárach ag] LT",nextWeek:"dddd [ag] LT",lastDay:"[Inné ag] LT",lastWeek:"dddd [seo caite] [ag] LT",sameElse:"L"},relativeTime:{future:"i %s",past:"%s ó shin",s:"cúpla soicind",ss:"%d soicind",m:"nóiméad",mm:"%d nóiméad",h:"uair an chloig",hh:"%d uair an chloig",d:"lá",dd:"%d lá",M:"mí",MM:"%d míonna",y:"bliain",yy:"%d bliain"},dayOfMonthOrdinalParse:/\d{1,2}(d|na|mh)/,ordinal:function(e){return e+(1===e?"d":e%10==2?"na":"mh")},week:{dow:1,doy:4}})}(t(5093))},217(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a=["Am Faoilleach","An Gearran","Am Màrt","An Giblean","An Cèitean","An t-Ògmhios","An t-Iuchar","An Lùnastal","An t-Sultain","An Dàmhair","An t-Samhain","An Dùbhlachd"],t=["Faoi","Gear","Màrt","Gibl","Cèit","Ògmh","Iuch","Lùn","Sult","Dàmh","Samh","Dùbh"],s=["Didòmhnaich","Diluain","Dimàirt","Diciadain","Diardaoin","Dihaoine","Disathairne"],n=["Did","Dil","Dim","Dic","Dia","Dih","Dis"],r=["Dò","Lu","Mà","Ci","Ar","Ha","Sa"];e.defineLocale("gd",{months:a,monthsShort:t,monthsParseExact:!0,weekdays:s,weekdaysShort:n,weekdaysMin:r,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[An-diugh aig] LT",nextDay:"[A-màireach aig] LT",nextWeek:"dddd [aig] LT",lastDay:"[An-dè aig] LT",lastWeek:"dddd [seo chaidh] [aig] LT",sameElse:"L"},relativeTime:{future:"ann an %s",past:"bho chionn %s",s:"beagan diogan",ss:"%d diogan",m:"mionaid",mm:"%d mionaidean",h:"uair",hh:"%d uairean",d:"latha",dd:"%d latha",M:"mìos",MM:"%d mìosan",y:"bliadhna",yy:"%d bliadhna"},dayOfMonthOrdinalParse:/\d{1,2}(d|na|mh)/,ordinal:function(e){return e+(1===e?"d":e%10==2?"na":"mh")},week:{dow:1,doy:4}})}(t(5093))},7329:function(e,a,t){!function(e){"use strict"; +var a=["Am Faoilleach","An Gearran","Am Màrt","An Giblean","An Cèitean","An t-Ògmhios","An t-Iuchar","An Lùnastal","An t-Sultain","An Dàmhair","An t-Samhain","An Dùbhlachd"],t=["Faoi","Gear","Màrt","Gibl","Cèit","Ògmh","Iuch","Lùn","Sult","Dàmh","Samh","Dùbh"],s=["Didòmhnaich","Diluain","Dimàirt","Diciadain","Diardaoin","Dihaoine","Disathairne"],n=["Did","Dil","Dim","Dic","Dia","Dih","Dis"],r=["Dò","Lu","Mà","Ci","Ar","Ha","Sa"];e.defineLocale("gd",{months:a,monthsShort:t,monthsParseExact:!0,weekdays:s,weekdaysShort:n,weekdaysMin:r,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[An-diugh aig] LT",nextDay:"[A-màireach aig] LT",nextWeek:"dddd [aig] LT",lastDay:"[An-dè aig] LT",lastWeek:"dddd [seo chaidh] [aig] LT",sameElse:"L"},relativeTime:{future:"ann an %s",past:"bho chionn %s",s:"beagan diogan",ss:"%d diogan",m:"mionaid",mm:"%d mionaidean",h:"uair",hh:"%d uairean",d:"latha",dd:"%d latha",M:"mìos",MM:"%d mìosan",y:"bliadhna",yy:"%d bliadhna"},dayOfMonthOrdinalParse:/\d{1,2}(d|na|mh)/,ordinal:function(e){return e+(1===e?"d":e%10==2?"na":"mh")},week:{dow:1,doy:4}})}(t(5093))},7329(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("gl",{months:"xaneiro_febreiro_marzo_abril_maio_xuño_xullo_agosto_setembro_outubro_novembro_decembro".split("_"),monthsShort:"xan._feb._mar._abr._mai._xuñ._xul._ago._set._out._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"domingo_luns_martes_mércores_xoves_venres_sábado".split("_"),weekdaysShort:"dom._lun._mar._mér._xov._ven._sáb.".split("_"),weekdaysMin:"do_lu_ma_mé_xo_ve_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY H:mm",LLLL:"dddd, D [de] MMMM [de] YYYY H:mm"},calendar:{sameDay:function(){return"[hoxe "+(1!==this.hours()?"ás":"á")+"] LT"},nextDay:function(){return"[mañá "+(1!==this.hours()?"ás":"á")+"] LT"},nextWeek:function(){return"dddd ["+(1!==this.hours()?"ás":"a")+"] LT"},lastDay:function(){return"[onte "+(1!==this.hours()?"á":"a")+"] LT"},lastWeek:function(){return"[o] dddd [pasado "+(1!==this.hours()?"ás":"a")+"] LT"},sameElse:"L"},relativeTime:{future:function(e){return 0===e.indexOf("un")?"n"+e:"en "+e},past:"hai %s",s:"uns segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"unha hora",hh:"%d horas",d:"un día",dd:"%d días",M:"un mes",MM:"%d meses",y:"un ano",yy:"%d anos"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(t(5093))},2124:function(e,a,t){!function(e){"use strict"; +e.defineLocale("gl",{months:"xaneiro_febreiro_marzo_abril_maio_xuño_xullo_agosto_setembro_outubro_novembro_decembro".split("_"),monthsShort:"xan._feb._mar._abr._mai._xuñ._xul._ago._set._out._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"domingo_luns_martes_mércores_xoves_venres_sábado".split("_"),weekdaysShort:"dom._lun._mar._mér._xov._ven._sáb.".split("_"),weekdaysMin:"do_lu_ma_mé_xo_ve_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY H:mm",LLLL:"dddd, D [de] MMMM [de] YYYY H:mm"},calendar:{sameDay:function(){return"[hoxe "+(1!==this.hours()?"ás":"á")+"] LT"},nextDay:function(){return"[mañá "+(1!==this.hours()?"ás":"á")+"] LT"},nextWeek:function(){return"dddd ["+(1!==this.hours()?"ás":"a")+"] LT"},lastDay:function(){return"[onte "+(1!==this.hours()?"á":"a")+"] LT"},lastWeek:function(){return"[o] dddd [pasado "+(1!==this.hours()?"ás":"a")+"] LT"},sameElse:"L"},relativeTime:{future:function(e){return 0===e.indexOf("un")?"n"+e:"en "+e},past:"hai %s",s:"uns segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"unha hora",hh:"%d horas",d:"un día",dd:"%d días",M:"un mes",MM:"%d meses",y:"un ano",yy:"%d anos"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(t(5093))},2124(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e,a,t,s){var n={s:["थोडया सॅकंडांनी","थोडे सॅकंड"],ss:[e+" सॅकंडांनी",e+" सॅकंड"],m:["एका मिणटान","एक मिनूट"],mm:[e+" मिणटांनी",e+" मिणटां"],h:["एका वरान","एक वर"],hh:[e+" वरांनी",e+" वरां"],d:["एका दिसान","एक दीस"],dd:[e+" दिसांनी",e+" दीस"],M:["एका म्हयन्यान","एक म्हयनो"],MM:[e+" म्हयन्यानी",e+" म्हयने"],y:["एका वर्सान","एक वर्स"],yy:[e+" वर्सांनी",e+" वर्सां"]};return s?n[t][0]:n[t][1]}e.defineLocale("gom-deva",{months:{standalone:"जानेवारी_फेब्रुवारी_मार्च_एप्रील_मे_जून_जुलय_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर".split("_"),format:"जानेवारीच्या_फेब्रुवारीच्या_मार्चाच्या_एप्रीलाच्या_मेयाच्या_जूनाच्या_जुलयाच्या_ऑगस्टाच्या_सप्टेंबराच्या_ऑक्टोबराच्या_नोव्हेंबराच्या_डिसेंबराच्या".split("_"),isFormat:/MMMM(\s)+D[oD]?/},monthsShort:"जाने._फेब्रु._मार्च_एप्री._मे_जून_जुल._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.".split("_"),monthsParseExact:!0,weekdays:"आयतार_सोमार_मंगळार_बुधवार_बिरेस्तार_सुक्रार_शेनवार".split("_"),weekdaysShort:"आयत._सोम._मंगळ._बुध._ब्रेस्त._सुक्र._शेन.".split("_"),weekdaysMin:"आ_सो_मं_बु_ब्रे_सु_शे".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"A h:mm [वाजतां]",LTS:"A h:mm:ss [वाजतां]",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY A h:mm [वाजतां]",LLLL:"dddd, MMMM Do, YYYY, A h:mm [वाजतां]",llll:"ddd, D MMM YYYY, A h:mm [वाजतां]"},calendar:{sameDay:"[आयज] LT",nextDay:"[फाल्यां] LT",nextWeek:"[फुडलो] dddd[,] LT",lastDay:"[काल] LT",lastWeek:"[फाटलो] dddd[,] LT",sameElse:"L"},relativeTime:{future:"%s",past:"%s आदीं",s:a,ss:a,m:a,mm:a,h:a,hh:a,d:a,dd:a,M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}(वेर)/,ordinal:function(e,a){return"D"===a?e+"वेर":e},week:{dow:0,doy:3},meridiemParse:/राती|सकाळीं|दनपारां|सांजे/,meridiemHour:function(e,a){return 12===e&&(e=0),"राती"===a?e<4?e:e+12:"सकाळीं"===a?e:"दनपारां"===a?e>12?e:e+12:"सांजे"===a?e+12:void 0},meridiem:function(e,a,t){return e<4?"राती":e<12?"सकाळीं":e<16?"दनपारां":e<20?"सांजे":"राती"}})}(t(5093))},3383:function(e,a,t){!function(e){"use strict"; +function a(e,a,t,s){var n={s:["थोडया सॅकंडांनी","थोडे सॅकंड"],ss:[e+" सॅकंडांनी",e+" सॅकंड"],m:["एका मिणटान","एक मिनूट"],mm:[e+" मिणटांनी",e+" मिणटां"],h:["एका वरान","एक वर"],hh:[e+" वरांनी",e+" वरां"],d:["एका दिसान","एक दीस"],dd:[e+" दिसांनी",e+" दीस"],M:["एका म्हयन्यान","एक म्हयनो"],MM:[e+" म्हयन्यानी",e+" म्हयने"],y:["एका वर्सान","एक वर्स"],yy:[e+" वर्सांनी",e+" वर्सां"]};return s?n[t][0]:n[t][1]}e.defineLocale("gom-deva",{months:{standalone:"जानेवारी_फेब्रुवारी_मार्च_एप्रील_मे_जून_जुलय_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर".split("_"),format:"जानेवारीच्या_फेब्रुवारीच्या_मार्चाच्या_एप्रीलाच्या_मेयाच्या_जूनाच्या_जुलयाच्या_ऑगस्टाच्या_सप्टेंबराच्या_ऑक्टोबराच्या_नोव्हेंबराच्या_डिसेंबराच्या".split("_"),isFormat:/MMMM(\s)+D[oD]?/},monthsShort:"जाने._फेब्रु._मार्च_एप्री._मे_जून_जुल._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.".split("_"),monthsParseExact:!0,weekdays:"आयतार_सोमार_मंगळार_बुधवार_बिरेस्तार_सुक्रार_शेनवार".split("_"),weekdaysShort:"आयत._सोम._मंगळ._बुध._ब्रेस्त._सुक्र._शेन.".split("_"),weekdaysMin:"आ_सो_मं_बु_ब्रे_सु_शे".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"A h:mm [वाजतां]",LTS:"A h:mm:ss [वाजतां]",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY A h:mm [वाजतां]",LLLL:"dddd, MMMM Do, YYYY, A h:mm [वाजतां]",llll:"ddd, D MMM YYYY, A h:mm [वाजतां]"},calendar:{sameDay:"[आयज] LT",nextDay:"[फाल्यां] LT",nextWeek:"[फुडलो] dddd[,] LT",lastDay:"[काल] LT",lastWeek:"[फाटलो] dddd[,] LT",sameElse:"L"},relativeTime:{future:"%s",past:"%s आदीं",s:a,ss:a,m:a,mm:a,h:a,hh:a,d:a,dd:a,M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}(वेर)/,ordinal:function(e,a){return"D"===a?e+"वेर":e},week:{dow:0,doy:3},meridiemParse:/राती|सकाळीं|दनपारां|सांजे/,meridiemHour:function(e,a){return 12===e&&(e=0),"राती"===a?e<4?e:e+12:"सकाळीं"===a?e:"दनपारां"===a?e>12?e:e+12:"सांजे"===a?e+12:void 0},meridiem:function(e,a,t){return e<4?"राती":e<12?"सकाळीं":e<16?"दनपारां":e<20?"सांजे":"राती"}})}(t(5093))},3383(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e,a,t,s){var n={s:["thoddea sekondamni","thodde sekond"],ss:[e+" sekondamni",e+" sekond"],m:["eka mintan","ek minut"],mm:[e+" mintamni",e+" mintam"],h:["eka voran","ek vor"],hh:[e+" voramni",e+" voram"],d:["eka disan","ek dis"],dd:[e+" disamni",e+" dis"],M:["eka mhoinean","ek mhoino"],MM:[e+" mhoineamni",e+" mhoine"],y:["eka vorsan","ek voros"],yy:[e+" vorsamni",e+" vorsam"]};return s?n[t][0]:n[t][1]}e.defineLocale("gom-latn",{months:{standalone:"Janer_Febrer_Mars_Abril_Mai_Jun_Julai_Agost_Setembr_Otubr_Novembr_Dezembr".split("_"),format:"Janerachea_Febrerachea_Marsachea_Abrilachea_Maiachea_Junachea_Julaiachea_Agostachea_Setembrachea_Otubrachea_Novembrachea_Dezembrachea".split("_"),isFormat:/MMMM(\s)+D[oD]?/},monthsShort:"Jan._Feb._Mars_Abr._Mai_Jun_Jul._Ago._Set._Otu._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Aitar_Somar_Mongllar_Budhvar_Birestar_Sukrar_Son'var".split("_"),weekdaysShort:"Ait._Som._Mon._Bud._Bre._Suk._Son.".split("_"),weekdaysMin:"Ai_Sm_Mo_Bu_Br_Su_Sn".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"A h:mm [vazta]",LTS:"A h:mm:ss [vazta]",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY A h:mm [vazta]",LLLL:"dddd, MMMM Do, YYYY, A h:mm [vazta]",llll:"ddd, D MMM YYYY, A h:mm [vazta]"},calendar:{sameDay:"[Aiz] LT",nextDay:"[Faleam] LT",nextWeek:"[Fuddlo] dddd[,] LT",lastDay:"[Kal] LT",lastWeek:"[Fattlo] dddd[,] LT",sameElse:"L"},relativeTime:{future:"%s",past:"%s adim",s:a,ss:a,m:a,mm:a,h:a,hh:a,d:a,dd:a,M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}(er)/,ordinal:function(e,a){return"D"===a?e+"er":e},week:{dow:0,doy:3},meridiemParse:/rati|sokallim|donparam|sanje/,meridiemHour:function(e,a){return 12===e&&(e=0),"rati"===a?e<4?e:e+12:"sokallim"===a?e:"donparam"===a?e>12?e:e+12:"sanje"===a?e+12:void 0},meridiem:function(e,a,t){return e<4?"rati":e<12?"sokallim":e<16?"donparam":e<20?"sanje":"rati"}})}(t(5093))},5050:function(e,a,t){!function(e){"use strict"; +function a(e,a,t,s){var n={s:["thoddea sekondamni","thodde sekond"],ss:[e+" sekondamni",e+" sekond"],m:["eka mintan","ek minut"],mm:[e+" mintamni",e+" mintam"],h:["eka voran","ek vor"],hh:[e+" voramni",e+" voram"],d:["eka disan","ek dis"],dd:[e+" disamni",e+" dis"],M:["eka mhoinean","ek mhoino"],MM:[e+" mhoineamni",e+" mhoine"],y:["eka vorsan","ek voros"],yy:[e+" vorsamni",e+" vorsam"]};return s?n[t][0]:n[t][1]}e.defineLocale("gom-latn",{months:{standalone:"Janer_Febrer_Mars_Abril_Mai_Jun_Julai_Agost_Setembr_Otubr_Novembr_Dezembr".split("_"),format:"Janerachea_Febrerachea_Marsachea_Abrilachea_Maiachea_Junachea_Julaiachea_Agostachea_Setembrachea_Otubrachea_Novembrachea_Dezembrachea".split("_"),isFormat:/MMMM(\s)+D[oD]?/},monthsShort:"Jan._Feb._Mars_Abr._Mai_Jun_Jul._Ago._Set._Otu._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Aitar_Somar_Mongllar_Budhvar_Birestar_Sukrar_Son'var".split("_"),weekdaysShort:"Ait._Som._Mon._Bud._Bre._Suk._Son.".split("_"),weekdaysMin:"Ai_Sm_Mo_Bu_Br_Su_Sn".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"A h:mm [vazta]",LTS:"A h:mm:ss [vazta]",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY A h:mm [vazta]",LLLL:"dddd, MMMM Do, YYYY, A h:mm [vazta]",llll:"ddd, D MMM YYYY, A h:mm [vazta]"},calendar:{sameDay:"[Aiz] LT",nextDay:"[Faleam] LT",nextWeek:"[Fuddlo] dddd[,] LT",lastDay:"[Kal] LT",lastWeek:"[Fattlo] dddd[,] LT",sameElse:"L"},relativeTime:{future:"%s",past:"%s adim",s:a,ss:a,m:a,mm:a,h:a,hh:a,d:a,dd:a,M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}(er)/,ordinal:function(e,a){return"D"===a?e+"er":e},week:{dow:0,doy:3},meridiemParse:/rati|sokallim|donparam|sanje/,meridiemHour:function(e,a){return 12===e&&(e=0),"rati"===a?e<4?e:e+12:"sokallim"===a?e:"donparam"===a?e>12?e:e+12:"sanje"===a?e+12:void 0},meridiem:function(e,a,t){return e<4?"rati":e<12?"sokallim":e<16?"donparam":e<20?"sanje":"rati"}})}(t(5093))},5050(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"૧",2:"૨",3:"૩",4:"૪",5:"૫",6:"૬",7:"૭",8:"૮",9:"૯",0:"૦"},t={"૧":"1","૨":"2","૩":"3","૪":"4","૫":"5","૬":"6","૭":"7","૮":"8","૯":"9","૦":"0"};e.defineLocale("gu",{months:"જાન્યુઆરી_ફેબ્રુઆરી_માર્ચ_એપ્રિલ_મે_જૂન_જુલાઈ_ઑગસ્ટ_સપ્ટેમ્બર_ઑક્ટ્બર_નવેમ્બર_ડિસેમ્બર".split("_"),monthsShort:"જાન્યુ._ફેબ્રુ._માર્ચ_એપ્રિ._મે_જૂન_જુલા._ઑગ._સપ્ટે._ઑક્ટ્._નવે._ડિસે.".split("_"),monthsParseExact:!0,weekdays:"રવિવાર_સોમવાર_મંગળવાર_બુધ્વાર_ગુરુવાર_શુક્રવાર_શનિવાર".split("_"),weekdaysShort:"રવિ_સોમ_મંગળ_બુધ્_ગુરુ_શુક્ર_શનિ".split("_"),weekdaysMin:"ર_સો_મં_બુ_ગુ_શુ_શ".split("_"),longDateFormat:{LT:"A h:mm વાગ્યે",LTS:"A h:mm:ss વાગ્યે",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm વાગ્યે",LLLL:"dddd, D MMMM YYYY, A h:mm વાગ્યે"},calendar:{sameDay:"[આજ] LT",nextDay:"[કાલે] LT",nextWeek:"dddd, LT",lastDay:"[ગઇકાલે] LT",lastWeek:"[પાછલા] dddd, LT",sameElse:"L"},relativeTime:{future:"%s મા",past:"%s પહેલા",s:"અમુક પળો",ss:"%d સેકંડ",m:"એક મિનિટ",mm:"%d મિનિટ",h:"એક કલાક",hh:"%d કલાક",d:"એક દિવસ",dd:"%d દિવસ",M:"એક મહિનો",MM:"%d મહિનો",y:"એક વર્ષ",yy:"%d વર્ષ"},preparse:function(e){return e.replace(/[૧૨૩૪૫૬૭૮૯૦]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/રાત|બપોર|સવાર|સાંજ/,meridiemHour:function(e,a){return 12===e&&(e=0),"રાત"===a?e<4?e:e+12:"સવાર"===a?e:"બપોર"===a?e>=10?e:e+12:"સાંજ"===a?e+12:void 0},meridiem:function(e,a,t){return e<4?"રાત":e<10?"સવાર":e<17?"બપોર":e<20?"સાંજ":"રાત"},week:{dow:0,doy:6}})}(t(5093))},1713:function(e,a,t){!function(e){"use strict"; +var a={1:"૧",2:"૨",3:"૩",4:"૪",5:"૫",6:"૬",7:"૭",8:"૮",9:"૯",0:"૦"},t={"૧":"1","૨":"2","૩":"3","૪":"4","૫":"5","૬":"6","૭":"7","૮":"8","૯":"9","૦":"0"};e.defineLocale("gu",{months:"જાન્યુઆરી_ફેબ્રુઆરી_માર્ચ_એપ્રિલ_મે_જૂન_જુલાઈ_ઑગસ્ટ_સપ્ટેમ્બર_ઑક્ટ્બર_નવેમ્બર_ડિસેમ્બર".split("_"),monthsShort:"જાન્યુ._ફેબ્રુ._માર્ચ_એપ્રિ._મે_જૂન_જુલા._ઑગ._સપ્ટે._ઑક્ટ્._નવે._ડિસે.".split("_"),monthsParseExact:!0,weekdays:"રવિવાર_સોમવાર_મંગળવાર_બુધ્વાર_ગુરુવાર_શુક્રવાર_શનિવાર".split("_"),weekdaysShort:"રવિ_સોમ_મંગળ_બુધ્_ગુરુ_શુક્ર_શનિ".split("_"),weekdaysMin:"ર_સો_મં_બુ_ગુ_શુ_શ".split("_"),longDateFormat:{LT:"A h:mm વાગ્યે",LTS:"A h:mm:ss વાગ્યે",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm વાગ્યે",LLLL:"dddd, D MMMM YYYY, A h:mm વાગ્યે"},calendar:{sameDay:"[આજ] LT",nextDay:"[કાલે] LT",nextWeek:"dddd, LT",lastDay:"[ગઇકાલે] LT",lastWeek:"[પાછલા] dddd, LT",sameElse:"L"},relativeTime:{future:"%s મા",past:"%s પહેલા",s:"અમુક પળો",ss:"%d સેકંડ",m:"એક મિનિટ",mm:"%d મિનિટ",h:"એક કલાક",hh:"%d કલાક",d:"એક દિવસ",dd:"%d દિવસ",M:"એક મહિનો",MM:"%d મહિનો",y:"એક વર્ષ",yy:"%d વર્ષ"},preparse:function(e){return e.replace(/[૧૨૩૪૫૬૭૮૯૦]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/રાત|બપોર|સવાર|સાંજ/,meridiemHour:function(e,a){return 12===e&&(e=0),"રાત"===a?e<4?e:e+12:"સવાર"===a?e:"બપોર"===a?e>=10?e:e+12:"સાંજ"===a?e+12:void 0},meridiem:function(e,a,t){return e<4?"રાત":e<10?"સવાર":e<17?"બપોર":e<20?"સાંજ":"રાત"},week:{dow:0,doy:6}})}(t(5093))},1713(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("he",{months:"ינואר_פברואר_מרץ_אפריל_מאי_יוני_יולי_אוגוסט_ספטמבר_אוקטובר_נובמבר_דצמבר".split("_"),monthsShort:"ינו׳_פבר׳_מרץ_אפר׳_מאי_יוני_יולי_אוג׳_ספט׳_אוק׳_נוב׳_דצמ׳".split("_"),weekdays:"ראשון_שני_שלישי_רביעי_חמישי_שישי_שבת".split("_"),weekdaysShort:"א׳_ב׳_ג׳_ד׳_ה׳_ו׳_ש׳".split("_"),weekdaysMin:"א_ב_ג_ד_ה_ו_ש".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [ב]MMMM YYYY",LLL:"D [ב]MMMM YYYY HH:mm",LLLL:"dddd, D [ב]MMMM YYYY HH:mm",l:"D/M/YYYY",ll:"D MMM YYYY",lll:"D MMM YYYY HH:mm",llll:"ddd, D MMM YYYY HH:mm"},calendar:{sameDay:"[היום ב־]LT",nextDay:"[מחר ב־]LT",nextWeek:"dddd [בשעה] LT",lastDay:"[אתמול ב־]LT",lastWeek:"[ביום] dddd [האחרון בשעה] LT",sameElse:"L"},relativeTime:{future:"בעוד %s",past:"לפני %s",s:"מספר שניות",ss:"%d שניות",m:"דקה",mm:"%d דקות",h:"שעה",hh:function(e){return 2===e?"שעתיים":e+" שעות"},d:"יום",dd:function(e){return 2===e?"יומיים":e+" ימים"},M:"חודש",MM:function(e){return 2===e?"חודשיים":e+" חודשים"},y:"שנה",yy:function(e){return 2===e?"שנתיים":e%10==0&&10!==e?e+" שנה":e+" שנים"}},meridiemParse:/אחה"צ|לפנה"צ|אחרי הצהריים|לפני הצהריים|לפנות בוקר|בבוקר|בערב/i,isPM:function(e){return/^(אחה"צ|אחרי הצהריים|בערב)$/.test(e)},meridiem:function(e,a,t){return e<5?"לפנות בוקר":e<10?"בבוקר":e<12?t?'לפנה"צ':"לפני הצהריים":e<18?t?'אחה"צ':"אחרי הצהריים":"בערב"}})}(t(5093))},3861:function(e,a,t){!function(e){"use strict"; +e.defineLocale("he",{months:"ינואר_פברואר_מרץ_אפריל_מאי_יוני_יולי_אוגוסט_ספטמבר_אוקטובר_נובמבר_דצמבר".split("_"),monthsShort:"ינו׳_פבר׳_מרץ_אפר׳_מאי_יוני_יולי_אוג׳_ספט׳_אוק׳_נוב׳_דצמ׳".split("_"),weekdays:"ראשון_שני_שלישי_רביעי_חמישי_שישי_שבת".split("_"),weekdaysShort:"א׳_ב׳_ג׳_ד׳_ה׳_ו׳_ש׳".split("_"),weekdaysMin:"א_ב_ג_ד_ה_ו_ש".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [ב]MMMM YYYY",LLL:"D [ב]MMMM YYYY HH:mm",LLLL:"dddd, D [ב]MMMM YYYY HH:mm",l:"D/M/YYYY",ll:"D MMM YYYY",lll:"D MMM YYYY HH:mm",llll:"ddd, D MMM YYYY HH:mm"},calendar:{sameDay:"[היום ב־]LT",nextDay:"[מחר ב־]LT",nextWeek:"dddd [בשעה] LT",lastDay:"[אתמול ב־]LT",lastWeek:"[ביום] dddd [האחרון בשעה] LT",sameElse:"L"},relativeTime:{future:"בעוד %s",past:"לפני %s",s:"מספר שניות",ss:"%d שניות",m:"דקה",mm:"%d דקות",h:"שעה",hh:function(e){return 2===e?"שעתיים":e+" שעות"},d:"יום",dd:function(e){return 2===e?"יומיים":e+" ימים"},M:"חודש",MM:function(e){return 2===e?"חודשיים":e+" חודשים"},y:"שנה",yy:function(e){return 2===e?"שנתיים":e%10==0&&10!==e?e+" שנה":e+" שנים"}},meridiemParse:/אחה"צ|לפנה"צ|אחרי הצהריים|לפני הצהריים|לפנות בוקר|בבוקר|בערב/i,isPM:function(e){return/^(אחה"צ|אחרי הצהריים|בערב)$/.test(e)},meridiem:function(e,a,t){return e<5?"לפנות בוקר":e<10?"בבוקר":e<12?t?'לפנה"צ':"לפני הצהריים":e<18?t?'אחה"צ':"אחרי הצהריים":"בערב"}})}(t(5093))},3861(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"१",2:"२",3:"३",4:"४",5:"५",6:"६",7:"७",8:"८",9:"९",0:"०"},t={"१":"1","२":"2","३":"3","४":"4","५":"5","६":"6","७":"7","८":"8","९":"9","०":"0"},s=[/^जन/i,/^फ़र|फर/i,/^मार्च/i,/^अप्रै/i,/^मई/i,/^जून/i,/^जुल/i,/^अग/i,/^सितं|सित/i,/^अक्टू/i,/^नव|नवं/i,/^दिसं|दिस/i],n=[/^जन/i,/^फ़र/i,/^मार्च/i,/^अप्रै/i,/^मई/i,/^जून/i,/^जुल/i,/^अग/i,/^सित/i,/^अक्टू/i,/^नव/i,/^दिस/i];e.defineLocale("hi",{months:{format:"जनवरी_फ़रवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितम्बर_अक्टूबर_नवम्बर_दिसम्बर".split("_"),standalone:"जनवरी_फरवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितंबर_अक्टूबर_नवंबर_दिसंबर".split("_")},monthsShort:"जन._फ़र._मार्च_अप्रै._मई_जून_जुल._अग._सित._अक्टू._नव._दिस.".split("_"),weekdays:"रविवार_सोमवार_मंगलवार_बुधवार_गुरूवार_शुक्रवार_शनिवार".split("_"),weekdaysShort:"रवि_सोम_मंगल_बुध_गुरू_शुक्र_शनि".split("_"),weekdaysMin:"र_सो_मं_बु_गु_शु_श".split("_"),longDateFormat:{LT:"A h:mm बजे",LTS:"A h:mm:ss बजे",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm बजे",LLLL:"dddd, D MMMM YYYY, A h:mm बजे"},monthsParse:s,longMonthsParse:s,shortMonthsParse:n,monthsRegex:/^(जनवरी|जन\.?|फ़रवरी|फरवरी|फ़र\.?|मार्च?|अप्रैल|अप्रै\.?|मई?|जून?|जुलाई|जुल\.?|अगस्त|अग\.?|सितम्बर|सितंबर|सित\.?|अक्टूबर|अक्टू\.?|नवम्बर|नवंबर|नव\.?|दिसम्बर|दिसंबर|दिस\.?)/i,monthsShortRegex:/^(जनवरी|जन\.?|फ़रवरी|फरवरी|फ़र\.?|मार्च?|अप्रैल|अप्रै\.?|मई?|जून?|जुलाई|जुल\.?|अगस्त|अग\.?|सितम्बर|सितंबर|सित\.?|अक्टूबर|अक्टू\.?|नवम्बर|नवंबर|नव\.?|दिसम्बर|दिसंबर|दिस\.?)/i,monthsStrictRegex:/^(जनवरी?|फ़रवरी|फरवरी?|मार्च?|अप्रैल?|मई?|जून?|जुलाई?|अगस्त?|सितम्बर|सितंबर|सित?\.?|अक्टूबर|अक्टू\.?|नवम्बर|नवंबर?|दिसम्बर|दिसंबर?)/i,monthsShortStrictRegex:/^(जन\.?|फ़र\.?|मार्च?|अप्रै\.?|मई?|जून?|जुल\.?|अग\.?|सित\.?|अक्टू\.?|नव\.?|दिस\.?)/i,calendar:{sameDay:"[आज] LT",nextDay:"[कल] LT",nextWeek:"dddd, LT",lastDay:"[कल] LT",lastWeek:"[पिछले] dddd, LT",sameElse:"L"},relativeTime:{future:"%s में",past:"%s पहले",s:"कुछ ही क्षण",ss:"%d सेकंड",m:"एक मिनट",mm:"%d मिनट",h:"एक घंटा",hh:"%d घंटे",d:"एक दिन",dd:"%d दिन",M:"एक महीने",MM:"%d महीने",y:"एक वर्ष",yy:"%d वर्ष"},preparse:function(e){return e.replace(/[१२३४५६७८९०]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/रात|सुबह|दोपहर|शाम/,meridiemHour:function(e,a){return 12===e&&(e=0),"रात"===a?e<4?e:e+12:"सुबह"===a?e:"दोपहर"===a?e>=10?e:e+12:"शाम"===a?e+12:void 0},meridiem:function(e,a,t){return e<4?"रात":e<10?"सुबह":e<17?"दोपहर":e<20?"शाम":"रात"},week:{dow:0,doy:6}})}(t(5093))},6308:function(e,a,t){!function(e){"use strict"; +var a={1:"१",2:"२",3:"३",4:"४",5:"५",6:"६",7:"७",8:"८",9:"९",0:"०"},t={"१":"1","२":"2","३":"3","४":"4","५":"5","६":"6","७":"7","८":"8","९":"9","०":"0"},s=[/^जन/i,/^फ़र|फर/i,/^मार्च/i,/^अप्रै/i,/^मई/i,/^जून/i,/^जुल/i,/^अग/i,/^सितं|सित/i,/^अक्टू/i,/^नव|नवं/i,/^दिसं|दिस/i],n=[/^जन/i,/^फ़र/i,/^मार्च/i,/^अप्रै/i,/^मई/i,/^जून/i,/^जुल/i,/^अग/i,/^सित/i,/^अक्टू/i,/^नव/i,/^दिस/i];e.defineLocale("hi",{months:{format:"जनवरी_फ़रवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितम्बर_अक्टूबर_नवम्बर_दिसम्बर".split("_"),standalone:"जनवरी_फरवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितंबर_अक्टूबर_नवंबर_दिसंबर".split("_")},monthsShort:"जन._फ़र._मार्च_अप्रै._मई_जून_जुल._अग._सित._अक्टू._नव._दिस.".split("_"),weekdays:"रविवार_सोमवार_मंगलवार_बुधवार_गुरूवार_शुक्रवार_शनिवार".split("_"),weekdaysShort:"रवि_सोम_मंगल_बुध_गुरू_शुक्र_शनि".split("_"),weekdaysMin:"र_सो_मं_बु_गु_शु_श".split("_"),longDateFormat:{LT:"A h:mm बजे",LTS:"A h:mm:ss बजे",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm बजे",LLLL:"dddd, D MMMM YYYY, A h:mm बजे"},monthsParse:s,longMonthsParse:s,shortMonthsParse:n,monthsRegex:/^(जनवरी|जन\.?|फ़रवरी|फरवरी|फ़र\.?|मार्च?|अप्रैल|अप्रै\.?|मई?|जून?|जुलाई|जुल\.?|अगस्त|अग\.?|सितम्बर|सितंबर|सित\.?|अक्टूबर|अक्टू\.?|नवम्बर|नवंबर|नव\.?|दिसम्बर|दिसंबर|दिस\.?)/i,monthsShortRegex:/^(जनवरी|जन\.?|फ़रवरी|फरवरी|फ़र\.?|मार्च?|अप्रैल|अप्रै\.?|मई?|जून?|जुलाई|जुल\.?|अगस्त|अग\.?|सितम्बर|सितंबर|सित\.?|अक्टूबर|अक्टू\.?|नवम्बर|नवंबर|नव\.?|दिसम्बर|दिसंबर|दिस\.?)/i,monthsStrictRegex:/^(जनवरी?|फ़रवरी|फरवरी?|मार्च?|अप्रैल?|मई?|जून?|जुलाई?|अगस्त?|सितम्बर|सितंबर|सित?\.?|अक्टूबर|अक्टू\.?|नवम्बर|नवंबर?|दिसम्बर|दिसंबर?)/i,monthsShortStrictRegex:/^(जन\.?|फ़र\.?|मार्च?|अप्रै\.?|मई?|जून?|जुल\.?|अग\.?|सित\.?|अक्टू\.?|नव\.?|दिस\.?)/i,calendar:{sameDay:"[आज] LT",nextDay:"[कल] LT",nextWeek:"dddd, LT",lastDay:"[कल] LT",lastWeek:"[पिछले] dddd, LT",sameElse:"L"},relativeTime:{future:"%s में",past:"%s पहले",s:"कुछ ही क्षण",ss:"%d सेकंड",m:"एक मिनट",mm:"%d मिनट",h:"एक घंटा",hh:"%d घंटे",d:"एक दिन",dd:"%d दिन",M:"एक महीने",MM:"%d महीने",y:"एक वर्ष",yy:"%d वर्ष"},preparse:function(e){return e.replace(/[१२३४५६७८९०]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/रात|सुबह|दोपहर|शाम/,meridiemHour:function(e,a){return 12===e&&(e=0),"रात"===a?e<4?e:e+12:"सुबह"===a?e:"दोपहर"===a?e>=10?e:e+12:"शाम"===a?e+12:void 0},meridiem:function(e,a,t){return e<4?"रात":e<10?"सुबह":e<17?"दोपहर":e<20?"शाम":"रात"},week:{dow:0,doy:6}})}(t(5093))},6308(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e,a,t){var s=e+" ";switch(t){case"ss":return s+=1===e?"sekunda":2===e||3===e||4===e?"sekunde":"sekundi";case"m":return a?"jedna minuta":"jedne minute";case"mm":return s+=1===e?"minuta":2===e||3===e||4===e?"minute":"minuta";case"h":return a?"jedan sat":"jednog sata";case"hh":return s+=1===e?"sat":2===e||3===e||4===e?"sata":"sati";case"dd":return s+=1===e?"dan":"dana";case"MM":return s+=1===e?"mjesec":2===e||3===e||4===e?"mjeseca":"mjeseci";case"yy":return s+=1===e?"godina":2===e||3===e||4===e?"godine":"godina"}}e.defineLocale("hr",{months:{format:"siječnja_veljače_ožujka_travnja_svibnja_lipnja_srpnja_kolovoza_rujna_listopada_studenoga_prosinca".split("_"),standalone:"siječanj_veljača_ožujak_travanj_svibanj_lipanj_srpanj_kolovoz_rujan_listopad_studeni_prosinac".split("_")},monthsShort:"sij._velj._ožu._tra._svi._lip._srp._kol._ruj._lis._stu._pro.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"Do MMMM YYYY",LLL:"Do MMMM YYYY H:mm",LLLL:"dddd, Do MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[jučer u] LT",lastWeek:function(){switch(this.day()){case 0:return"[prošlu] [nedjelju] [u] LT";case 3:return"[prošlu] [srijedu] [u] LT";case 6:return"[prošle] [subote] [u] LT";case 1:case 2:case 4:case 5:return"[prošli] dddd [u] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"par sekundi",ss:a,m:a,mm:a,h:a,hh:a,d:"dan",dd:a,M:"mjesec",MM:a,y:"godinu",yy:a},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(t(5093))},609:function(e,a,t){!function(e){"use strict"; +function a(e,a,t){var s=e+" ";switch(t){case"ss":return s+=1===e?"sekunda":2===e||3===e||4===e?"sekunde":"sekundi";case"m":return a?"jedna minuta":"jedne minute";case"mm":return s+=1===e?"minuta":2===e||3===e||4===e?"minute":"minuta";case"h":return a?"jedan sat":"jednog sata";case"hh":return s+=1===e?"sat":2===e||3===e||4===e?"sata":"sati";case"dd":return s+=1===e?"dan":"dana";case"MM":return s+=1===e?"mjesec":2===e||3===e||4===e?"mjeseca":"mjeseci";case"yy":return s+=1===e?"godina":2===e||3===e||4===e?"godine":"godina"}}e.defineLocale("hr",{months:{format:"siječnja_veljače_ožujka_travnja_svibnja_lipnja_srpnja_kolovoza_rujna_listopada_studenoga_prosinca".split("_"),standalone:"siječanj_veljača_ožujak_travanj_svibanj_lipanj_srpanj_kolovoz_rujan_listopad_studeni_prosinac".split("_")},monthsShort:"sij._velj._ožu._tra._svi._lip._srp._kol._ruj._lis._stu._pro.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"Do MMMM YYYY",LLL:"Do MMMM YYYY H:mm",LLLL:"dddd, Do MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[jučer u] LT",lastWeek:function(){switch(this.day()){case 0:return"[prošlu] [nedjelju] [u] LT";case 3:return"[prošlu] [srijedu] [u] LT";case 6:return"[prošle] [subote] [u] LT";case 1:case 2:case 4:case 5:return"[prošli] dddd [u] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"par sekundi",ss:a,m:a,mm:a,h:a,hh:a,d:"dan",dd:a,M:"mjesec",MM:a,y:"godinu",yy:a},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(t(5093))},609(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a="vasárnap hétfőn kedden szerdán csütörtökön pénteken szombaton".split(" ");function t(e,a,t,s){var n=e;switch(t){case"s":return s||a?"néhány másodperc":"néhány másodperce";case"ss":return n+(s||a)?" másodperc":" másodperce";case"m":return"egy"+(s||a?" perc":" perce");case"mm":return n+(s||a?" perc":" perce");case"h":return"egy"+(s||a?" óra":" órája");case"hh":return n+(s||a?" óra":" órája");case"d":return"egy"+(s||a?" nap":" napja");case"dd":return n+(s||a?" nap":" napja");case"M":return"egy"+(s||a?" hónap":" hónapja");case"MM":return n+(s||a?" hónap":" hónapja");case"y":return"egy"+(s||a?" év":" éve");case"yy":return n+(s||a?" év":" éve")}return""}function s(e){return(e?"":"[múlt] ")+"["+a[this.day()]+"] LT[-kor]"}e.defineLocale("hu",{months:"január_február_március_április_május_június_július_augusztus_szeptember_október_november_december".split("_"),monthsShort:"jan._feb._márc._ápr._máj._jún._júl._aug._szept._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"vasárnap_hétfő_kedd_szerda_csütörtök_péntek_szombat".split("_"),weekdaysShort:"vas_hét_kedd_sze_csüt_pén_szo".split("_"),weekdaysMin:"v_h_k_sze_cs_p_szo".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"YYYY.MM.DD.",LL:"YYYY. MMMM D.",LLL:"YYYY. MMMM D. H:mm",LLLL:"YYYY. MMMM D., dddd H:mm"},meridiemParse:/de|du/i,isPM:function(e){return"u"===e.charAt(1).toLowerCase()},meridiem:function(e,a,t){return e<12?!0===t?"de":"DE":!0===t?"du":"DU"},calendar:{sameDay:"[ma] LT[-kor]",nextDay:"[holnap] LT[-kor]",nextWeek:function(){return s.call(this,!0)},lastDay:"[tegnap] LT[-kor]",lastWeek:function(){return s.call(this,!1)},sameElse:"L"},relativeTime:{future:"%s múlva",past:"%s",s:t,ss:t,m:t,mm:t,h:t,hh:t,d:t,dd:t,M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},7160:function(e,a,t){!function(e){"use strict"; +var a="vasárnap hétfőn kedden szerdán csütörtökön pénteken szombaton".split(" ");function t(e,a,t,s){var n=e;switch(t){case"s":return s||a?"néhány másodperc":"néhány másodperce";case"ss":return n+(s||a)?" másodperc":" másodperce";case"m":return"egy"+(s||a?" perc":" perce");case"mm":return n+(s||a?" perc":" perce");case"h":return"egy"+(s||a?" óra":" órája");case"hh":return n+(s||a?" óra":" órája");case"d":return"egy"+(s||a?" nap":" napja");case"dd":return n+(s||a?" nap":" napja");case"M":return"egy"+(s||a?" hónap":" hónapja");case"MM":return n+(s||a?" hónap":" hónapja");case"y":return"egy"+(s||a?" év":" éve");case"yy":return n+(s||a?" év":" éve")}return""}function s(e){return(e?"":"[múlt] ")+"["+a[this.day()]+"] LT[-kor]"}e.defineLocale("hu",{months:"január_február_március_április_május_június_július_augusztus_szeptember_október_november_december".split("_"),monthsShort:"jan._feb._márc._ápr._máj._jún._júl._aug._szept._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"vasárnap_hétfő_kedd_szerda_csütörtök_péntek_szombat".split("_"),weekdaysShort:"vas_hét_kedd_sze_csüt_pén_szo".split("_"),weekdaysMin:"v_h_k_sze_cs_p_szo".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"YYYY.MM.DD.",LL:"YYYY. MMMM D.",LLL:"YYYY. MMMM D. H:mm",LLLL:"YYYY. MMMM D., dddd H:mm"},meridiemParse:/de|du/i,isPM:function(e){return"u"===e.charAt(1).toLowerCase()},meridiem:function(e,a,t){return e<12?!0===t?"de":"DE":!0===t?"du":"DU"},calendar:{sameDay:"[ma] LT[-kor]",nextDay:"[holnap] LT[-kor]",nextWeek:function(){return s.call(this,!0)},lastDay:"[tegnap] LT[-kor]",lastWeek:function(){return s.call(this,!1)},sameElse:"L"},relativeTime:{future:"%s múlva",past:"%s",s:t,ss:t,m:t,mm:t,h:t,hh:t,d:t,dd:t,M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},7160(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("hy-am",{months:{format:"հունվարի_փետրվարի_մարտի_ապրիլի_մայիսի_հունիսի_հուլիսի_օգոստոսի_սեպտեմբերի_հոկտեմբերի_նոյեմբերի_դեկտեմբերի".split("_"),standalone:"հունվար_փետրվար_մարտ_ապրիլ_մայիս_հունիս_հուլիս_օգոստոս_սեպտեմբեր_հոկտեմբեր_նոյեմբեր_դեկտեմբեր".split("_")},monthsShort:"հնվ_փտր_մրտ_ապր_մյս_հնս_հլս_օգս_սպտ_հկտ_նմբ_դկտ".split("_"),weekdays:"կիրակի_երկուշաբթի_երեքշաբթի_չորեքշաբթի_հինգշաբթի_ուրբաթ_շաբաթ".split("_"),weekdaysShort:"կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ".split("_"),weekdaysMin:"կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY թ.",LLL:"D MMMM YYYY թ., HH:mm",LLLL:"dddd, D MMMM YYYY թ., HH:mm"},calendar:{sameDay:"[այսօր] LT",nextDay:"[վաղը] LT",lastDay:"[երեկ] LT",nextWeek:function(){return"dddd [օրը ժամը] LT"},lastWeek:function(){return"[անցած] dddd [օրը ժամը] LT"},sameElse:"L"},relativeTime:{future:"%s հետո",past:"%s առաջ",s:"մի քանի վայրկյան",ss:"%d վայրկյան",m:"րոպե",mm:"%d րոպե",h:"ժամ",hh:"%d ժամ",d:"օր",dd:"%d օր",M:"ամիս",MM:"%d ամիս",y:"տարի",yy:"%d տարի"},meridiemParse:/գիշերվա|առավոտվա|ցերեկվա|երեկոյան/,isPM:function(e){return/^(ցերեկվա|երեկոյան)$/.test(e)},meridiem:function(e){return e<4?"գիշերվա":e<12?"առավոտվա":e<17?"ցերեկվա":"երեկոյան"},dayOfMonthOrdinalParse:/\d{1,2}|\d{1,2}-(ին|րդ)/,ordinal:function(e,a){switch(a){case"DDD":case"w":case"W":case"DDDo":return 1===e?e+"-ին":e+"-րդ";default:return e}},week:{dow:1,doy:7}})}(t(5093))},4063:function(e,a,t){!function(e){"use strict"; +e.defineLocale("hy-am",{months:{format:"հունվարի_փետրվարի_մարտի_ապրիլի_մայիսի_հունիսի_հուլիսի_օգոստոսի_սեպտեմբերի_հոկտեմբերի_նոյեմբերի_դեկտեմբերի".split("_"),standalone:"հունվար_փետրվար_մարտ_ապրիլ_մայիս_հունիս_հուլիս_օգոստոս_սեպտեմբեր_հոկտեմբեր_նոյեմբեր_դեկտեմբեր".split("_")},monthsShort:"հնվ_փտր_մրտ_ապր_մյս_հնս_հլս_օգս_սպտ_հկտ_նմբ_դկտ".split("_"),weekdays:"կիրակի_երկուշաբթի_երեքշաբթի_չորեքշաբթի_հինգշաբթի_ուրբաթ_շաբաթ".split("_"),weekdaysShort:"կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ".split("_"),weekdaysMin:"կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY թ.",LLL:"D MMMM YYYY թ., HH:mm",LLLL:"dddd, D MMMM YYYY թ., HH:mm"},calendar:{sameDay:"[այսօր] LT",nextDay:"[վաղը] LT",lastDay:"[երեկ] LT",nextWeek:function(){return"dddd [օրը ժամը] LT"},lastWeek:function(){return"[անցած] dddd [օրը ժամը] LT"},sameElse:"L"},relativeTime:{future:"%s հետո",past:"%s առաջ",s:"մի քանի վայրկյան",ss:"%d վայրկյան",m:"րոպե",mm:"%d րոպե",h:"ժամ",hh:"%d ժամ",d:"օր",dd:"%d օր",M:"ամիս",MM:"%d ամիս",y:"տարի",yy:"%d տարի"},meridiemParse:/գիշերվա|առավոտվա|ցերեկվա|երեկոյան/,isPM:function(e){return/^(ցերեկվա|երեկոյան)$/.test(e)},meridiem:function(e){return e<4?"գիշերվա":e<12?"առավոտվա":e<17?"ցերեկվա":"երեկոյան"},dayOfMonthOrdinalParse:/\d{1,2}|\d{1,2}-(ին|րդ)/,ordinal:function(e,a){switch(a){case"DDD":case"w":case"W":case"DDDo":return 1===e?e+"-ին":e+"-րդ";default:return e}},week:{dow:1,doy:7}})}(t(5093))},4063(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("id",{months:"Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember".split("_"),monthsShort:"Jan_Feb_Mar_Apr_Mei_Jun_Jul_Agt_Sep_Okt_Nov_Des".split("_"),weekdays:"Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu".split("_"),weekdaysShort:"Min_Sen_Sel_Rab_Kam_Jum_Sab".split("_"),weekdaysMin:"Mg_Sn_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|siang|sore|malam/,meridiemHour:function(e,a){return 12===e&&(e=0),"pagi"===a?e:"siang"===a?e>=11?e:e+12:"sore"===a||"malam"===a?e+12:void 0},meridiem:function(e,a,t){return e<11?"pagi":e<15?"siang":e<19?"sore":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Besok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kemarin pukul] LT",lastWeek:"dddd [lalu pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lalu",s:"beberapa detik",ss:"%d detik",m:"semenit",mm:"%d menit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:0,doy:6}})}(t(5093))},9374:function(e,a,t){!function(e){"use strict"; +e.defineLocale("id",{months:"Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember".split("_"),monthsShort:"Jan_Feb_Mar_Apr_Mei_Jun_Jul_Agt_Sep_Okt_Nov_Des".split("_"),weekdays:"Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu".split("_"),weekdaysShort:"Min_Sen_Sel_Rab_Kam_Jum_Sab".split("_"),weekdaysMin:"Mg_Sn_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|siang|sore|malam/,meridiemHour:function(e,a){return 12===e&&(e=0),"pagi"===a?e:"siang"===a?e>=11?e:e+12:"sore"===a||"malam"===a?e+12:void 0},meridiem:function(e,a,t){return e<11?"pagi":e<15?"siang":e<19?"sore":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Besok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kemarin pukul] LT",lastWeek:"dddd [lalu pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lalu",s:"beberapa detik",ss:"%d detik",m:"semenit",mm:"%d menit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:0,doy:6}})}(t(5093))},9374(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e){return e%100==11||e%10!=1}function t(e,t,s,n){var r=e+" ";switch(s){case"s":return t||n?"nokkrar sekúndur":"nokkrum sekúndum";case"ss":return a(e)?r+(t||n?"sekúndur":"sekúndum"):r+"sekúnda";case"m":return t?"mínúta":"mínútu";case"mm":return a(e)?r+(t||n?"mínútur":"mínútum"):t?r+"mínúta":r+"mínútu";case"hh":return a(e)?r+(t||n?"klukkustundir":"klukkustundum"):r+"klukkustund";case"d":return t?"dagur":n?"dag":"degi";case"dd":return a(e)?t?r+"dagar":r+(n?"daga":"dögum"):t?r+"dagur":r+(n?"dag":"degi");case"M":return t?"mánuður":n?"mánuð":"mánuði";case"MM":return a(e)?t?r+"mánuðir":r+(n?"mánuði":"mánuðum"):t?r+"mánuður":r+(n?"mánuð":"mánuði");case"y":return t||n?"ár":"ári";case"yy":return a(e)?r+(t||n?"ár":"árum"):r+(t||n?"ár":"ári")}}e.defineLocale("is",{months:"janúar_febrúar_mars_apríl_maí_júní_júlí_ágúst_september_október_nóvember_desember".split("_"),monthsShort:"jan_feb_mar_apr_maí_jún_júl_ágú_sep_okt_nóv_des".split("_"),weekdays:"sunnudagur_mánudagur_þriðjudagur_miðvikudagur_fimmtudagur_föstudagur_laugardagur".split("_"),weekdaysShort:"sun_mán_þri_mið_fim_fös_lau".split("_"),weekdaysMin:"Su_Má_Þr_Mi_Fi_Fö_La".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] H:mm",LLLL:"dddd, D. MMMM YYYY [kl.] H:mm"},calendar:{sameDay:"[í dag kl.] LT",nextDay:"[á morgun kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[í gær kl.] LT",lastWeek:"[síðasta] dddd [kl.] LT",sameElse:"L"},relativeTime:{future:"eftir %s",past:"fyrir %s síðan",s:t,ss:t,m:t,mm:t,h:"klukkustund",hh:t,d:t,dd:t,M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},1827:function(e,a,t){!function(e){"use strict"; +function a(e){return e%100==11||e%10!=1}function t(e,t,s,n){var r=e+" ";switch(s){case"s":return t||n?"nokkrar sekúndur":"nokkrum sekúndum";case"ss":return a(e)?r+(t||n?"sekúndur":"sekúndum"):r+"sekúnda";case"m":return t?"mínúta":"mínútu";case"mm":return a(e)?r+(t||n?"mínútur":"mínútum"):t?r+"mínúta":r+"mínútu";case"hh":return a(e)?r+(t||n?"klukkustundir":"klukkustundum"):r+"klukkustund";case"d":return t?"dagur":n?"dag":"degi";case"dd":return a(e)?t?r+"dagar":r+(n?"daga":"dögum"):t?r+"dagur":r+(n?"dag":"degi");case"M":return t?"mánuður":n?"mánuð":"mánuði";case"MM":return a(e)?t?r+"mánuðir":r+(n?"mánuði":"mánuðum"):t?r+"mánuður":r+(n?"mánuð":"mánuði");case"y":return t||n?"ár":"ári";case"yy":return a(e)?r+(t||n?"ár":"árum"):r+(t||n?"ár":"ári")}}e.defineLocale("is",{months:"janúar_febrúar_mars_apríl_maí_júní_júlí_ágúst_september_október_nóvember_desember".split("_"),monthsShort:"jan_feb_mar_apr_maí_jún_júl_ágú_sep_okt_nóv_des".split("_"),weekdays:"sunnudagur_mánudagur_þriðjudagur_miðvikudagur_fimmtudagur_föstudagur_laugardagur".split("_"),weekdaysShort:"sun_mán_þri_mið_fim_fös_lau".split("_"),weekdaysMin:"Su_Má_Þr_Mi_Fi_Fö_La".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] H:mm",LLLL:"dddd, D. MMMM YYYY [kl.] H:mm"},calendar:{sameDay:"[í dag kl.] LT",nextDay:"[á morgun kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[í gær kl.] LT",lastWeek:"[síðasta] dddd [kl.] LT",sameElse:"L"},relativeTime:{future:"eftir %s",past:"fyrir %s síðan",s:t,ss:t,m:t,mm:t,h:"klukkustund",hh:t,d:t,dd:t,M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},1827(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("it-ch",{months:"gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre".split("_"),monthsShort:"gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic".split("_"),weekdays:"domenica_lunedì_martedì_mercoledì_giovedì_venerdì_sabato".split("_"),weekdaysShort:"dom_lun_mar_mer_gio_ven_sab".split("_"),weekdaysMin:"do_lu_ma_me_gi_ve_sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Oggi alle] LT",nextDay:"[Domani alle] LT",nextWeek:"dddd [alle] LT",lastDay:"[Ieri alle] LT",lastWeek:function(){return 0===this.day()?"[la scorsa] dddd [alle] LT":"[lo scorso] dddd [alle] LT"},sameElse:"L"},relativeTime:{future:function(e){return(/^[0-9].+$/.test(e)?"tra":"in")+" "+e},past:"%s fa",s:"alcuni secondi",ss:"%d secondi",m:"un minuto",mm:"%d minuti",h:"un'ora",hh:"%d ore",d:"un giorno",dd:"%d giorni",M:"un mese",MM:"%d mesi",y:"un anno",yy:"%d anni"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(t(5093))},8383:function(e,a,t){!function(e){"use strict"; +e.defineLocale("it-ch",{months:"gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre".split("_"),monthsShort:"gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic".split("_"),weekdays:"domenica_lunedì_martedì_mercoledì_giovedì_venerdì_sabato".split("_"),weekdaysShort:"dom_lun_mar_mer_gio_ven_sab".split("_"),weekdaysMin:"do_lu_ma_me_gi_ve_sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Oggi alle] LT",nextDay:"[Domani alle] LT",nextWeek:"dddd [alle] LT",lastDay:"[Ieri alle] LT",lastWeek:function(){return 0===this.day()?"[la scorsa] dddd [alle] LT":"[lo scorso] dddd [alle] LT"},sameElse:"L"},relativeTime:{future:function(e){return(/^[0-9].+$/.test(e)?"tra":"in")+" "+e},past:"%s fa",s:"alcuni secondi",ss:"%d secondi",m:"un minuto",mm:"%d minuti",h:"un'ora",hh:"%d ore",d:"un giorno",dd:"%d giorni",M:"un mese",MM:"%d mesi",y:"un anno",yy:"%d anni"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(t(5093))},8383(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("it",{months:"gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre".split("_"),monthsShort:"gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic".split("_"),weekdays:"domenica_lunedì_martedì_mercoledì_giovedì_venerdì_sabato".split("_"),weekdaysShort:"dom_lun_mar_mer_gio_ven_sab".split("_"),weekdaysMin:"do_lu_ma_me_gi_ve_sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:function(){return"[Oggi a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},nextDay:function(){return"[Domani a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},nextWeek:function(){return"dddd [a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},lastDay:function(){return"[Ieri a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},lastWeek:function(){return 0===this.day()?"[La scorsa] dddd [a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT":"[Lo scorso] dddd [a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},sameElse:"L"},relativeTime:{future:"tra %s",past:"%s fa",s:"alcuni secondi",ss:"%d secondi",m:"un minuto",mm:"%d minuti",h:"un'ora",hh:"%d ore",d:"un giorno",dd:"%d giorni",w:"una settimana",ww:"%d settimane",M:"un mese",MM:"%d mesi",y:"un anno",yy:"%d anni"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(t(5093))},3827:function(e,a,t){!function(e){"use strict"; +e.defineLocale("it",{months:"gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre".split("_"),monthsShort:"gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic".split("_"),weekdays:"domenica_lunedì_martedì_mercoledì_giovedì_venerdì_sabato".split("_"),weekdaysShort:"dom_lun_mar_mer_gio_ven_sab".split("_"),weekdaysMin:"do_lu_ma_me_gi_ve_sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:function(){return"[Oggi a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},nextDay:function(){return"[Domani a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},nextWeek:function(){return"dddd [a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},lastDay:function(){return"[Ieri a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},lastWeek:function(){return 0===this.day()?"[La scorsa] dddd [a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT":"[Lo scorso] dddd [a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},sameElse:"L"},relativeTime:{future:"tra %s",past:"%s fa",s:"alcuni secondi",ss:"%d secondi",m:"un minuto",mm:"%d minuti",h:"un'ora",hh:"%d ore",d:"un giorno",dd:"%d giorni",w:"una settimana",ww:"%d settimane",M:"un mese",MM:"%d mesi",y:"un anno",yy:"%d anni"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(t(5093))},3827(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("ja",{eras:[{since:"2019-05-01",offset:1,name:"令和",narrow:"㋿",abbr:"R"},{since:"1989-01-08",until:"2019-04-30",offset:1,name:"平成",narrow:"㍻",abbr:"H"},{since:"1926-12-25",until:"1989-01-07",offset:1,name:"昭和",narrow:"㍼",abbr:"S"},{since:"1912-07-30",until:"1926-12-24",offset:1,name:"大正",narrow:"㍽",abbr:"T"},{since:"1873-01-01",until:"1912-07-29",offset:6,name:"明治",narrow:"㍾",abbr:"M"},{since:"0001-01-01",until:"1873-12-31",offset:1,name:"西暦",narrow:"AD",abbr:"AD"},{since:"0000-12-31",until:-1/0,offset:1,name:"紀元前",narrow:"BC",abbr:"BC"}],eraYearOrdinalRegex:/(元|\d+)年/,eraYearOrdinalParse:function(e,a){return"元"===a[1]?1:parseInt(a[1]||e,10)},months:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日".split("_"),weekdaysShort:"日_月_火_水_木_金_土".split("_"),weekdaysMin:"日_月_火_水_木_金_土".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日 dddd HH:mm",l:"YYYY/MM/DD",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日(ddd) HH:mm"},meridiemParse:/午前|午後/i,isPM:function(e){return"午後"===e},meridiem:function(e,a,t){return e<12?"午前":"午後"},calendar:{sameDay:"[今日] LT",nextDay:"[明日] LT",nextWeek:function(e){return e.week()!==this.week()?"[来週]dddd LT":"dddd LT"},lastDay:"[昨日] LT",lastWeek:function(e){return this.week()!==e.week()?"[先週]dddd LT":"dddd LT"},sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}日/,ordinal:function(e,a){switch(a){case"y":return 1===e?"元年":e+"年";case"d":case"D":case"DDD":return e+"日";default:return e}},relativeTime:{future:"%s後",past:"%s前",s:"数秒",ss:"%d秒",m:"1分",mm:"%d分",h:"1時間",hh:"%d時間",d:"1日",dd:"%d日",M:"1ヶ月",MM:"%dヶ月",y:"1年",yy:"%d年"}})}(t(5093))},9722:function(e,a,t){!function(e){"use strict"; +e.defineLocale("ja",{eras:[{since:"2019-05-01",offset:1,name:"令和",narrow:"㋿",abbr:"R"},{since:"1989-01-08",until:"2019-04-30",offset:1,name:"平成",narrow:"㍻",abbr:"H"},{since:"1926-12-25",until:"1989-01-07",offset:1,name:"昭和",narrow:"㍼",abbr:"S"},{since:"1912-07-30",until:"1926-12-24",offset:1,name:"大正",narrow:"㍽",abbr:"T"},{since:"1873-01-01",until:"1912-07-29",offset:6,name:"明治",narrow:"㍾",abbr:"M"},{since:"0001-01-01",until:"1873-12-31",offset:1,name:"西暦",narrow:"AD",abbr:"AD"},{since:"0000-12-31",until:-1/0,offset:1,name:"紀元前",narrow:"BC",abbr:"BC"}],eraYearOrdinalRegex:/(元|\d+)年/,eraYearOrdinalParse:function(e,a){return"元"===a[1]?1:parseInt(a[1]||e,10)},months:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日".split("_"),weekdaysShort:"日_月_火_水_木_金_土".split("_"),weekdaysMin:"日_月_火_水_木_金_土".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日 dddd HH:mm",l:"YYYY/MM/DD",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日(ddd) HH:mm"},meridiemParse:/午前|午後/i,isPM:function(e){return"午後"===e},meridiem:function(e,a,t){return e<12?"午前":"午後"},calendar:{sameDay:"[今日] LT",nextDay:"[明日] LT",nextWeek:function(e){return e.week()!==this.week()?"[来週]dddd LT":"dddd LT"},lastDay:"[昨日] LT",lastWeek:function(e){return this.week()!==e.week()?"[先週]dddd LT":"dddd LT"},sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}日/,ordinal:function(e,a){switch(a){case"y":return 1===e?"元年":e+"年";case"d":case"D":case"DDD":return e+"日";default:return e}},relativeTime:{future:"%s後",past:"%s前",s:"数秒",ss:"%d秒",m:"1分",mm:"%d分",h:"1時間",hh:"%d時間",d:"1日",dd:"%d日",M:"1ヶ月",MM:"%dヶ月",y:"1年",yy:"%d年"}})}(t(5093))},9722(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("jv",{months:"Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_Nopember_Desember".split("_"),monthsShort:"Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nop_Des".split("_"),weekdays:"Minggu_Senen_Seloso_Rebu_Kemis_Jemuwah_Septu".split("_"),weekdaysShort:"Min_Sen_Sel_Reb_Kem_Jem_Sep".split("_"),weekdaysMin:"Mg_Sn_Sl_Rb_Km_Jm_Sp".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/enjing|siyang|sonten|ndalu/,meridiemHour:function(e,a){return 12===e&&(e=0),"enjing"===a?e:"siyang"===a?e>=11?e:e+12:"sonten"===a||"ndalu"===a?e+12:void 0},meridiem:function(e,a,t){return e<11?"enjing":e<15?"siyang":e<19?"sonten":"ndalu"},calendar:{sameDay:"[Dinten puniko pukul] LT",nextDay:"[Mbenjang pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kala wingi pukul] LT",lastWeek:"dddd [kepengker pukul] LT",sameElse:"L"},relativeTime:{future:"wonten ing %s",past:"%s ingkang kepengker",s:"sawetawis detik",ss:"%d detik",m:"setunggal menit",mm:"%d menit",h:"setunggal jam",hh:"%d jam",d:"sedinten",dd:"%d dinten",M:"sewulan",MM:"%d wulan",y:"setaun",yy:"%d taun"},week:{dow:1,doy:7}})}(t(5093))},1794:function(e,a,t){!function(e){"use strict"; +e.defineLocale("jv",{months:"Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_Nopember_Desember".split("_"),monthsShort:"Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nop_Des".split("_"),weekdays:"Minggu_Senen_Seloso_Rebu_Kemis_Jemuwah_Septu".split("_"),weekdaysShort:"Min_Sen_Sel_Reb_Kem_Jem_Sep".split("_"),weekdaysMin:"Mg_Sn_Sl_Rb_Km_Jm_Sp".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/enjing|siyang|sonten|ndalu/,meridiemHour:function(e,a){return 12===e&&(e=0),"enjing"===a?e:"siyang"===a?e>=11?e:e+12:"sonten"===a||"ndalu"===a?e+12:void 0},meridiem:function(e,a,t){return e<11?"enjing":e<15?"siyang":e<19?"sonten":"ndalu"},calendar:{sameDay:"[Dinten puniko pukul] LT",nextDay:"[Mbenjang pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kala wingi pukul] LT",lastWeek:"dddd [kepengker pukul] LT",sameElse:"L"},relativeTime:{future:"wonten ing %s",past:"%s ingkang kepengker",s:"sawetawis detik",ss:"%d detik",m:"setunggal menit",mm:"%d menit",h:"setunggal jam",hh:"%d jam",d:"sedinten",dd:"%d dinten",M:"sewulan",MM:"%d wulan",y:"setaun",yy:"%d taun"},week:{dow:1,doy:7}})}(t(5093))},1794(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("ka",{months:"იანვარი_თებერვალი_მარტი_აპრილი_მაისი_ივნისი_ივლისი_აგვისტო_სექტემბერი_ოქტომბერი_ნოემბერი_დეკემბერი".split("_"),monthsShort:"იან_თებ_მარ_აპრ_მაი_ივნ_ივლ_აგვ_სექ_ოქტ_ნოე_დეკ".split("_"),weekdays:{standalone:"კვირა_ორშაბათი_სამშაბათი_ოთხშაბათი_ხუთშაბათი_პარასკევი_შაბათი".split("_"),format:"კვირას_ორშაბათს_სამშაბათს_ოთხშაბათს_ხუთშაბათს_პარასკევს_შაბათს".split("_"),isFormat:/(წინა|შემდეგ)/},weekdaysShort:"კვი_ორშ_სამ_ოთხ_ხუთ_პარ_შაბ".split("_"),weekdaysMin:"კვ_ორ_სა_ოთ_ხუ_პა_შა".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[დღეს] LT[-ზე]",nextDay:"[ხვალ] LT[-ზე]",lastDay:"[გუშინ] LT[-ზე]",nextWeek:"[შემდეგ] dddd LT[-ზე]",lastWeek:"[წინა] dddd LT-ზე",sameElse:"L"},relativeTime:{future:function(e){return e.replace(/(წამ|წუთ|საათ|წელ|დღ|თვ)(ი|ე)/,(function(e,a,t){return"ი"===t?a+"ში":a+t+"ში"}))},past:function(e){return/(წამი|წუთი|საათი|დღე|თვე)/.test(e)?e.replace(/(ი|ე)$/,"ის წინ"):/წელი/.test(e)?e.replace(/წელი$/,"წლის წინ"):e},s:"რამდენიმე წამი",ss:"%d წამი",m:"წუთი",mm:"%d წუთი",h:"საათი",hh:"%d საათი",d:"დღე",dd:"%d დღე",M:"თვე",MM:"%d თვე",y:"წელი",yy:"%d წელი"},dayOfMonthOrdinalParse:/0|1-ლი|მე-\d{1,2}|\d{1,2}-ე/,ordinal:function(e){return 0===e?e:1===e?e+"-ლი":e<20||e<=100&&e%20==0||e%100==0?"მე-"+e:e+"-ე"},week:{dow:1,doy:7}})}(t(5093))},7088:function(e,a,t){!function(e){"use strict"; +e.defineLocale("ka",{months:"იანვარი_თებერვალი_მარტი_აპრილი_მაისი_ივნისი_ივლისი_აგვისტო_სექტემბერი_ოქტომბერი_ნოემბერი_დეკემბერი".split("_"),monthsShort:"იან_თებ_მარ_აპრ_მაი_ივნ_ივლ_აგვ_სექ_ოქტ_ნოე_დეკ".split("_"),weekdays:{standalone:"კვირა_ორშაბათი_სამშაბათი_ოთხშაბათი_ხუთშაბათი_პარასკევი_შაბათი".split("_"),format:"კვირას_ორშაბათს_სამშაბათს_ოთხშაბათს_ხუთშაბათს_პარასკევს_შაბათს".split("_"),isFormat:/(წინა|შემდეგ)/},weekdaysShort:"კვი_ორშ_სამ_ოთხ_ხუთ_პარ_შაბ".split("_"),weekdaysMin:"კვ_ორ_სა_ოთ_ხუ_პა_შა".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[დღეს] LT[-ზე]",nextDay:"[ხვალ] LT[-ზე]",lastDay:"[გუშინ] LT[-ზე]",nextWeek:"[შემდეგ] dddd LT[-ზე]",lastWeek:"[წინა] dddd LT-ზე",sameElse:"L"},relativeTime:{future:function(e){return e.replace(/(წამ|წუთ|საათ|წელ|დღ|თვ)(ი|ე)/,(function(e,a,t){return"ი"===t?a+"ში":a+t+"ში"}))},past:function(e){return/(წამი|წუთი|საათი|დღე|თვე)/.test(e)?e.replace(/(ი|ე)$/,"ის წინ"):/წელი/.test(e)?e.replace(/წელი$/,"წლის წინ"):e},s:"რამდენიმე წამი",ss:"%d წამი",m:"წუთი",mm:"%d წუთი",h:"საათი",hh:"%d საათი",d:"დღე",dd:"%d დღე",M:"თვე",MM:"%d თვე",y:"წელი",yy:"%d წელი"},dayOfMonthOrdinalParse:/0|1-ლი|მე-\d{1,2}|\d{1,2}-ე/,ordinal:function(e){return 0===e?e:1===e?e+"-ლი":e<20||e<=100&&e%20==0||e%100==0?"მე-"+e:e+"-ე"},week:{dow:1,doy:7}})}(t(5093))},7088(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={0:"-ші",1:"-ші",2:"-ші",3:"-ші",4:"-ші",5:"-ші",6:"-шы",7:"-ші",8:"-ші",9:"-шы",10:"-шы",20:"-шы",30:"-шы",40:"-шы",50:"-ші",60:"-шы",70:"-ші",80:"-ші",90:"-шы",100:"-ші"};e.defineLocale("kk",{months:"қаңтар_ақпан_наурыз_сәуір_мамыр_маусым_шілде_тамыз_қыркүйек_қазан_қараша_желтоқсан".split("_"),monthsShort:"қаң_ақп_нау_сәу_мам_мау_шіл_там_қыр_қаз_қар_жел".split("_"),weekdays:"жексенбі_дүйсенбі_сейсенбі_сәрсенбі_бейсенбі_жұма_сенбі".split("_"),weekdaysShort:"жек_дүй_сей_сәр_бей_жұм_сен".split("_"),weekdaysMin:"жк_дй_сй_ср_бй_жм_сн".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Бүгін сағат] LT",nextDay:"[Ертең сағат] LT",nextWeek:"dddd [сағат] LT",lastDay:"[Кеше сағат] LT",lastWeek:"[Өткен аптаның] dddd [сағат] LT",sameElse:"L"},relativeTime:{future:"%s ішінде",past:"%s бұрын",s:"бірнеше секунд",ss:"%d секунд",m:"бір минут",mm:"%d минут",h:"бір сағат",hh:"%d сағат",d:"бір күн",dd:"%d күн",M:"бір ай",MM:"%d ай",y:"бір жыл",yy:"%d жыл"},dayOfMonthOrdinalParse:/\d{1,2}-(ші|шы)/,ordinal:function(e){var t=e%10,s=e>=100?100:null;return e+(a[e]||a[t]||a[s])},week:{dow:1,doy:7}})}(t(5093))},6870:function(e,a,t){!function(e){"use strict"; +var a={0:"-ші",1:"-ші",2:"-ші",3:"-ші",4:"-ші",5:"-ші",6:"-шы",7:"-ші",8:"-ші",9:"-шы",10:"-шы",20:"-шы",30:"-шы",40:"-шы",50:"-ші",60:"-шы",70:"-ші",80:"-ші",90:"-шы",100:"-ші"};e.defineLocale("kk",{months:"қаңтар_ақпан_наурыз_сәуір_мамыр_маусым_шілде_тамыз_қыркүйек_қазан_қараша_желтоқсан".split("_"),monthsShort:"қаң_ақп_нау_сәу_мам_мау_шіл_там_қыр_қаз_қар_жел".split("_"),weekdays:"жексенбі_дүйсенбі_сейсенбі_сәрсенбі_бейсенбі_жұма_сенбі".split("_"),weekdaysShort:"жек_дүй_сей_сәр_бей_жұм_сен".split("_"),weekdaysMin:"жк_дй_сй_ср_бй_жм_сн".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Бүгін сағат] LT",nextDay:"[Ертең сағат] LT",nextWeek:"dddd [сағат] LT",lastDay:"[Кеше сағат] LT",lastWeek:"[Өткен аптаның] dddd [сағат] LT",sameElse:"L"},relativeTime:{future:"%s ішінде",past:"%s бұрын",s:"бірнеше секунд",ss:"%d секунд",m:"бір минут",mm:"%d минут",h:"бір сағат",hh:"%d сағат",d:"бір күн",dd:"%d күн",M:"бір ай",MM:"%d ай",y:"бір жыл",yy:"%d жыл"},dayOfMonthOrdinalParse:/\d{1,2}-(ші|шы)/,ordinal:function(e){var t=e%10,s=e>=100?100:null;return e+(a[e]||a[t]||a[s])},week:{dow:1,doy:7}})}(t(5093))},6870(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"១",2:"២",3:"៣",4:"៤",5:"៥",6:"៦",7:"៧",8:"៨",9:"៩",0:"០"},t={"១":"1","២":"2","៣":"3","៤":"4","៥":"5","៦":"6","៧":"7","៨":"8","៩":"9","០":"0"};e.defineLocale("km",{months:"មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ".split("_"),monthsShort:"មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ".split("_"),weekdays:"អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍".split("_"),weekdaysShort:"អា_ច_អ_ព_ព្រ_សុ_ស".split("_"),weekdaysMin:"អា_ច_អ_ព_ព្រ_សុ_ស".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},meridiemParse:/ព្រឹក|ល្ងាច/,isPM:function(e){return"ល្ងាច"===e},meridiem:function(e,a,t){return e<12?"ព្រឹក":"ល្ងាច"},calendar:{sameDay:"[ថ្ងៃនេះ ម៉ោង] LT",nextDay:"[ស្អែក ម៉ោង] LT",nextWeek:"dddd [ម៉ោង] LT",lastDay:"[ម្សិលមិញ ម៉ោង] LT",lastWeek:"dddd [សប្តាហ៍មុន] [ម៉ោង] LT",sameElse:"L"},relativeTime:{future:"%sទៀត",past:"%sមុន",s:"ប៉ុន្មានវិនាទី",ss:"%d វិនាទី",m:"មួយនាទី",mm:"%d នាទី",h:"មួយម៉ោង",hh:"%d ម៉ោង",d:"មួយថ្ងៃ",dd:"%d ថ្ងៃ",M:"មួយខែ",MM:"%d ខែ",y:"មួយឆ្នាំ",yy:"%d ឆ្នាំ"},dayOfMonthOrdinalParse:/ទី\d{1,2}/,ordinal:"ទី%d",preparse:function(e){return e.replace(/[១២៣៤៥៦៧៨៩០]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},week:{dow:1,doy:4}})}(t(5093))},4451:function(e,a,t){!function(e){"use strict"; +var a={1:"១",2:"២",3:"៣",4:"៤",5:"៥",6:"៦",7:"៧",8:"៨",9:"៩",0:"០"},t={"១":"1","២":"2","៣":"3","៤":"4","៥":"5","៦":"6","៧":"7","៨":"8","៩":"9","០":"0"};e.defineLocale("km",{months:"មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ".split("_"),monthsShort:"មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ".split("_"),weekdays:"អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍".split("_"),weekdaysShort:"អា_ច_អ_ព_ព្រ_សុ_ស".split("_"),weekdaysMin:"អា_ច_អ_ព_ព្រ_សុ_ស".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},meridiemParse:/ព្រឹក|ល្ងាច/,isPM:function(e){return"ល្ងាច"===e},meridiem:function(e,a,t){return e<12?"ព្រឹក":"ល្ងាច"},calendar:{sameDay:"[ថ្ងៃនេះ ម៉ោង] LT",nextDay:"[ស្អែក ម៉ោង] LT",nextWeek:"dddd [ម៉ោង] LT",lastDay:"[ម្សិលមិញ ម៉ោង] LT",lastWeek:"dddd [សប្តាហ៍មុន] [ម៉ោង] LT",sameElse:"L"},relativeTime:{future:"%sទៀត",past:"%sមុន",s:"ប៉ុន្មានវិនាទី",ss:"%d វិនាទី",m:"មួយនាទី",mm:"%d នាទី",h:"មួយម៉ោង",hh:"%d ម៉ោង",d:"មួយថ្ងៃ",dd:"%d ថ្ងៃ",M:"មួយខែ",MM:"%d ខែ",y:"មួយឆ្នាំ",yy:"%d ឆ្នាំ"},dayOfMonthOrdinalParse:/ទី\d{1,2}/,ordinal:"ទី%d",preparse:function(e){return e.replace(/[១២៣៤៥៦៧៨៩០]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},week:{dow:1,doy:4}})}(t(5093))},4451(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"೧",2:"೨",3:"೩",4:"೪",5:"೫",6:"೬",7:"೭",8:"೮",9:"೯",0:"೦"},t={"೧":"1","೨":"2","೩":"3","೪":"4","೫":"5","೬":"6","೭":"7","೮":"8","೯":"9","೦":"0"};e.defineLocale("kn",{months:"ಜನವರಿ_ಫೆಬ್ರವರಿ_ಮಾರ್ಚ್_ಏಪ್ರಿಲ್_ಮೇ_ಜೂನ್_ಜುಲೈ_ಆಗಸ್ಟ್_ಸೆಪ್ಟೆಂಬರ್_ಅಕ್ಟೋಬರ್_ನವೆಂಬರ್_ಡಿಸೆಂಬರ್".split("_"),monthsShort:"ಜನ_ಫೆಬ್ರ_ಮಾರ್ಚ್_ಏಪ್ರಿಲ್_ಮೇ_ಜೂನ್_ಜುಲೈ_ಆಗಸ್ಟ್_ಸೆಪ್ಟೆಂ_ಅಕ್ಟೋ_ನವೆಂ_ಡಿಸೆಂ".split("_"),monthsParseExact:!0,weekdays:"ಭಾನುವಾರ_ಸೋಮವಾರ_ಮಂಗಳವಾರ_ಬುಧವಾರ_ಗುರುವಾರ_ಶುಕ್ರವಾರ_ಶನಿವಾರ".split("_"),weekdaysShort:"ಭಾನು_ಸೋಮ_ಮಂಗಳ_ಬುಧ_ಗುರು_ಶುಕ್ರ_ಶನಿ".split("_"),weekdaysMin:"ಭಾ_ಸೋ_ಮಂ_ಬು_ಗು_ಶು_ಶ".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[ಇಂದು] LT",nextDay:"[ನಾಳೆ] LT",nextWeek:"dddd, LT",lastDay:"[ನಿನ್ನೆ] LT",lastWeek:"[ಕೊನೆಯ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s ನಂತರ",past:"%s ಹಿಂದೆ",s:"ಕೆಲವು ಕ್ಷಣಗಳು",ss:"%d ಸೆಕೆಂಡುಗಳು",m:"ಒಂದು ನಿಮಿಷ",mm:"%d ನಿಮಿಷ",h:"ಒಂದು ಗಂಟೆ",hh:"%d ಗಂಟೆ",d:"ಒಂದು ದಿನ",dd:"%d ದಿನ",M:"ಒಂದು ತಿಂಗಳು",MM:"%d ತಿಂಗಳು",y:"ಒಂದು ವರ್ಷ",yy:"%d ವರ್ಷ"},preparse:function(e){return e.replace(/[೧೨೩೪೫೬೭೮೯೦]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/ರಾತ್ರಿ|ಬೆಳಿಗ್ಗೆ|ಮಧ್ಯಾಹ್ನ|ಸಂಜೆ/,meridiemHour:function(e,a){return 12===e&&(e=0),"ರಾತ್ರಿ"===a?e<4?e:e+12:"ಬೆಳಿಗ್ಗೆ"===a?e:"ಮಧ್ಯಾಹ್ನ"===a?e>=10?e:e+12:"ಸಂಜೆ"===a?e+12:void 0},meridiem:function(e,a,t){return e<4?"ರಾತ್ರಿ":e<10?"ಬೆಳಿಗ್ಗೆ":e<17?"ಮಧ್ಯಾಹ್ನ":e<20?"ಸಂಜೆ":"ರಾತ್ರಿ"},dayOfMonthOrdinalParse:/\d{1,2}(ನೇ)/,ordinal:function(e){return e+"ನೇ"},week:{dow:0,doy:6}})}(t(5093))},3164:function(e,a,t){!function(e){"use strict"; +var a={1:"೧",2:"೨",3:"೩",4:"೪",5:"೫",6:"೬",7:"೭",8:"೮",9:"೯",0:"೦"},t={"೧":"1","೨":"2","೩":"3","೪":"4","೫":"5","೬":"6","೭":"7","೮":"8","೯":"9","೦":"0"};e.defineLocale("kn",{months:"ಜನವರಿ_ಫೆಬ್ರವರಿ_ಮಾರ್ಚ್_ಏಪ್ರಿಲ್_ಮೇ_ಜೂನ್_ಜುಲೈ_ಆಗಸ್ಟ್_ಸೆಪ್ಟೆಂಬರ್_ಅಕ್ಟೋಬರ್_ನವೆಂಬರ್_ಡಿಸೆಂಬರ್".split("_"),monthsShort:"ಜನ_ಫೆಬ್ರ_ಮಾರ್ಚ್_ಏಪ್ರಿಲ್_ಮೇ_ಜೂನ್_ಜುಲೈ_ಆಗಸ್ಟ್_ಸೆಪ್ಟೆಂ_ಅಕ್ಟೋ_ನವೆಂ_ಡಿಸೆಂ".split("_"),monthsParseExact:!0,weekdays:"ಭಾನುವಾರ_ಸೋಮವಾರ_ಮಂಗಳವಾರ_ಬುಧವಾರ_ಗುರುವಾರ_ಶುಕ್ರವಾರ_ಶನಿವಾರ".split("_"),weekdaysShort:"ಭಾನು_ಸೋಮ_ಮಂಗಳ_ಬುಧ_ಗುರು_ಶುಕ್ರ_ಶನಿ".split("_"),weekdaysMin:"ಭಾ_ಸೋ_ಮಂ_ಬು_ಗು_ಶು_ಶ".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[ಇಂದು] LT",nextDay:"[ನಾಳೆ] LT",nextWeek:"dddd, LT",lastDay:"[ನಿನ್ನೆ] LT",lastWeek:"[ಕೊನೆಯ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s ನಂತರ",past:"%s ಹಿಂದೆ",s:"ಕೆಲವು ಕ್ಷಣಗಳು",ss:"%d ಸೆಕೆಂಡುಗಳು",m:"ಒಂದು ನಿಮಿಷ",mm:"%d ನಿಮಿಷ",h:"ಒಂದು ಗಂಟೆ",hh:"%d ಗಂಟೆ",d:"ಒಂದು ದಿನ",dd:"%d ದಿನ",M:"ಒಂದು ತಿಂಗಳು",MM:"%d ತಿಂಗಳು",y:"ಒಂದು ವರ್ಷ",yy:"%d ವರ್ಷ"},preparse:function(e){return e.replace(/[೧೨೩೪೫೬೭೮೯೦]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/ರಾತ್ರಿ|ಬೆಳಿಗ್ಗೆ|ಮಧ್ಯಾಹ್ನ|ಸಂಜೆ/,meridiemHour:function(e,a){return 12===e&&(e=0),"ರಾತ್ರಿ"===a?e<4?e:e+12:"ಬೆಳಿಗ್ಗೆ"===a?e:"ಮಧ್ಯಾಹ್ನ"===a?e>=10?e:e+12:"ಸಂಜೆ"===a?e+12:void 0},meridiem:function(e,a,t){return e<4?"ರಾತ್ರಿ":e<10?"ಬೆಳಿಗ್ಗೆ":e<17?"ಮಧ್ಯಾಹ್ನ":e<20?"ಸಂಜೆ":"ರಾತ್ರಿ"},dayOfMonthOrdinalParse:/\d{1,2}(ನೇ)/,ordinal:function(e){return e+"ನೇ"},week:{dow:0,doy:6}})}(t(5093))},3164(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("ko",{months:"1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월".split("_"),monthsShort:"1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월".split("_"),weekdays:"일요일_월요일_화요일_수요일_목요일_금요일_토요일".split("_"),weekdaysShort:"일_월_화_수_목_금_토".split("_"),weekdaysMin:"일_월_화_수_목_금_토".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"YYYY.MM.DD.",LL:"YYYY년 MMMM D일",LLL:"YYYY년 MMMM D일 A h:mm",LLLL:"YYYY년 MMMM D일 dddd A h:mm",l:"YYYY.MM.DD.",ll:"YYYY년 MMMM D일",lll:"YYYY년 MMMM D일 A h:mm",llll:"YYYY년 MMMM D일 dddd A h:mm"},calendar:{sameDay:"오늘 LT",nextDay:"내일 LT",nextWeek:"dddd LT",lastDay:"어제 LT",lastWeek:"지난주 dddd LT",sameElse:"L"},relativeTime:{future:"%s 후",past:"%s 전",s:"몇 초",ss:"%d초",m:"1분",mm:"%d분",h:"한 시간",hh:"%d시간",d:"하루",dd:"%d일",M:"한 달",MM:"%d달",y:"일 년",yy:"%d년"},dayOfMonthOrdinalParse:/\d{1,2}(일|월|주)/,ordinal:function(e,a){switch(a){case"d":case"D":case"DDD":return e+"일";case"M":return e+"월";case"w":case"W":return e+"주";default:return e}},meridiemParse:/오전|오후/,isPM:function(e){return"오후"===e},meridiem:function(e,a,t){return e<12?"오전":"오후"}})}(t(5093))},6181:function(e,a,t){!function(e){"use strict"; +e.defineLocale("ko",{months:"1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월".split("_"),monthsShort:"1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월".split("_"),weekdays:"일요일_월요일_화요일_수요일_목요일_금요일_토요일".split("_"),weekdaysShort:"일_월_화_수_목_금_토".split("_"),weekdaysMin:"일_월_화_수_목_금_토".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"YYYY.MM.DD.",LL:"YYYY년 MMMM D일",LLL:"YYYY년 MMMM D일 A h:mm",LLLL:"YYYY년 MMMM D일 dddd A h:mm",l:"YYYY.MM.DD.",ll:"YYYY년 MMMM D일",lll:"YYYY년 MMMM D일 A h:mm",llll:"YYYY년 MMMM D일 dddd A h:mm"},calendar:{sameDay:"오늘 LT",nextDay:"내일 LT",nextWeek:"dddd LT",lastDay:"어제 LT",lastWeek:"지난주 dddd LT",sameElse:"L"},relativeTime:{future:"%s 후",past:"%s 전",s:"몇 초",ss:"%d초",m:"1분",mm:"%d분",h:"한 시간",hh:"%d시간",d:"하루",dd:"%d일",M:"한 달",MM:"%d달",y:"일 년",yy:"%d년"},dayOfMonthOrdinalParse:/\d{1,2}(일|월|주)/,ordinal:function(e,a){switch(a){case"d":case"D":case"DDD":return e+"일";case"M":return e+"월";case"w":case"W":return e+"주";default:return e}},meridiemParse:/오전|오후/,isPM:function(e){return"오후"===e},meridiem:function(e,a,t){return e<12?"오전":"오후"}})}(t(5093))},6181(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e,a,t,s){var n={s:["çend sanîye","çend sanîyeyan"],ss:[e+" sanîye",e+" sanîyeyan"],m:["deqîqeyek","deqîqeyekê"],mm:[e+" deqîqe",e+" deqîqeyan"],h:["saetek","saetekê"],hh:[e+" saet",e+" saetan"],d:["rojek","rojekê"],dd:[e+" roj",e+" rojan"],w:["hefteyek","hefteyekê"],ww:[e+" hefte",e+" hefteyan"],M:["mehek","mehekê"],MM:[e+" meh",e+" mehan"],y:["salek","salekê"],yy:[e+" sal",e+" salan"]};return a?n[t][0]:n[t][1]}function t(e){var a=(e=""+e).substring(e.length-1),t=e.length>1?e.substring(e.length-2):"";return 12==t||13==t||"2"!=a&&"3"!=a&&"50"!=t&&"70"!=a&&"80"!=a?"ê":"yê"}e.defineLocale("ku-kmr",{months:"Rêbendan_Sibat_Adar_Nîsan_Gulan_Hezîran_Tîrmeh_Tebax_Îlon_Cotmeh_Mijdar_Berfanbar".split("_"),monthsShort:"Rêb_Sib_Ada_Nîs_Gul_Hez_Tîr_Teb_Îlo_Cot_Mij_Ber".split("_"),monthsParseExact:!0,weekdays:"Yekşem_Duşem_Sêşem_Çarşem_Pêncşem_În_Şemî".split("_"),weekdaysShort:"Yek_Du_Sê_Çar_Pên_În_Şem".split("_"),weekdaysMin:"Ye_Du_Sê_Ça_Pê_În_Şe".split("_"),meridiem:function(e,a,t){return e<12?t?"bn":"BN":t?"pn":"PN"},meridiemParse:/bn|BN|pn|PN/,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"Do MMMM[a] YYYY[an]",LLL:"Do MMMM[a] YYYY[an] HH:mm",LLLL:"dddd, Do MMMM[a] YYYY[an] HH:mm",ll:"Do MMM[.] YYYY[an]",lll:"Do MMM[.] YYYY[an] HH:mm",llll:"ddd[.], Do MMM[.] YYYY[an] HH:mm"},calendar:{sameDay:"[Îro di saet] LT [de]",nextDay:"[Sibê di saet] LT [de]",nextWeek:"dddd [di saet] LT [de]",lastDay:"[Duh di saet] LT [de]",lastWeek:"dddd[a borî di saet] LT [de]",sameElse:"L"},relativeTime:{future:"di %s de",past:"berî %s",s:a,ss:a,m:a,mm:a,h:a,hh:a,d:a,dd:a,w:a,ww:a,M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}(?:yê|ê|\.)/,ordinal:function(e,a){var s=a.toLowerCase();return s.includes("w")||s.includes("m")?e+".":e+t(e)},week:{dow:1,doy:4}})}(t(5093))},8174:function(e,a,t){!function(e){"use strict"; +function a(e,a,t,s){var n={s:["çend sanîye","çend sanîyeyan"],ss:[e+" sanîye",e+" sanîyeyan"],m:["deqîqeyek","deqîqeyekê"],mm:[e+" deqîqe",e+" deqîqeyan"],h:["saetek","saetekê"],hh:[e+" saet",e+" saetan"],d:["rojek","rojekê"],dd:[e+" roj",e+" rojan"],w:["hefteyek","hefteyekê"],ww:[e+" hefte",e+" hefteyan"],M:["mehek","mehekê"],MM:[e+" meh",e+" mehan"],y:["salek","salekê"],yy:[e+" sal",e+" salan"]};return a?n[t][0]:n[t][1]}function t(e){var a=(e=""+e).substring(e.length-1),t=e.length>1?e.substring(e.length-2):"";return 12==t||13==t||"2"!=a&&"3"!=a&&"50"!=t&&"70"!=a&&"80"!=a?"ê":"yê"}e.defineLocale("ku-kmr",{months:"Rêbendan_Sibat_Adar_Nîsan_Gulan_Hezîran_Tîrmeh_Tebax_Îlon_Cotmeh_Mijdar_Berfanbar".split("_"),monthsShort:"Rêb_Sib_Ada_Nîs_Gul_Hez_Tîr_Teb_Îlo_Cot_Mij_Ber".split("_"),monthsParseExact:!0,weekdays:"Yekşem_Duşem_Sêşem_Çarşem_Pêncşem_În_Şemî".split("_"),weekdaysShort:"Yek_Du_Sê_Çar_Pên_În_Şem".split("_"),weekdaysMin:"Ye_Du_Sê_Ça_Pê_În_Şe".split("_"),meridiem:function(e,a,t){return e<12?t?"bn":"BN":t?"pn":"PN"},meridiemParse:/bn|BN|pn|PN/,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"Do MMMM[a] YYYY[an]",LLL:"Do MMMM[a] YYYY[an] HH:mm",LLLL:"dddd, Do MMMM[a] YYYY[an] HH:mm",ll:"Do MMM[.] YYYY[an]",lll:"Do MMM[.] YYYY[an] HH:mm",llll:"ddd[.], Do MMM[.] YYYY[an] HH:mm"},calendar:{sameDay:"[Îro di saet] LT [de]",nextDay:"[Sibê di saet] LT [de]",nextWeek:"dddd [di saet] LT [de]",lastDay:"[Duh di saet] LT [de]",lastWeek:"dddd[a borî di saet] LT [de]",sameElse:"L"},relativeTime:{future:"di %s de",past:"berî %s",s:a,ss:a,m:a,mm:a,h:a,hh:a,d:a,dd:a,w:a,ww:a,M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}(?:yê|ê|\.)/,ordinal:function(e,a){var s=a.toLowerCase();return s.includes("w")||s.includes("m")?e+".":e+t(e)},week:{dow:1,doy:4}})}(t(5093))},8174(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"١",2:"٢",3:"٣",4:"٤",5:"٥",6:"٦",7:"٧",8:"٨",9:"٩",0:"٠"},t={"١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","٠":"0"},s=["کانونی دووەم","شوبات","ئازار","نیسان","ئایار","حوزەیران","تەمموز","ئاب","ئەیلوول","تشرینی یەكەم","تشرینی دووەم","كانونی یەکەم"];e.defineLocale("ku",{months:s,monthsShort:s,weekdays:"یه‌كشه‌ممه‌_دووشه‌ممه‌_سێشه‌ممه‌_چوارشه‌ممه‌_پێنجشه‌ممه‌_هه‌ینی_شه‌ممه‌".split("_"),weekdaysShort:"یه‌كشه‌م_دووشه‌م_سێشه‌م_چوارشه‌م_پێنجشه‌م_هه‌ینی_شه‌ممه‌".split("_"),weekdaysMin:"ی_د_س_چ_پ_ه_ش".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},meridiemParse:/ئێواره‌|به‌یانی/,isPM:function(e){return/ئێواره‌/.test(e)},meridiem:function(e,a,t){return e<12?"به‌یانی":"ئێواره‌"},calendar:{sameDay:"[ئه‌مرۆ كاتژمێر] LT",nextDay:"[به‌یانی كاتژمێر] LT",nextWeek:"dddd [كاتژمێر] LT",lastDay:"[دوێنێ كاتژمێر] LT",lastWeek:"dddd [كاتژمێر] LT",sameElse:"L"},relativeTime:{future:"له‌ %s",past:"%s",s:"چه‌ند چركه‌یه‌ك",ss:"چركه‌ %d",m:"یه‌ك خوله‌ك",mm:"%d خوله‌ك",h:"یه‌ك كاتژمێر",hh:"%d كاتژمێر",d:"یه‌ك ڕۆژ",dd:"%d ڕۆژ",M:"یه‌ك مانگ",MM:"%d مانگ",y:"یه‌ك ساڵ",yy:"%d ساڵ"},preparse:function(e){return e.replace(/[١٢٣٤٥٦٧٨٩٠]/g,(function(e){return t[e]})).replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]})).replace(/,/g,"،")},week:{dow:6,doy:12}})}(t(5093))},8474:function(e,a,t){!function(e){"use strict"; +var a={1:"١",2:"٢",3:"٣",4:"٤",5:"٥",6:"٦",7:"٧",8:"٨",9:"٩",0:"٠"},t={"١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","٠":"0"},s=["کانونی دووەم","شوبات","ئازار","نیسان","ئایار","حوزەیران","تەمموز","ئاب","ئەیلوول","تشرینی یەكەم","تشرینی دووەم","كانونی یەکەم"];e.defineLocale("ku",{months:s,monthsShort:s,weekdays:"یه‌كشه‌ممه‌_دووشه‌ممه‌_سێشه‌ممه‌_چوارشه‌ممه‌_پێنجشه‌ممه‌_هه‌ینی_شه‌ممه‌".split("_"),weekdaysShort:"یه‌كشه‌م_دووشه‌م_سێشه‌م_چوارشه‌م_پێنجشه‌م_هه‌ینی_شه‌ممه‌".split("_"),weekdaysMin:"ی_د_س_چ_پ_ه_ش".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},meridiemParse:/ئێواره‌|به‌یانی/,isPM:function(e){return/ئێواره‌/.test(e)},meridiem:function(e,a,t){return e<12?"به‌یانی":"ئێواره‌"},calendar:{sameDay:"[ئه‌مرۆ كاتژمێر] LT",nextDay:"[به‌یانی كاتژمێر] LT",nextWeek:"dddd [كاتژمێر] LT",lastDay:"[دوێنێ كاتژمێر] LT",lastWeek:"dddd [كاتژمێر] LT",sameElse:"L"},relativeTime:{future:"له‌ %s",past:"%s",s:"چه‌ند چركه‌یه‌ك",ss:"چركه‌ %d",m:"یه‌ك خوله‌ك",mm:"%d خوله‌ك",h:"یه‌ك كاتژمێر",hh:"%d كاتژمێر",d:"یه‌ك ڕۆژ",dd:"%d ڕۆژ",M:"یه‌ك مانگ",MM:"%d مانگ",y:"یه‌ك ساڵ",yy:"%d ساڵ"},preparse:function(e){return e.replace(/[١٢٣٤٥٦٧٨٩٠]/g,(function(e){return t[e]})).replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]})).replace(/,/g,"،")},week:{dow:6,doy:12}})}(t(5093))},8474(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={0:"-чү",1:"-чи",2:"-чи",3:"-чү",4:"-чү",5:"-чи",6:"-чы",7:"-чи",8:"-чи",9:"-чу",10:"-чу",20:"-чы",30:"-чу",40:"-чы",50:"-чү",60:"-чы",70:"-чи",80:"-чи",90:"-чу",100:"-чү"};e.defineLocale("ky",{months:"январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь".split("_"),monthsShort:"янв_фев_март_апр_май_июнь_июль_авг_сен_окт_ноя_дек".split("_"),weekdays:"Жекшемби_Дүйшөмбү_Шейшемби_Шаршемби_Бейшемби_Жума_Ишемби".split("_"),weekdaysShort:"Жек_Дүй_Шей_Шар_Бей_Жум_Ише".split("_"),weekdaysMin:"Жк_Дй_Шй_Шр_Бй_Жм_Иш".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Бүгүн саат] LT",nextDay:"[Эртең саат] LT",nextWeek:"dddd [саат] LT",lastDay:"[Кечээ саат] LT",lastWeek:"[Өткөн аптанын] dddd [күнү] [саат] LT",sameElse:"L"},relativeTime:{future:"%s ичинде",past:"%s мурун",s:"бирнече секунд",ss:"%d секунд",m:"бир мүнөт",mm:"%d мүнөт",h:"бир саат",hh:"%d саат",d:"бир күн",dd:"%d күн",M:"бир ай",MM:"%d ай",y:"бир жыл",yy:"%d жыл"},dayOfMonthOrdinalParse:/\d{1,2}-(чи|чы|чү|чу)/,ordinal:function(e){var t=e%10,s=e>=100?100:null;return e+(a[e]||a[t]||a[s])},week:{dow:1,doy:7}})}(t(5093))},9680:function(e,a,t){!function(e){"use strict"; +var a={0:"-чү",1:"-чи",2:"-чи",3:"-чү",4:"-чү",5:"-чи",6:"-чы",7:"-чи",8:"-чи",9:"-чу",10:"-чу",20:"-чы",30:"-чу",40:"-чы",50:"-чү",60:"-чы",70:"-чи",80:"-чи",90:"-чу",100:"-чү"};e.defineLocale("ky",{months:"январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь".split("_"),monthsShort:"янв_фев_март_апр_май_июнь_июль_авг_сен_окт_ноя_дек".split("_"),weekdays:"Жекшемби_Дүйшөмбү_Шейшемби_Шаршемби_Бейшемби_Жума_Ишемби".split("_"),weekdaysShort:"Жек_Дүй_Шей_Шар_Бей_Жум_Ише".split("_"),weekdaysMin:"Жк_Дй_Шй_Шр_Бй_Жм_Иш".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Бүгүн саат] LT",nextDay:"[Эртең саат] LT",nextWeek:"dddd [саат] LT",lastDay:"[Кечээ саат] LT",lastWeek:"[Өткөн аптанын] dddd [күнү] [саат] LT",sameElse:"L"},relativeTime:{future:"%s ичинде",past:"%s мурун",s:"бирнече секунд",ss:"%d секунд",m:"бир мүнөт",mm:"%d мүнөт",h:"бир саат",hh:"%d саат",d:"бир күн",dd:"%d күн",M:"бир ай",MM:"%d ай",y:"бир жыл",yy:"%d жыл"},dayOfMonthOrdinalParse:/\d{1,2}-(чи|чы|чү|чу)/,ordinal:function(e){var t=e%10,s=e>=100?100:null;return e+(a[e]||a[t]||a[s])},week:{dow:1,doy:7}})}(t(5093))},9680(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e,a,t,s){var n={m:["eng Minutt","enger Minutt"],h:["eng Stonn","enger Stonn"],d:["een Dag","engem Dag"],M:["ee Mount","engem Mount"],y:["ee Joer","engem Joer"]};return a?n[t][0]:n[t][1]}function t(e){return n(e.substr(0,e.indexOf(" ")))?"a "+e:"an "+e}function s(e){return n(e.substr(0,e.indexOf(" ")))?"viru "+e:"virun "+e}function n(e){if(e=parseInt(e,10),isNaN(e))return!1;if(e<0)return!0;if(e<10)return 4<=e&&e<=7;if(e<100){var a=e%10;return n(0===a?e/10:a)}if(e<1e4){for(;e>=10;)e/=10;return n(e)}return n(e/=1e3)}e.defineLocale("lb",{months:"Januar_Februar_Mäerz_Abrëll_Mee_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Febr._Mrz._Abr._Mee_Jun._Jul._Aug._Sept._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonndeg_Méindeg_Dënschdeg_Mëttwoch_Donneschdeg_Freideg_Samschdeg".split("_"),weekdaysShort:"So._Mé._Dë._Më._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mé_Dë_Më_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm [Auer]",LTS:"H:mm:ss [Auer]",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm [Auer]",LLLL:"dddd, D. MMMM YYYY H:mm [Auer]"},calendar:{sameDay:"[Haut um] LT",sameElse:"L",nextDay:"[Muer um] LT",nextWeek:"dddd [um] LT",lastDay:"[Gëschter um] LT",lastWeek:function(){switch(this.day()){case 2:case 4:return"[Leschten] dddd [um] LT";default:return"[Leschte] dddd [um] LT"}}},relativeTime:{future:t,past:s,s:"e puer Sekonnen",ss:"%d Sekonnen",m:a,mm:"%d Minutten",h:a,hh:"%d Stonnen",d:a,dd:"%d Deeg",M:a,MM:"%d Méint",y:a,yy:"%d Joer"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},5867:function(e,a,t){!function(e){"use strict"; +function a(e,a,t,s){var n={m:["eng Minutt","enger Minutt"],h:["eng Stonn","enger Stonn"],d:["een Dag","engem Dag"],M:["ee Mount","engem Mount"],y:["ee Joer","engem Joer"]};return a?n[t][0]:n[t][1]}function t(e){return n(e.substr(0,e.indexOf(" ")))?"a "+e:"an "+e}function s(e){return n(e.substr(0,e.indexOf(" ")))?"viru "+e:"virun "+e}function n(e){if(e=parseInt(e,10),isNaN(e))return!1;if(e<0)return!0;if(e<10)return 4<=e&&e<=7;if(e<100){var a=e%10;return n(0===a?e/10:a)}if(e<1e4){for(;e>=10;)e/=10;return n(e)}return n(e/=1e3)}e.defineLocale("lb",{months:"Januar_Februar_Mäerz_Abrëll_Mee_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Febr._Mrz._Abr._Mee_Jun._Jul._Aug._Sept._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonndeg_Méindeg_Dënschdeg_Mëttwoch_Donneschdeg_Freideg_Samschdeg".split("_"),weekdaysShort:"So._Mé._Dë._Më._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mé_Dë_Më_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm [Auer]",LTS:"H:mm:ss [Auer]",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm [Auer]",LLLL:"dddd, D. MMMM YYYY H:mm [Auer]"},calendar:{sameDay:"[Haut um] LT",sameElse:"L",nextDay:"[Muer um] LT",nextWeek:"dddd [um] LT",lastDay:"[Gëschter um] LT",lastWeek:function(){switch(this.day()){case 2:case 4:return"[Leschten] dddd [um] LT";default:return"[Leschte] dddd [um] LT"}}},relativeTime:{future:t,past:s,s:"e puer Sekonnen",ss:"%d Sekonnen",m:a,mm:"%d Minutten",h:a,hh:"%d Stonnen",d:a,dd:"%d Deeg",M:a,MM:"%d Méint",y:a,yy:"%d Joer"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},5867(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("lo",{months:"ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ".split("_"),monthsShort:"ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ".split("_"),weekdays:"ອາທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ".split("_"),weekdaysShort:"ທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ".split("_"),weekdaysMin:"ທ_ຈ_ອຄ_ພ_ພຫ_ສກ_ສ".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"ວັນdddd D MMMM YYYY HH:mm"},meridiemParse:/ຕອນເຊົ້າ|ຕອນແລງ/,isPM:function(e){return"ຕອນແລງ"===e},meridiem:function(e,a,t){return e<12?"ຕອນເຊົ້າ":"ຕອນແລງ"},calendar:{sameDay:"[ມື້ນີ້ເວລາ] LT",nextDay:"[ມື້ອື່ນເວລາ] LT",nextWeek:"[ວັນ]dddd[ໜ້າເວລາ] LT",lastDay:"[ມື້ວານນີ້ເວລາ] LT",lastWeek:"[ວັນ]dddd[ແລ້ວນີ້ເວລາ] LT",sameElse:"L"},relativeTime:{future:"ອີກ %s",past:"%sຜ່ານມາ",s:"ບໍ່ເທົ່າໃດວິນາທີ",ss:"%d ວິນາທີ",m:"1 ນາທີ",mm:"%d ນາທີ",h:"1 ຊົ່ວໂມງ",hh:"%d ຊົ່ວໂມງ",d:"1 ມື້",dd:"%d ມື້",M:"1 ເດືອນ",MM:"%d ເດືອນ",y:"1 ປີ",yy:"%d ປີ"},dayOfMonthOrdinalParse:/(ທີ່)\d{1,2}/,ordinal:function(e){return"ທີ່"+e}})}(t(5093))},5766:function(e,a,t){!function(e){"use strict"; +e.defineLocale("lo",{months:"ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ".split("_"),monthsShort:"ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ".split("_"),weekdays:"ອາທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ".split("_"),weekdaysShort:"ທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ".split("_"),weekdaysMin:"ທ_ຈ_ອຄ_ພ_ພຫ_ສກ_ສ".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"ວັນdddd D MMMM YYYY HH:mm"},meridiemParse:/ຕອນເຊົ້າ|ຕອນແລງ/,isPM:function(e){return"ຕອນແລງ"===e},meridiem:function(e,a,t){return e<12?"ຕອນເຊົ້າ":"ຕອນແລງ"},calendar:{sameDay:"[ມື້ນີ້ເວລາ] LT",nextDay:"[ມື້ອື່ນເວລາ] LT",nextWeek:"[ວັນ]dddd[ໜ້າເວລາ] LT",lastDay:"[ມື້ວານນີ້ເວລາ] LT",lastWeek:"[ວັນ]dddd[ແລ້ວນີ້ເວລາ] LT",sameElse:"L"},relativeTime:{future:"ອີກ %s",past:"%sຜ່ານມາ",s:"ບໍ່ເທົ່າໃດວິນາທີ",ss:"%d ວິນາທີ",m:"1 ນາທີ",mm:"%d ນາທີ",h:"1 ຊົ່ວໂມງ",hh:"%d ຊົ່ວໂມງ",d:"1 ມື້",dd:"%d ມື້",M:"1 ເດືອນ",MM:"%d ເດືອນ",y:"1 ປີ",yy:"%d ປີ"},dayOfMonthOrdinalParse:/(ທີ່)\d{1,2}/,ordinal:function(e){return"ທີ່"+e}})}(t(5093))},5766(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={ss:"sekundė_sekundžių_sekundes",m:"minutė_minutės_minutę",mm:"minutės_minučių_minutes",h:"valanda_valandos_valandą",hh:"valandos_valandų_valandas",d:"diena_dienos_dieną",dd:"dienos_dienų_dienas",M:"mėnuo_mėnesio_mėnesį",MM:"mėnesiai_mėnesių_mėnesius",y:"metai_metų_metus",yy:"metai_metų_metus"};function t(e,a,t,s){return a?"kelios sekundės":s?"kelių sekundžių":"kelias sekundes"}function s(e,a,t,s){return a?r(t)[0]:s?r(t)[1]:r(t)[2]}function n(e){return e%10==0||e>10&&e<20}function r(e){return a[e].split("_")}function i(e,a,t,i){var d=e+" ";return 1===e?d+s(e,a,t[0],i):a?d+(n(e)?r(t)[1]:r(t)[0]):i?d+r(t)[1]:d+(n(e)?r(t)[1]:r(t)[2])}e.defineLocale("lt",{months:{format:"sausio_vasario_kovo_balandžio_gegužės_birželio_liepos_rugpjūčio_rugsėjo_spalio_lapkričio_gruodžio".split("_"),standalone:"sausis_vasaris_kovas_balandis_gegužė_birželis_liepa_rugpjūtis_rugsėjis_spalis_lapkritis_gruodis".split("_"),isFormat:/D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|MMMM?(\[[^\[\]]*\]|\s)+D[oD]?/},monthsShort:"sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd".split("_"),weekdays:{format:"sekmadienį_pirmadienį_antradienį_trečiadienį_ketvirtadienį_penktadienį_šeštadienį".split("_"),standalone:"sekmadienis_pirmadienis_antradienis_trečiadienis_ketvirtadienis_penktadienis_šeštadienis".split("_"),isFormat:/dddd HH:mm/},weekdaysShort:"Sek_Pir_Ant_Tre_Ket_Pen_Šeš".split("_"),weekdaysMin:"S_P_A_T_K_Pn_Š".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY [m.] MMMM D [d.]",LLL:"YYYY [m.] MMMM D [d.], HH:mm [val.]",LLLL:"YYYY [m.] MMMM D [d.], dddd, HH:mm [val.]",l:"YYYY-MM-DD",ll:"YYYY [m.] MMMM D [d.]",lll:"YYYY [m.] MMMM D [d.], HH:mm [val.]",llll:"YYYY [m.] MMMM D [d.], ddd, HH:mm [val.]"},calendar:{sameDay:"[Šiandien] LT",nextDay:"[Rytoj] LT",nextWeek:"dddd LT",lastDay:"[Vakar] LT",lastWeek:"[Praėjusį] dddd LT",sameElse:"L"},relativeTime:{future:"po %s",past:"prieš %s",s:t,ss:i,m:s,mm:i,h:s,hh:i,d:s,dd:i,M:s,MM:i,y:s,yy:i},dayOfMonthOrdinalParse:/\d{1,2}-oji/,ordinal:function(e){return e+"-oji"},week:{dow:1,doy:4}})}(t(5093))},9532:function(e,a,t){!function(e){"use strict"; +var a={ss:"sekundė_sekundžių_sekundes",m:"minutė_minutės_minutę",mm:"minutės_minučių_minutes",h:"valanda_valandos_valandą",hh:"valandos_valandų_valandas",d:"diena_dienos_dieną",dd:"dienos_dienų_dienas",M:"mėnuo_mėnesio_mėnesį",MM:"mėnesiai_mėnesių_mėnesius",y:"metai_metų_metus",yy:"metai_metų_metus"};function t(e,a,t,s){return a?"kelios sekundės":s?"kelių sekundžių":"kelias sekundes"}function s(e,a,t,s){return a?r(t)[0]:s?r(t)[1]:r(t)[2]}function n(e){return e%10==0||e>10&&e<20}function r(e){return a[e].split("_")}function d(e,a,t,d){var i=e+" ";return 1===e?i+s(e,a,t[0],d):a?i+(n(e)?r(t)[1]:r(t)[0]):d?i+r(t)[1]:i+(n(e)?r(t)[1]:r(t)[2])}e.defineLocale("lt",{months:{format:"sausio_vasario_kovo_balandžio_gegužės_birželio_liepos_rugpjūčio_rugsėjo_spalio_lapkričio_gruodžio".split("_"),standalone:"sausis_vasaris_kovas_balandis_gegužė_birželis_liepa_rugpjūtis_rugsėjis_spalis_lapkritis_gruodis".split("_"),isFormat:/D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|MMMM?(\[[^\[\]]*\]|\s)+D[oD]?/},monthsShort:"sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd".split("_"),weekdays:{format:"sekmadienį_pirmadienį_antradienį_trečiadienį_ketvirtadienį_penktadienį_šeštadienį".split("_"),standalone:"sekmadienis_pirmadienis_antradienis_trečiadienis_ketvirtadienis_penktadienis_šeštadienis".split("_"),isFormat:/dddd HH:mm/},weekdaysShort:"Sek_Pir_Ant_Tre_Ket_Pen_Šeš".split("_"),weekdaysMin:"S_P_A_T_K_Pn_Š".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY [m.] MMMM D [d.]",LLL:"YYYY [m.] MMMM D [d.], HH:mm [val.]",LLLL:"YYYY [m.] MMMM D [d.], dddd, HH:mm [val.]",l:"YYYY-MM-DD",ll:"YYYY [m.] MMMM D [d.]",lll:"YYYY [m.] MMMM D [d.], HH:mm [val.]",llll:"YYYY [m.] MMMM D [d.], ddd, HH:mm [val.]"},calendar:{sameDay:"[Šiandien] LT",nextDay:"[Rytoj] LT",nextWeek:"dddd LT",lastDay:"[Vakar] LT",lastWeek:"[Praėjusį] dddd LT",sameElse:"L"},relativeTime:{future:"po %s",past:"prieš %s",s:t,ss:d,m:s,mm:d,h:s,hh:d,d:s,dd:d,M:s,MM:d,y:s,yy:d},dayOfMonthOrdinalParse:/\d{1,2}-oji/,ordinal:function(e){return e+"-oji"},week:{dow:1,doy:4}})}(t(5093))},9532(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={ss:"sekundes_sekundēm_sekunde_sekundes".split("_"),m:"minūtes_minūtēm_minūte_minūtes".split("_"),mm:"minūtes_minūtēm_minūte_minūtes".split("_"),h:"stundas_stundām_stunda_stundas".split("_"),hh:"stundas_stundām_stunda_stundas".split("_"),d:"dienas_dienām_diena_dienas".split("_"),dd:"dienas_dienām_diena_dienas".split("_"),M:"mēneša_mēnešiem_mēnesis_mēneši".split("_"),MM:"mēneša_mēnešiem_mēnesis_mēneši".split("_"),y:"gada_gadiem_gads_gadi".split("_"),yy:"gada_gadiem_gads_gadi".split("_")};function t(e,a,t){return t?a%10==1&&a%100!=11?e[2]:e[3]:a%10==1&&a%100!=11?e[0]:e[1]}function s(e,s,n){return e+" "+t(a[n],e,s)}function n(e,s,n){return t(a[n],e,s)}function r(e,a){return a?"dažas sekundes":"dažām sekundēm"}e.defineLocale("lv",{months:"janvāris_februāris_marts_aprīlis_maijs_jūnijs_jūlijs_augusts_septembris_oktobris_novembris_decembris".split("_"),monthsShort:"jan_feb_mar_apr_mai_jūn_jūl_aug_sep_okt_nov_dec".split("_"),weekdays:"svētdiena_pirmdiena_otrdiena_trešdiena_ceturtdiena_piektdiena_sestdiena".split("_"),weekdaysShort:"Sv_P_O_T_C_Pk_S".split("_"),weekdaysMin:"Sv_P_O_T_C_Pk_S".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY.",LL:"YYYY. [gada] D. MMMM",LLL:"YYYY. [gada] D. MMMM, HH:mm",LLLL:"YYYY. [gada] D. MMMM, dddd, HH:mm"},calendar:{sameDay:"[Šodien pulksten] LT",nextDay:"[Rīt pulksten] LT",nextWeek:"dddd [pulksten] LT",lastDay:"[Vakar pulksten] LT",lastWeek:"[Pagājušā] dddd [pulksten] LT",sameElse:"L"},relativeTime:{future:"pēc %s",past:"pirms %s",s:r,ss:s,m:n,mm:s,h:n,hh:s,d:n,dd:s,M:n,MM:s,y:n,yy:s},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},8076:function(e,a,t){!function(e){"use strict"; +var a={ss:"sekundes_sekundēm_sekunde_sekundes".split("_"),m:"minūtes_minūtēm_minūte_minūtes".split("_"),mm:"minūtes_minūtēm_minūte_minūtes".split("_"),h:"stundas_stundām_stunda_stundas".split("_"),hh:"stundas_stundām_stunda_stundas".split("_"),d:"dienas_dienām_diena_dienas".split("_"),dd:"dienas_dienām_diena_dienas".split("_"),M:"mēneša_mēnešiem_mēnesis_mēneši".split("_"),MM:"mēneša_mēnešiem_mēnesis_mēneši".split("_"),y:"gada_gadiem_gads_gadi".split("_"),yy:"gada_gadiem_gads_gadi".split("_")};function t(e,a,t){return t?a%10==1&&a%100!=11?e[2]:e[3]:a%10==1&&a%100!=11?e[0]:e[1]}function s(e,s,n){return e+" "+t(a[n],e,s)}function n(e,s,n){return t(a[n],e,s)}function r(e,a){return a?"dažas sekundes":"dažām sekundēm"}e.defineLocale("lv",{months:"janvāris_februāris_marts_aprīlis_maijs_jūnijs_jūlijs_augusts_septembris_oktobris_novembris_decembris".split("_"),monthsShort:"jan_feb_mar_apr_mai_jūn_jūl_aug_sep_okt_nov_dec".split("_"),weekdays:"svētdiena_pirmdiena_otrdiena_trešdiena_ceturtdiena_piektdiena_sestdiena".split("_"),weekdaysShort:"Sv_P_O_T_C_Pk_S".split("_"),weekdaysMin:"Sv_P_O_T_C_Pk_S".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY.",LL:"YYYY. [gada] D. MMMM",LLL:"YYYY. [gada] D. MMMM, HH:mm",LLLL:"YYYY. [gada] D. MMMM, dddd, HH:mm"},calendar:{sameDay:"[Šodien pulksten] LT",nextDay:"[Rīt pulksten] LT",nextWeek:"dddd [pulksten] LT",lastDay:"[Vakar pulksten] LT",lastWeek:"[Pagājušā] dddd [pulksten] LT",sameElse:"L"},relativeTime:{future:"pēc %s",past:"pirms %s",s:r,ss:s,m:n,mm:s,h:n,hh:s,d:n,dd:s,M:n,MM:s,y:n,yy:s},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},8076(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={words:{ss:["sekund","sekunda","sekundi"],m:["jedan minut","jednog minuta"],mm:["minut","minuta","minuta"],h:["jedan sat","jednog sata"],hh:["sat","sata","sati"],dd:["dan","dana","dana"],MM:["mjesec","mjeseca","mjeseci"],yy:["godina","godine","godina"]},correctGrammaticalCase:function(e,a){return 1===e?a[0]:e>=2&&e<=4?a[1]:a[2]},translate:function(e,t,s){var n=a.words[s];return 1===s.length?t?n[0]:n[1]:e+" "+a.correctGrammaticalCase(e,n)}};e.defineLocale("me",{months:"januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sjutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[juče u] LT",lastWeek:function(){return["[prošle] [nedjelje] [u] LT","[prošlog] [ponedjeljka] [u] LT","[prošlog] [utorka] [u] LT","[prošle] [srijede] [u] LT","[prošlog] [četvrtka] [u] LT","[prošlog] [petka] [u] LT","[prošle] [subote] [u] LT"][this.day()]},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"nekoliko sekundi",ss:a.translate,m:a.translate,mm:a.translate,h:a.translate,hh:a.translate,d:"dan",dd:a.translate,M:"mjesec",MM:a.translate,y:"godinu",yy:a.translate},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(t(5093))},1848:function(e,a,t){!function(e){"use strict"; +var a={words:{ss:["sekund","sekunda","sekundi"],m:["jedan minut","jednog minuta"],mm:["minut","minuta","minuta"],h:["jedan sat","jednog sata"],hh:["sat","sata","sati"],dd:["dan","dana","dana"],MM:["mjesec","mjeseca","mjeseci"],yy:["godina","godine","godina"]},correctGrammaticalCase:function(e,a){return 1===e?a[0]:e>=2&&e<=4?a[1]:a[2]},translate:function(e,t,s){var n=a.words[s];return 1===s.length?t?n[0]:n[1]:e+" "+a.correctGrammaticalCase(e,n)}};e.defineLocale("me",{months:"januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sjutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[juče u] LT",lastWeek:function(){return["[prošle] [nedjelje] [u] LT","[prošlog] [ponedjeljka] [u] LT","[prošlog] [utorka] [u] LT","[prošle] [srijede] [u] LT","[prošlog] [četvrtka] [u] LT","[prošlog] [petka] [u] LT","[prošle] [subote] [u] LT"][this.day()]},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"nekoliko sekundi",ss:a.translate,m:a.translate,mm:a.translate,h:a.translate,hh:a.translate,d:"dan",dd:a.translate,M:"mjesec",MM:a.translate,y:"godinu",yy:a.translate},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(t(5093))},1848(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("mi",{months:"Kohi-tāte_Hui-tanguru_Poutū-te-rangi_Paenga-whāwhā_Haratua_Pipiri_Hōngoingoi_Here-turi-kōkā_Mahuru_Whiringa-ā-nuku_Whiringa-ā-rangi_Hakihea".split("_"),monthsShort:"Kohi_Hui_Pou_Pae_Hara_Pipi_Hōngoi_Here_Mahu_Whi-nu_Whi-ra_Haki".split("_"),monthsRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsStrictRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsShortRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsShortStrictRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,2}/i,weekdays:"Rātapu_Mane_Tūrei_Wenerei_Tāite_Paraire_Hātarei".split("_"),weekdaysShort:"Ta_Ma_Tū_We_Tāi_Pa_Hā".split("_"),weekdaysMin:"Ta_Ma_Tū_We_Tāi_Pa_Hā".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [i] HH:mm",LLLL:"dddd, D MMMM YYYY [i] HH:mm"},calendar:{sameDay:"[i teie mahana, i] LT",nextDay:"[apopo i] LT",nextWeek:"dddd [i] LT",lastDay:"[inanahi i] LT",lastWeek:"dddd [whakamutunga i] LT",sameElse:"L"},relativeTime:{future:"i roto i %s",past:"%s i mua",s:"te hēkona ruarua",ss:"%d hēkona",m:"he meneti",mm:"%d meneti",h:"te haora",hh:"%d haora",d:"he ra",dd:"%d ra",M:"he marama",MM:"%d marama",y:"he tau",yy:"%d tau"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(t(5093))},306:function(e,a,t){!function(e){"use strict"; +e.defineLocale("mi",{months:"Kohi-tāte_Hui-tanguru_Poutū-te-rangi_Paenga-whāwhā_Haratua_Pipiri_Hōngoingoi_Here-turi-kōkā_Mahuru_Whiringa-ā-nuku_Whiringa-ā-rangi_Hakihea".split("_"),monthsShort:"Kohi_Hui_Pou_Pae_Hara_Pipi_Hōngoi_Here_Mahu_Whi-nu_Whi-ra_Haki".split("_"),monthsRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsStrictRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsShortRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsShortStrictRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,2}/i,weekdays:"Rātapu_Mane_Tūrei_Wenerei_Tāite_Paraire_Hātarei".split("_"),weekdaysShort:"Ta_Ma_Tū_We_Tāi_Pa_Hā".split("_"),weekdaysMin:"Ta_Ma_Tū_We_Tāi_Pa_Hā".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [i] HH:mm",LLLL:"dddd, D MMMM YYYY [i] HH:mm"},calendar:{sameDay:"[i teie mahana, i] LT",nextDay:"[apopo i] LT",nextWeek:"dddd [i] LT",lastDay:"[inanahi i] LT",lastWeek:"dddd [whakamutunga i] LT",sameElse:"L"},relativeTime:{future:"i roto i %s",past:"%s i mua",s:"te hēkona ruarua",ss:"%d hēkona",m:"he meneti",mm:"%d meneti",h:"te haora",hh:"%d haora",d:"he ra",dd:"%d ra",M:"he marama",MM:"%d marama",y:"he tau",yy:"%d tau"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(t(5093))},306(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("mk",{months:"јануари_февруари_март_април_мај_јуни_јули_август_септември_октомври_ноември_декември".split("_"),monthsShort:"јан_фев_мар_апр_мај_јун_јул_авг_сеп_окт_ное_дек".split("_"),weekdays:"недела_понеделник_вторник_среда_четврток_петок_сабота".split("_"),weekdaysShort:"нед_пон_вто_сре_чет_пет_саб".split("_"),weekdaysMin:"нe_пo_вт_ср_че_пе_сa".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[Денес во] LT",nextDay:"[Утре во] LT",nextWeek:"[Во] dddd [во] LT",lastDay:"[Вчера во] LT",lastWeek:function(){switch(this.day()){case 0:case 3:case 6:return"[Изминатата] dddd [во] LT";case 1:case 2:case 4:case 5:return"[Изминатиот] dddd [во] LT"}},sameElse:"L"},relativeTime:{future:"за %s",past:"пред %s",s:"неколку секунди",ss:"%d секунди",m:"една минута",mm:"%d минути",h:"еден час",hh:"%d часа",d:"еден ден",dd:"%d дена",M:"еден месец",MM:"%d месеци",y:"една година",yy:"%d години"},dayOfMonthOrdinalParse:/\d{1,2}-(ев|ен|ти|ви|ри|ми)/,ordinal:function(e){var a=e%10,t=e%100;return 0===e?e+"-ев":0===t?e+"-ен":t>10&&t<20?e+"-ти":1===a?e+"-ви":2===a?e+"-ри":7===a||8===a?e+"-ми":e+"-ти"},week:{dow:1,doy:7}})}(t(5093))},3739:function(e,a,t){!function(e){"use strict"; +e.defineLocale("mk",{months:"јануари_февруари_март_април_мај_јуни_јули_август_септември_октомври_ноември_декември".split("_"),monthsShort:"јан_фев_мар_апр_мај_јун_јул_авг_сеп_окт_ное_дек".split("_"),weekdays:"недела_понеделник_вторник_среда_четврток_петок_сабота".split("_"),weekdaysShort:"нед_пон_вто_сре_чет_пет_саб".split("_"),weekdaysMin:"нe_пo_вт_ср_че_пе_сa".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[Денес во] LT",nextDay:"[Утре во] LT",nextWeek:"[Во] dddd [во] LT",lastDay:"[Вчера во] LT",lastWeek:function(){switch(this.day()){case 0:case 3:case 6:return"[Изминатата] dddd [во] LT";case 1:case 2:case 4:case 5:return"[Изминатиот] dddd [во] LT"}},sameElse:"L"},relativeTime:{future:"за %s",past:"пред %s",s:"неколку секунди",ss:"%d секунди",m:"една минута",mm:"%d минути",h:"еден час",hh:"%d часа",d:"еден ден",dd:"%d дена",M:"еден месец",MM:"%d месеци",y:"една година",yy:"%d години"},dayOfMonthOrdinalParse:/\d{1,2}-(ев|ен|ти|ви|ри|ми)/,ordinal:function(e){var a=e%10,t=e%100;return 0===e?e+"-ев":0===t?e+"-ен":t>10&&t<20?e+"-ти":1===a?e+"-ви":2===a?e+"-ри":7===a||8===a?e+"-ми":e+"-ти"},week:{dow:1,doy:7}})}(t(5093))},3739(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("ml",{months:"ജനുവരി_ഫെബ്രുവരി_മാർച്ച്_ഏപ്രിൽ_മേയ്_ജൂൺ_ജൂലൈ_ഓഗസ്റ്റ്_സെപ്റ്റംബർ_ഒക്ടോബർ_നവംബർ_ഡിസംബർ".split("_"),monthsShort:"ജനു._ഫെബ്രു._മാർ._ഏപ്രി._മേയ്_ജൂൺ_ജൂലൈ._ഓഗ._സെപ്റ്റ._ഒക്ടോ._നവം._ഡിസം.".split("_"),monthsParseExact:!0,weekdays:"ഞായറാഴ്ച_തിങ്കളാഴ്ച_ചൊവ്വാഴ്ച_ബുധനാഴ്ച_വ്യാഴാഴ്ച_വെള്ളിയാഴ്ച_ശനിയാഴ്ച".split("_"),weekdaysShort:"ഞായർ_തിങ്കൾ_ചൊവ്വ_ബുധൻ_വ്യാഴം_വെള്ളി_ശനി".split("_"),weekdaysMin:"ഞാ_തി_ചൊ_ബു_വ്യാ_വെ_ശ".split("_"),longDateFormat:{LT:"A h:mm -നു",LTS:"A h:mm:ss -നു",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm -നു",LLLL:"dddd, D MMMM YYYY, A h:mm -നു"},calendar:{sameDay:"[ഇന്ന്] LT",nextDay:"[നാളെ] LT",nextWeek:"dddd, LT",lastDay:"[ഇന്നലെ] LT",lastWeek:"[കഴിഞ്ഞ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s കഴിഞ്ഞ്",past:"%s മുൻപ്",s:"അൽപ നിമിഷങ്ങൾ",ss:"%d സെക്കൻഡ്",m:"ഒരു മിനിറ്റ്",mm:"%d മിനിറ്റ്",h:"ഒരു മണിക്കൂർ",hh:"%d മണിക്കൂർ",d:"ഒരു ദിവസം",dd:"%d ദിവസം",M:"ഒരു മാസം",MM:"%d മാസം",y:"ഒരു വർഷം",yy:"%d വർഷം"},meridiemParse:/രാത്രി|രാവിലെ|ഉച്ച കഴിഞ്ഞ്|വൈകുന്നേരം|രാത്രി/i,meridiemHour:function(e,a){return 12===e&&(e=0),"രാത്രി"===a&&e>=4||"ഉച്ച കഴിഞ്ഞ്"===a||"വൈകുന്നേരം"===a?e+12:e},meridiem:function(e,a,t){return e<4?"രാത്രി":e<12?"രാവിലെ":e<17?"ഉച്ച കഴിഞ്ഞ്":e<20?"വൈകുന്നേരം":"രാത്രി"}})}(t(5093))},9053:function(e,a,t){!function(e){"use strict"; +e.defineLocale("ml",{months:"ജനുവരി_ഫെബ്രുവരി_മാർച്ച്_ഏപ്രിൽ_മേയ്_ജൂൺ_ജൂലൈ_ഓഗസ്റ്റ്_സെപ്റ്റംബർ_ഒക്ടോബർ_നവംബർ_ഡിസംബർ".split("_"),monthsShort:"ജനു._ഫെബ്രു._മാർ._ഏപ്രി._മേയ്_ജൂൺ_ജൂലൈ._ഓഗ._സെപ്റ്റ._ഒക്ടോ._നവം._ഡിസം.".split("_"),monthsParseExact:!0,weekdays:"ഞായറാഴ്ച_തിങ്കളാഴ്ച_ചൊവ്വാഴ്ച_ബുധനാഴ്ച_വ്യാഴാഴ്ച_വെള്ളിയാഴ്ച_ശനിയാഴ്ച".split("_"),weekdaysShort:"ഞായർ_തിങ്കൾ_ചൊവ്വ_ബുധൻ_വ്യാഴം_വെള്ളി_ശനി".split("_"),weekdaysMin:"ഞാ_തി_ചൊ_ബു_വ്യാ_വെ_ശ".split("_"),longDateFormat:{LT:"A h:mm -നു",LTS:"A h:mm:ss -നു",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm -നു",LLLL:"dddd, D MMMM YYYY, A h:mm -നു"},calendar:{sameDay:"[ഇന്ന്] LT",nextDay:"[നാളെ] LT",nextWeek:"dddd, LT",lastDay:"[ഇന്നലെ] LT",lastWeek:"[കഴിഞ്ഞ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s കഴിഞ്ഞ്",past:"%s മുൻപ്",s:"അൽപ നിമിഷങ്ങൾ",ss:"%d സെക്കൻഡ്",m:"ഒരു മിനിറ്റ്",mm:"%d മിനിറ്റ്",h:"ഒരു മണിക്കൂർ",hh:"%d മണിക്കൂർ",d:"ഒരു ദിവസം",dd:"%d ദിവസം",M:"ഒരു മാസം",MM:"%d മാസം",y:"ഒരു വർഷം",yy:"%d വർഷം"},meridiemParse:/രാത്രി|രാവിലെ|ഉച്ച കഴിഞ്ഞ്|വൈകുന്നേരം|രാത്രി/i,meridiemHour:function(e,a){return 12===e&&(e=0),"രാത്രി"===a&&e>=4||"ഉച്ച കഴിഞ്ഞ്"===a||"വൈകുന്നേരം"===a?e+12:e},meridiem:function(e,a,t){return e<4?"രാത്രി":e<12?"രാവിലെ":e<17?"ഉച്ച കഴിഞ്ഞ്":e<20?"വൈകുന്നേരം":"രാത്രി"}})}(t(5093))},9053(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e,a,t,s){switch(t){case"s":return a?"хэдхэн секунд":"хэдхэн секундын";case"ss":return e+(a?" секунд":" секундын");case"m":case"mm":return e+(a?" минут":" минутын");case"h":case"hh":return e+(a?" цаг":" цагийн");case"d":case"dd":return e+(a?" өдөр":" өдрийн");case"M":case"MM":return e+(a?" сар":" сарын");case"y":case"yy":return e+(a?" жил":" жилийн");default:return e}}e.defineLocale("mn",{months:"Нэгдүгээр сар_Хоёрдугаар сар_Гуравдугаар сар_Дөрөвдүгээр сар_Тавдугаар сар_Зургадугаар сар_Долдугаар сар_Наймдугаар сар_Есдүгээр сар_Аравдугаар сар_Арван нэгдүгээр сар_Арван хоёрдугаар сар".split("_"),monthsShort:"1 сар_2 сар_3 сар_4 сар_5 сар_6 сар_7 сар_8 сар_9 сар_10 сар_11 сар_12 сар".split("_"),monthsParseExact:!0,weekdays:"Ням_Даваа_Мягмар_Лхагва_Пүрэв_Баасан_Бямба".split("_"),weekdaysShort:"Ням_Дав_Мяг_Лха_Пүр_Баа_Бям".split("_"),weekdaysMin:"Ня_Да_Мя_Лх_Пү_Ба_Бя".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY оны MMMMын D",LLL:"YYYY оны MMMMын D HH:mm",LLLL:"dddd, YYYY оны MMMMын D HH:mm"},meridiemParse:/ҮӨ|ҮХ/i,isPM:function(e){return"ҮХ"===e},meridiem:function(e,a,t){return e<12?"ҮӨ":"ҮХ"},calendar:{sameDay:"[Өнөөдөр] LT",nextDay:"[Маргааш] LT",nextWeek:"[Ирэх] dddd LT",lastDay:"[Өчигдөр] LT",lastWeek:"[Өнгөрсөн] dddd LT",sameElse:"L"},relativeTime:{future:"%s дараа",past:"%s өмнө",s:a,ss:a,m:a,mm:a,h:a,hh:a,d:a,dd:a,M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2} өдөр/,ordinal:function(e,a){switch(a){case"d":case"D":case"DDD":return e+" өдөр";default:return e}}})}(t(5093))},6169:function(e,a,t){!function(e){"use strict"; +function a(e,a,t,s){switch(t){case"s":return a?"хэдхэн секунд":"хэдхэн секундын";case"ss":return e+(a?" секунд":" секундын");case"m":case"mm":return e+(a?" минут":" минутын");case"h":case"hh":return e+(a?" цаг":" цагийн");case"d":case"dd":return e+(a?" өдөр":" өдрийн");case"M":case"MM":return e+(a?" сар":" сарын");case"y":case"yy":return e+(a?" жил":" жилийн");default:return e}}e.defineLocale("mn",{months:"Нэгдүгээр сар_Хоёрдугаар сар_Гуравдугаар сар_Дөрөвдүгээр сар_Тавдугаар сар_Зургадугаар сар_Долдугаар сар_Наймдугаар сар_Есдүгээр сар_Аравдугаар сар_Арван нэгдүгээр сар_Арван хоёрдугаар сар".split("_"),monthsShort:"1 сар_2 сар_3 сар_4 сар_5 сар_6 сар_7 сар_8 сар_9 сар_10 сар_11 сар_12 сар".split("_"),monthsParseExact:!0,weekdays:"Ням_Даваа_Мягмар_Лхагва_Пүрэв_Баасан_Бямба".split("_"),weekdaysShort:"Ням_Дав_Мяг_Лха_Пүр_Баа_Бям".split("_"),weekdaysMin:"Ня_Да_Мя_Лх_Пү_Ба_Бя".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY оны MMMMын D",LLL:"YYYY оны MMMMын D HH:mm",LLLL:"dddd, YYYY оны MMMMын D HH:mm"},meridiemParse:/ҮӨ|ҮХ/i,isPM:function(e){return"ҮХ"===e},meridiem:function(e,a,t){return e<12?"ҮӨ":"ҮХ"},calendar:{sameDay:"[Өнөөдөр] LT",nextDay:"[Маргааш] LT",nextWeek:"[Ирэх] dddd LT",lastDay:"[Өчигдөр] LT",lastWeek:"[Өнгөрсөн] dddd LT",sameElse:"L"},relativeTime:{future:"%s дараа",past:"%s өмнө",s:a,ss:a,m:a,mm:a,h:a,hh:a,d:a,dd:a,M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2} өдөр/,ordinal:function(e,a){switch(a){case"d":case"D":case"DDD":return e+" өдөр";default:return e}}})}(t(5093))},6169(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"१",2:"२",3:"३",4:"४",5:"५",6:"६",7:"७",8:"८",9:"९",0:"०"},t={"१":"1","२":"2","३":"3","४":"4","५":"5","६":"6","७":"7","८":"8","९":"9","०":"0"};function s(e,a,t,s){var n="";if(a)switch(t){case"s":n="काही सेकंद";break;case"ss":n="%d सेकंद";break;case"m":n="एक मिनिट";break;case"mm":n="%d मिनिटे";break;case"h":n="एक तास";break;case"hh":n="%d तास";break;case"d":n="एक दिवस";break;case"dd":n="%d दिवस";break;case"M":n="एक महिना";break;case"MM":n="%d महिने";break;case"y":n="एक वर्ष";break;case"yy":n="%d वर्षे"}else switch(t){case"s":n="काही सेकंदां";break;case"ss":n="%d सेकंदां";break;case"m":n="एका मिनिटा";break;case"mm":n="%d मिनिटां";break;case"h":n="एका तासा";break;case"hh":n="%d तासां";break;case"d":n="एका दिवसा";break;case"dd":n="%d दिवसां";break;case"M":n="एका महिन्या";break;case"MM":n="%d महिन्यां";break;case"y":n="एका वर्षा";break;case"yy":n="%d वर्षां"}return n.replace(/%d/i,e)}e.defineLocale("mr",{months:"जानेवारी_फेब्रुवारी_मार्च_एप्रिल_मे_जून_जुलै_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर".split("_"),monthsShort:"जाने._फेब्रु._मार्च._एप्रि._मे._जून._जुलै._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.".split("_"),monthsParseExact:!0,weekdays:"रविवार_सोमवार_मंगळवार_बुधवार_गुरूवार_शुक्रवार_शनिवार".split("_"),weekdaysShort:"रवि_सोम_मंगळ_बुध_गुरू_शुक्र_शनि".split("_"),weekdaysMin:"र_सो_मं_बु_गु_शु_श".split("_"),longDateFormat:{LT:"A h:mm वाजता",LTS:"A h:mm:ss वाजता",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm वाजता",LLLL:"dddd, D MMMM YYYY, A h:mm वाजता"},calendar:{sameDay:"[आज] LT",nextDay:"[उद्या] LT",nextWeek:"dddd, LT",lastDay:"[काल] LT",lastWeek:"[मागील] dddd, LT",sameElse:"L"},relativeTime:{future:"%sमध्ये",past:"%sपूर्वी",s,ss:s,m:s,mm:s,h:s,hh:s,d:s,dd:s,M:s,MM:s,y:s,yy:s},preparse:function(e){return e.replace(/[१२३४५६७८९०]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/पहाटे|सकाळी|दुपारी|सायंकाळी|रात्री/,meridiemHour:function(e,a){return 12===e&&(e=0),"पहाटे"===a||"सकाळी"===a?e:"दुपारी"===a||"सायंकाळी"===a||"रात्री"===a?e>=12?e:e+12:void 0},meridiem:function(e,a,t){return e>=0&&e<6?"पहाटे":e<12?"सकाळी":e<17?"दुपारी":e<20?"सायंकाळी":"रात्री"},week:{dow:0,doy:6}})}(t(5093))},2297:function(e,a,t){!function(e){"use strict"; +var a={1:"१",2:"२",3:"३",4:"४",5:"५",6:"६",7:"७",8:"८",9:"९",0:"०"},t={"१":"1","२":"2","३":"3","४":"4","५":"5","६":"6","७":"7","८":"8","९":"9","०":"0"};function s(e,a,t,s){var n="";if(a)switch(t){case"s":n="काही सेकंद";break;case"ss":n="%d सेकंद";break;case"m":n="एक मिनिट";break;case"mm":n="%d मिनिटे";break;case"h":n="एक तास";break;case"hh":n="%d तास";break;case"d":n="एक दिवस";break;case"dd":n="%d दिवस";break;case"M":n="एक महिना";break;case"MM":n="%d महिने";break;case"y":n="एक वर्ष";break;case"yy":n="%d वर्षे"}else switch(t){case"s":n="काही सेकंदां";break;case"ss":n="%d सेकंदां";break;case"m":n="एका मिनिटा";break;case"mm":n="%d मिनिटां";break;case"h":n="एका तासा";break;case"hh":n="%d तासां";break;case"d":n="एका दिवसा";break;case"dd":n="%d दिवसां";break;case"M":n="एका महिन्या";break;case"MM":n="%d महिन्यां";break;case"y":n="एका वर्षा";break;case"yy":n="%d वर्षां"}return n.replace(/%d/i,e)}e.defineLocale("mr",{months:"जानेवारी_फेब्रुवारी_मार्च_एप्रिल_मे_जून_जुलै_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर".split("_"),monthsShort:"जाने._फेब्रु._मार्च._एप्रि._मे._जून._जुलै._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.".split("_"),monthsParseExact:!0,weekdays:"रविवार_सोमवार_मंगळवार_बुधवार_गुरूवार_शुक्रवार_शनिवार".split("_"),weekdaysShort:"रवि_सोम_मंगळ_बुध_गुरू_शुक्र_शनि".split("_"),weekdaysMin:"र_सो_मं_बु_गु_शु_श".split("_"),longDateFormat:{LT:"A h:mm वाजता",LTS:"A h:mm:ss वाजता",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm वाजता",LLLL:"dddd, D MMMM YYYY, A h:mm वाजता"},calendar:{sameDay:"[आज] LT",nextDay:"[उद्या] LT",nextWeek:"dddd, LT",lastDay:"[काल] LT",lastWeek:"[मागील] dddd, LT",sameElse:"L"},relativeTime:{future:"%sमध्ये",past:"%sपूर्वी",s,ss:s,m:s,mm:s,h:s,hh:s,d:s,dd:s,M:s,MM:s,y:s,yy:s},preparse:function(e){return e.replace(/[१२३४५६७८९०]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/पहाटे|सकाळी|दुपारी|सायंकाळी|रात्री/,meridiemHour:function(e,a){return 12===e&&(e=0),"पहाटे"===a||"सकाळी"===a?e:"दुपारी"===a||"सायंकाळी"===a||"रात्री"===a?e>=12?e:e+12:void 0},meridiem:function(e,a,t){return e>=0&&e<6?"पहाटे":e<12?"सकाळी":e<17?"दुपारी":e<20?"सायंकाळी":"रात्री"},week:{dow:0,doy:6}})}(t(5093))},2297(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("ms-my",{months:"Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis".split("_"),weekdays:"Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu".split("_"),weekdaysShort:"Ahd_Isn_Sel_Rab_Kha_Jum_Sab".split("_"),weekdaysMin:"Ah_Is_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|tengahari|petang|malam/,meridiemHour:function(e,a){return 12===e&&(e=0),"pagi"===a?e:"tengahari"===a?e>=11?e:e+12:"petang"===a||"malam"===a?e+12:void 0},meridiem:function(e,a,t){return e<11?"pagi":e<15?"tengahari":e<19?"petang":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Esok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kelmarin pukul] LT",lastWeek:"dddd [lepas pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lepas",s:"beberapa saat",ss:"%d saat",m:"seminit",mm:"%d minit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,doy:7}})}(t(5093))},3386:function(e,a,t){!function(e){"use strict"; +e.defineLocale("ms-my",{months:"Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis".split("_"),weekdays:"Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu".split("_"),weekdaysShort:"Ahd_Isn_Sel_Rab_Kha_Jum_Sab".split("_"),weekdaysMin:"Ah_Is_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|tengahari|petang|malam/,meridiemHour:function(e,a){return 12===e&&(e=0),"pagi"===a?e:"tengahari"===a?e>=11?e:e+12:"petang"===a||"malam"===a?e+12:void 0},meridiem:function(e,a,t){return e<11?"pagi":e<15?"tengahari":e<19?"petang":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Esok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kelmarin pukul] LT",lastWeek:"dddd [lepas pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lepas",s:"beberapa saat",ss:"%d saat",m:"seminit",mm:"%d minit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,doy:7}})}(t(5093))},3386(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("ms",{months:"Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis".split("_"),weekdays:"Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu".split("_"),weekdaysShort:"Ahd_Isn_Sel_Rab_Kha_Jum_Sab".split("_"),weekdaysMin:"Ah_Is_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|tengahari|petang|malam/,meridiemHour:function(e,a){return 12===e&&(e=0),"pagi"===a?e:"tengahari"===a?e>=11?e:e+12:"petang"===a||"malam"===a?e+12:void 0},meridiem:function(e,a,t){return e<11?"pagi":e<15?"tengahari":e<19?"petang":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Esok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kelmarin pukul] LT",lastWeek:"dddd [lepas pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lepas",s:"beberapa saat",ss:"%d saat",m:"seminit",mm:"%d minit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,doy:7}})}(t(5093))},7075:function(e,a,t){!function(e){"use strict"; +e.defineLocale("ms",{months:"Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis".split("_"),weekdays:"Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu".split("_"),weekdaysShort:"Ahd_Isn_Sel_Rab_Kha_Jum_Sab".split("_"),weekdaysMin:"Ah_Is_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|tengahari|petang|malam/,meridiemHour:function(e,a){return 12===e&&(e=0),"pagi"===a?e:"tengahari"===a?e>=11?e:e+12:"petang"===a||"malam"===a?e+12:void 0},meridiem:function(e,a,t){return e<11?"pagi":e<15?"tengahari":e<19?"petang":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Esok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kelmarin pukul] LT",lastWeek:"dddd [lepas pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lepas",s:"beberapa saat",ss:"%d saat",m:"seminit",mm:"%d minit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,doy:7}})}(t(5093))},7075(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("mt",{months:"Jannar_Frar_Marzu_April_Mejju_Ġunju_Lulju_Awwissu_Settembru_Ottubru_Novembru_Diċembru".split("_"),monthsShort:"Jan_Fra_Mar_Apr_Mej_Ġun_Lul_Aww_Set_Ott_Nov_Diċ".split("_"),weekdays:"Il-Ħadd_It-Tnejn_It-Tlieta_L-Erbgħa_Il-Ħamis_Il-Ġimgħa_Is-Sibt".split("_"),weekdaysShort:"Ħad_Tne_Tli_Erb_Ħam_Ġim_Sib".split("_"),weekdaysMin:"Ħa_Tn_Tl_Er_Ħa_Ġi_Si".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Illum fil-]LT",nextDay:"[Għada fil-]LT",nextWeek:"dddd [fil-]LT",lastDay:"[Il-bieraħ fil-]LT",lastWeek:"dddd [li għadda] [fil-]LT",sameElse:"L"},relativeTime:{future:"f’ %s",past:"%s ilu",s:"ftit sekondi",ss:"%d sekondi",m:"minuta",mm:"%d minuti",h:"siegħa",hh:"%d siegħat",d:"ġurnata",dd:"%d ġranet",M:"xahar",MM:"%d xhur",y:"sena",yy:"%d sni"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(t(5093))},2264:function(e,a,t){!function(e){"use strict"; +e.defineLocale("mt",{months:"Jannar_Frar_Marzu_April_Mejju_Ġunju_Lulju_Awwissu_Settembru_Ottubru_Novembru_Diċembru".split("_"),monthsShort:"Jan_Fra_Mar_Apr_Mej_Ġun_Lul_Aww_Set_Ott_Nov_Diċ".split("_"),weekdays:"Il-Ħadd_It-Tnejn_It-Tlieta_L-Erbgħa_Il-Ħamis_Il-Ġimgħa_Is-Sibt".split("_"),weekdaysShort:"Ħad_Tne_Tli_Erb_Ħam_Ġim_Sib".split("_"),weekdaysMin:"Ħa_Tn_Tl_Er_Ħa_Ġi_Si".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Illum fil-]LT",nextDay:"[Għada fil-]LT",nextWeek:"dddd [fil-]LT",lastDay:"[Il-bieraħ fil-]LT",lastWeek:"dddd [li għadda] [fil-]LT",sameElse:"L"},relativeTime:{future:"f’ %s",past:"%s ilu",s:"ftit sekondi",ss:"%d sekondi",m:"minuta",mm:"%d minuti",h:"siegħa",hh:"%d siegħat",d:"ġurnata",dd:"%d ġranet",M:"xahar",MM:"%d xhur",y:"sena",yy:"%d sni"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(t(5093))},2264(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"၁",2:"၂",3:"၃",4:"၄",5:"၅",6:"၆",7:"၇",8:"၈",9:"၉",0:"၀"},t={"၁":"1","၂":"2","၃":"3","၄":"4","၅":"5","၆":"6","၇":"7","၈":"8","၉":"9","၀":"0"};e.defineLocale("my",{months:"ဇန်နဝါရီ_ဖေဖော်ဝါရီ_မတ်_ဧပြီ_မေ_ဇွန်_ဇူလိုင်_သြဂုတ်_စက်တင်ဘာ_အောက်တိုဘာ_နိုဝင်ဘာ_ဒီဇင်ဘာ".split("_"),monthsShort:"ဇန်_ဖေ_မတ်_ပြီ_မေ_ဇွန်_လိုင်_သြ_စက်_အောက်_နို_ဒီ".split("_"),weekdays:"တနင်္ဂနွေ_တနင်္လာ_အင်္ဂါ_ဗုဒ္ဓဟူး_ကြာသပတေး_သောကြာ_စနေ".split("_"),weekdaysShort:"နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ".split("_"),weekdaysMin:"နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[ယနေ.] LT [မှာ]",nextDay:"[မနက်ဖြန်] LT [မှာ]",nextWeek:"dddd LT [မှာ]",lastDay:"[မနေ.က] LT [မှာ]",lastWeek:"[ပြီးခဲ့သော] dddd LT [မှာ]",sameElse:"L"},relativeTime:{future:"လာမည့် %s မှာ",past:"လွန်ခဲ့သော %s က",s:"စက္ကန်.အနည်းငယ်",ss:"%d စက္ကန့်",m:"တစ်မိနစ်",mm:"%d မိနစ်",h:"တစ်နာရီ",hh:"%d နာရီ",d:"တစ်ရက်",dd:"%d ရက်",M:"တစ်လ",MM:"%d လ",y:"တစ်နှစ်",yy:"%d နှစ်"},preparse:function(e){return e.replace(/[၁၂၃၄၅၆၇၈၉၀]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},week:{dow:1,doy:4}})}(t(5093))},2274:function(e,a,t){!function(e){"use strict"; +var a={1:"၁",2:"၂",3:"၃",4:"၄",5:"၅",6:"၆",7:"၇",8:"၈",9:"၉",0:"၀"},t={"၁":"1","၂":"2","၃":"3","၄":"4","၅":"5","၆":"6","၇":"7","၈":"8","၉":"9","၀":"0"};e.defineLocale("my",{months:"ဇန်နဝါရီ_ဖေဖော်ဝါရီ_မတ်_ဧပြီ_မေ_ဇွန်_ဇူလိုင်_သြဂုတ်_စက်တင်ဘာ_အောက်တိုဘာ_နိုဝင်ဘာ_ဒီဇင်ဘာ".split("_"),monthsShort:"ဇန်_ဖေ_မတ်_ပြီ_မေ_ဇွန်_လိုင်_သြ_စက်_အောက်_နို_ဒီ".split("_"),weekdays:"တနင်္ဂနွေ_တနင်္လာ_အင်္ဂါ_ဗုဒ္ဓဟူး_ကြာသပတေး_သောကြာ_စနေ".split("_"),weekdaysShort:"နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ".split("_"),weekdaysMin:"နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[ယနေ.] LT [မှာ]",nextDay:"[မနက်ဖြန်] LT [မှာ]",nextWeek:"dddd LT [မှာ]",lastDay:"[မနေ.က] LT [မှာ]",lastWeek:"[ပြီးခဲ့သော] dddd LT [မှာ]",sameElse:"L"},relativeTime:{future:"လာမည့် %s မှာ",past:"လွန်ခဲ့သော %s က",s:"စက္ကန်.အနည်းငယ်",ss:"%d စက္ကန့်",m:"တစ်မိနစ်",mm:"%d မိနစ်",h:"တစ်နာရီ",hh:"%d နာရီ",d:"တစ်ရက်",dd:"%d ရက်",M:"တစ်လ",MM:"%d လ",y:"တစ်နှစ်",yy:"%d နှစ်"},preparse:function(e){return e.replace(/[၁၂၃၄၅၆၇၈၉၀]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},week:{dow:1,doy:4}})}(t(5093))},2274(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("nb",{months:"januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan._feb._mars_apr._mai_juni_juli_aug._sep._okt._nov._des.".split("_"),monthsParseExact:!0,weekdays:"søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag".split("_"),weekdaysShort:"sø._ma._ti._on._to._fr._lø.".split("_"),weekdaysMin:"sø_ma_ti_on_to_fr_lø".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] HH:mm",LLLL:"dddd D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[i dag kl.] LT",nextDay:"[i morgen kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[i går kl.] LT",lastWeek:"[forrige] dddd [kl.] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s siden",s:"noen sekunder",ss:"%d sekunder",m:"ett minutt",mm:"%d minutter",h:"én time",hh:"%d timer",d:"én dag",dd:"%d dager",w:"én uke",ww:"%d uker",M:"én måned",MM:"%d måneder",y:"ett år",yy:"%d år"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},8235:function(e,a,t){!function(e){"use strict"; +e.defineLocale("nb",{months:"januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan._feb._mars_apr._mai_juni_juli_aug._sep._okt._nov._des.".split("_"),monthsParseExact:!0,weekdays:"søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag".split("_"),weekdaysShort:"sø._ma._ti._on._to._fr._lø.".split("_"),weekdaysMin:"sø_ma_ti_on_to_fr_lø".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] HH:mm",LLLL:"dddd D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[i dag kl.] LT",nextDay:"[i morgen kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[i går kl.] LT",lastWeek:"[forrige] dddd [kl.] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s siden",s:"noen sekunder",ss:"%d sekunder",m:"ett minutt",mm:"%d minutter",h:"én time",hh:"%d timer",d:"én dag",dd:"%d dager",w:"én uke",ww:"%d uker",M:"én måned",MM:"%d måneder",y:"ett år",yy:"%d år"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},8235(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"१",2:"२",3:"३",4:"४",5:"५",6:"६",7:"७",8:"८",9:"९",0:"०"},t={"१":"1","२":"2","३":"3","४":"4","५":"5","६":"6","७":"7","८":"8","९":"9","०":"0"};e.defineLocale("ne",{months:"जनवरी_फेब्रुवरी_मार्च_अप्रिल_मई_जुन_जुलाई_अगष्ट_सेप्टेम्बर_अक्टोबर_नोभेम्बर_डिसेम्बर".split("_"),monthsShort:"जन._फेब्रु._मार्च_अप्रि._मई_जुन_जुलाई._अग._सेप्ट._अक्टो._नोभे._डिसे.".split("_"),monthsParseExact:!0,weekdays:"आइतबार_सोमबार_मङ्गलबार_बुधबार_बिहिबार_शुक्रबार_शनिबार".split("_"),weekdaysShort:"आइत._सोम._मङ्गल._बुध._बिहि._शुक्र._शनि.".split("_"),weekdaysMin:"आ._सो._मं._बु._बि._शु._श.".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"Aको h:mm बजे",LTS:"Aको h:mm:ss बजे",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, Aको h:mm बजे",LLLL:"dddd, D MMMM YYYY, Aको h:mm बजे"},preparse:function(e){return e.replace(/[१२३४५६७८९०]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/राति|बिहान|दिउँसो|साँझ/,meridiemHour:function(e,a){return 12===e&&(e=0),"राति"===a?e<4?e:e+12:"बिहान"===a?e:"दिउँसो"===a?e>=10?e:e+12:"साँझ"===a?e+12:void 0},meridiem:function(e,a,t){return e<3?"राति":e<12?"बिहान":e<16?"दिउँसो":e<20?"साँझ":"राति"},calendar:{sameDay:"[आज] LT",nextDay:"[भोलि] LT",nextWeek:"[आउँदो] dddd[,] LT",lastDay:"[हिजो] LT",lastWeek:"[गएको] dddd[,] LT",sameElse:"L"},relativeTime:{future:"%sमा",past:"%s अगाडि",s:"केही क्षण",ss:"%d सेकेण्ड",m:"एक मिनेट",mm:"%d मिनेट",h:"एक घण्टा",hh:"%d घण्टा",d:"एक दिन",dd:"%d दिन",M:"एक महिना",MM:"%d महिना",y:"एक बर्ष",yy:"%d बर्ष"},week:{dow:0,doy:6}})}(t(5093))},3784:function(e,a,t){!function(e){"use strict"; +var a={1:"१",2:"२",3:"३",4:"४",5:"५",6:"६",7:"७",8:"८",9:"९",0:"०"},t={"१":"1","२":"2","३":"3","४":"4","५":"5","६":"6","७":"7","८":"8","९":"9","०":"0"};e.defineLocale("ne",{months:"जनवरी_फेब्रुवरी_मार्च_अप्रिल_मई_जुन_जुलाई_अगष्ट_सेप्टेम्बर_अक्टोबर_नोभेम्बर_डिसेम्बर".split("_"),monthsShort:"जन._फेब्रु._मार्च_अप्रि._मई_जुन_जुलाई._अग._सेप्ट._अक्टो._नोभे._डिसे.".split("_"),monthsParseExact:!0,weekdays:"आइतबार_सोमबार_मङ्गलबार_बुधबार_बिहिबार_शुक्रबार_शनिबार".split("_"),weekdaysShort:"आइत._सोम._मङ्गल._बुध._बिहि._शुक्र._शनि.".split("_"),weekdaysMin:"आ._सो._मं._बु._बि._शु._श.".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"Aको h:mm बजे",LTS:"Aको h:mm:ss बजे",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, Aको h:mm बजे",LLLL:"dddd, D MMMM YYYY, Aको h:mm बजे"},preparse:function(e){return e.replace(/[१२३४५६७८९०]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/राति|बिहान|दिउँसो|साँझ/,meridiemHour:function(e,a){return 12===e&&(e=0),"राति"===a?e<4?e:e+12:"बिहान"===a?e:"दिउँसो"===a?e>=10?e:e+12:"साँझ"===a?e+12:void 0},meridiem:function(e,a,t){return e<3?"राति":e<12?"बिहान":e<16?"दिउँसो":e<20?"साँझ":"राति"},calendar:{sameDay:"[आज] LT",nextDay:"[भोलि] LT",nextWeek:"[आउँदो] dddd[,] LT",lastDay:"[हिजो] LT",lastWeek:"[गएको] dddd[,] LT",sameElse:"L"},relativeTime:{future:"%sमा",past:"%s अगाडि",s:"केही क्षण",ss:"%d सेकेण्ड",m:"एक मिनेट",mm:"%d मिनेट",h:"एक घण्टा",hh:"%d घण्टा",d:"एक दिन",dd:"%d दिन",M:"एक महिना",MM:"%d महिना",y:"एक बर्ष",yy:"%d बर्ष"},week:{dow:0,doy:6}})}(t(5093))},3784(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a="jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.".split("_"),t="jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec".split("_"),s=[/^jan/i,/^feb/i,/^(maart|mrt\.?)$/i,/^apr/i,/^mei$/i,/^jun[i.]?$/i,/^jul[i.]?$/i,/^aug/i,/^sep/i,/^okt/i,/^nov/i,/^dec/i],n=/^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;e.defineLocale("nl-be",{months:"januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?t[e.month()]:a[e.month()]:a},monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december)/i,monthsShortStrictRegex:/^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag".split("_"),weekdaysShort:"zo._ma._di._wo._do._vr._za.".split("_"),weekdaysMin:"zo_ma_di_wo_do_vr_za".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[vandaag om] LT",nextDay:"[morgen om] LT",nextWeek:"dddd [om] LT",lastDay:"[gisteren om] LT",lastWeek:"[afgelopen] dddd [om] LT",sameElse:"L"},relativeTime:{future:"over %s",past:"%s geleden",s:"een paar seconden",ss:"%d seconden",m:"één minuut",mm:"%d minuten",h:"één uur",hh:"%d uur",d:"één dag",dd:"%d dagen",M:"één maand",MM:"%d maanden",y:"één jaar",yy:"%d jaar"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})}(t(5093))},2572:function(e,a,t){!function(e){"use strict"; +var a="jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.".split("_"),t="jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec".split("_"),s=[/^jan/i,/^feb/i,/^(maart|mrt\.?)$/i,/^apr/i,/^mei$/i,/^jun[i.]?$/i,/^jul[i.]?$/i,/^aug/i,/^sep/i,/^okt/i,/^nov/i,/^dec/i],n=/^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;e.defineLocale("nl-be",{months:"januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?t[e.month()]:a[e.month()]:a},monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december)/i,monthsShortStrictRegex:/^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag".split("_"),weekdaysShort:"zo._ma._di._wo._do._vr._za.".split("_"),weekdaysMin:"zo_ma_di_wo_do_vr_za".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[vandaag om] LT",nextDay:"[morgen om] LT",nextWeek:"dddd [om] LT",lastDay:"[gisteren om] LT",lastWeek:"[afgelopen] dddd [om] LT",sameElse:"L"},relativeTime:{future:"over %s",past:"%s geleden",s:"een paar seconden",ss:"%d seconden",m:"één minuut",mm:"%d minuten",h:"één uur",hh:"%d uur",d:"één dag",dd:"%d dagen",M:"één maand",MM:"%d maanden",y:"één jaar",yy:"%d jaar"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})}(t(5093))},2572(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a="jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.".split("_"),t="jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec".split("_"),s=[/^jan/i,/^feb/i,/^(maart|mrt\.?)$/i,/^apr/i,/^mei$/i,/^jun[i.]?$/i,/^jul[i.]?$/i,/^aug/i,/^sep/i,/^okt/i,/^nov/i,/^dec/i],n=/^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;e.defineLocale("nl",{months:"januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?t[e.month()]:a[e.month()]:a},monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december)/i,monthsShortStrictRegex:/^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag".split("_"),weekdaysShort:"zo._ma._di._wo._do._vr._za.".split("_"),weekdaysMin:"zo_ma_di_wo_do_vr_za".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[vandaag om] LT",nextDay:"[morgen om] LT",nextWeek:"dddd [om] LT",lastDay:"[gisteren om] LT",lastWeek:"[afgelopen] dddd [om] LT",sameElse:"L"},relativeTime:{future:"over %s",past:"%s geleden",s:"een paar seconden",ss:"%d seconden",m:"één minuut",mm:"%d minuten",h:"één uur",hh:"%d uur",d:"één dag",dd:"%d dagen",w:"één week",ww:"%d weken",M:"één maand",MM:"%d maanden",y:"één jaar",yy:"%d jaar"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})}(t(5093))},4566:function(e,a,t){!function(e){"use strict"; +var a="jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.".split("_"),t="jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec".split("_"),s=[/^jan/i,/^feb/i,/^(maart|mrt\.?)$/i,/^apr/i,/^mei$/i,/^jun[i.]?$/i,/^jul[i.]?$/i,/^aug/i,/^sep/i,/^okt/i,/^nov/i,/^dec/i],n=/^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;e.defineLocale("nl",{months:"januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?t[e.month()]:a[e.month()]:a},monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december)/i,monthsShortStrictRegex:/^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag".split("_"),weekdaysShort:"zo._ma._di._wo._do._vr._za.".split("_"),weekdaysMin:"zo_ma_di_wo_do_vr_za".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[vandaag om] LT",nextDay:"[morgen om] LT",nextWeek:"dddd [om] LT",lastDay:"[gisteren om] LT",lastWeek:"[afgelopen] dddd [om] LT",sameElse:"L"},relativeTime:{future:"over %s",past:"%s geleden",s:"een paar seconden",ss:"%d seconden",m:"één minuut",mm:"%d minuten",h:"één uur",hh:"%d uur",d:"één dag",dd:"%d dagen",w:"één week",ww:"%d weken",M:"één maand",MM:"%d maanden",y:"één jaar",yy:"%d jaar"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})}(t(5093))},4566(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("nn",{months:"januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan._feb._mars_apr._mai_juni_juli_aug._sep._okt._nov._des.".split("_"),monthsParseExact:!0,weekdays:"sundag_måndag_tysdag_onsdag_torsdag_fredag_laurdag".split("_"),weekdaysShort:"su._må._ty._on._to._fr._lau.".split("_"),weekdaysMin:"su_må_ty_on_to_fr_la".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] H:mm",LLLL:"dddd D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[I dag klokka] LT",nextDay:"[I morgon klokka] LT",nextWeek:"dddd [klokka] LT",lastDay:"[I går klokka] LT",lastWeek:"[Føregåande] dddd [klokka] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s sidan",s:"nokre sekund",ss:"%d sekund",m:"eit minutt",mm:"%d minutt",h:"ein time",hh:"%d timar",d:"ein dag",dd:"%d dagar",w:"ei veke",ww:"%d veker",M:"ein månad",MM:"%d månader",y:"eit år",yy:"%d år"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},9330:function(e,a,t){!function(e){"use strict"; +e.defineLocale("nn",{months:"januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan._feb._mars_apr._mai_juni_juli_aug._sep._okt._nov._des.".split("_"),monthsParseExact:!0,weekdays:"sundag_måndag_tysdag_onsdag_torsdag_fredag_laurdag".split("_"),weekdaysShort:"su._må._ty._on._to._fr._lau.".split("_"),weekdaysMin:"su_må_ty_on_to_fr_la".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] H:mm",LLLL:"dddd D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[I dag klokka] LT",nextDay:"[I morgon klokka] LT",nextWeek:"dddd [klokka] LT",lastDay:"[I går klokka] LT",lastWeek:"[Føregåande] dddd [klokka] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s sidan",s:"nokre sekund",ss:"%d sekund",m:"eit minutt",mm:"%d minutt",h:"ein time",hh:"%d timar",d:"ein dag",dd:"%d dagar",w:"ei veke",ww:"%d veker",M:"ein månad",MM:"%d månader",y:"eit år",yy:"%d år"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},9330(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("oc-lnc",{months:{standalone:"genièr_febrièr_març_abril_mai_junh_julhet_agost_setembre_octòbre_novembre_decembre".split("_"),format:"de genièr_de febrièr_de març_d'abril_de mai_de junh_de julhet_d'agost_de setembre_d'octòbre_de novembre_de decembre".split("_"),isFormat:/D[oD]?(\s)+MMMM/},monthsShort:"gen._febr._març_abr._mai_junh_julh._ago._set._oct._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"dimenge_diluns_dimars_dimècres_dijòus_divendres_dissabte".split("_"),weekdaysShort:"dg._dl._dm._dc._dj._dv._ds.".split("_"),weekdaysMin:"dg_dl_dm_dc_dj_dv_ds".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM [de] YYYY",ll:"D MMM YYYY",LLL:"D MMMM [de] YYYY [a] H:mm",lll:"D MMM YYYY, H:mm",LLLL:"dddd D MMMM [de] YYYY [a] H:mm",llll:"ddd D MMM YYYY, H:mm"},calendar:{sameDay:"[uèi a] LT",nextDay:"[deman a] LT",nextWeek:"dddd [a] LT",lastDay:"[ièr a] LT",lastWeek:"dddd [passat a] LT",sameElse:"L"},relativeTime:{future:"d'aquí %s",past:"fa %s",s:"unas segondas",ss:"%d segondas",m:"una minuta",mm:"%d minutas",h:"una ora",hh:"%d oras",d:"un jorn",dd:"%d jorns",M:"un mes",MM:"%d meses",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(r|n|t|è|a)/,ordinal:function(e,a){var t=1===e?"r":2===e?"n":3===e?"r":4===e?"t":"è";return"w"!==a&&"W"!==a||(t="a"),e+t},week:{dow:1,doy:4}})}(t(5093))},9849:function(e,a,t){!function(e){"use strict"; +e.defineLocale("oc-lnc",{months:{standalone:"genièr_febrièr_març_abril_mai_junh_julhet_agost_setembre_octòbre_novembre_decembre".split("_"),format:"de genièr_de febrièr_de març_d'abril_de mai_de junh_de julhet_d'agost_de setembre_d'octòbre_de novembre_de decembre".split("_"),isFormat:/D[oD]?(\s)+MMMM/},monthsShort:"gen._febr._març_abr._mai_junh_julh._ago._set._oct._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"dimenge_diluns_dimars_dimècres_dijòus_divendres_dissabte".split("_"),weekdaysShort:"dg._dl._dm._dc._dj._dv._ds.".split("_"),weekdaysMin:"dg_dl_dm_dc_dj_dv_ds".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM [de] YYYY",ll:"D MMM YYYY",LLL:"D MMMM [de] YYYY [a] H:mm",lll:"D MMM YYYY, H:mm",LLLL:"dddd D MMMM [de] YYYY [a] H:mm",llll:"ddd D MMM YYYY, H:mm"},calendar:{sameDay:"[uèi a] LT",nextDay:"[deman a] LT",nextWeek:"dddd [a] LT",lastDay:"[ièr a] LT",lastWeek:"dddd [passat a] LT",sameElse:"L"},relativeTime:{future:"d'aquí %s",past:"fa %s",s:"unas segondas",ss:"%d segondas",m:"una minuta",mm:"%d minutas",h:"una ora",hh:"%d oras",d:"un jorn",dd:"%d jorns",M:"un mes",MM:"%d meses",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(r|n|t|è|a)/,ordinal:function(e,a){var t=1===e?"r":2===e?"n":3===e?"r":4===e?"t":"è";return"w"!==a&&"W"!==a||(t="a"),e+t},week:{dow:1,doy:4}})}(t(5093))},9849(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"੧",2:"੨",3:"੩",4:"੪",5:"੫",6:"੬",7:"੭",8:"੮",9:"੯",0:"੦"},t={"੧":"1","੨":"2","੩":"3","੪":"4","੫":"5","੬":"6","੭":"7","੮":"8","੯":"9","੦":"0"};e.defineLocale("pa-in",{months:"ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ".split("_"),monthsShort:"ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ".split("_"),weekdays:"ਐਤਵਾਰ_ਸੋਮਵਾਰ_ਮੰਗਲਵਾਰ_ਬੁਧਵਾਰ_ਵੀਰਵਾਰ_ਸ਼ੁੱਕਰਵਾਰ_ਸ਼ਨੀਚਰਵਾਰ".split("_"),weekdaysShort:"ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ".split("_"),weekdaysMin:"ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ".split("_"),longDateFormat:{LT:"A h:mm ਵਜੇ",LTS:"A h:mm:ss ਵਜੇ",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm ਵਜੇ",LLLL:"dddd, D MMMM YYYY, A h:mm ਵਜੇ"},calendar:{sameDay:"[ਅਜ] LT",nextDay:"[ਕਲ] LT",nextWeek:"[ਅਗਲਾ] dddd, LT",lastDay:"[ਕਲ] LT",lastWeek:"[ਪਿਛਲੇ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s ਵਿੱਚ",past:"%s ਪਿਛਲੇ",s:"ਕੁਝ ਸਕਿੰਟ",ss:"%d ਸਕਿੰਟ",m:"ਇਕ ਮਿੰਟ",mm:"%d ਮਿੰਟ",h:"ਇੱਕ ਘੰਟਾ",hh:"%d ਘੰਟੇ",d:"ਇੱਕ ਦਿਨ",dd:"%d ਦਿਨ",M:"ਇੱਕ ਮਹੀਨਾ",MM:"%d ਮਹੀਨੇ",y:"ਇੱਕ ਸਾਲ",yy:"%d ਸਾਲ"},preparse:function(e){return e.replace(/[੧੨੩੪੫੬੭੮੯੦]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/ਰਾਤ|ਸਵੇਰ|ਦੁਪਹਿਰ|ਸ਼ਾਮ/,meridiemHour:function(e,a){return 12===e&&(e=0),"ਰਾਤ"===a?e<4?e:e+12:"ਸਵੇਰ"===a?e:"ਦੁਪਹਿਰ"===a?e>=10?e:e+12:"ਸ਼ਾਮ"===a?e+12:void 0},meridiem:function(e,a,t){return e<4?"ਰਾਤ":e<10?"ਸਵੇਰ":e<17?"ਦੁਪਹਿਰ":e<20?"ਸ਼ਾਮ":"ਰਾਤ"},week:{dow:0,doy:6}})}(t(5093))},4418:function(e,a,t){!function(e){"use strict"; +var a={1:"੧",2:"੨",3:"੩",4:"੪",5:"੫",6:"੬",7:"੭",8:"੮",9:"੯",0:"੦"},t={"੧":"1","੨":"2","੩":"3","੪":"4","੫":"5","੬":"6","੭":"7","੮":"8","੯":"9","੦":"0"};e.defineLocale("pa-in",{months:"ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ".split("_"),monthsShort:"ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ".split("_"),weekdays:"ਐਤਵਾਰ_ਸੋਮਵਾਰ_ਮੰਗਲਵਾਰ_ਬੁਧਵਾਰ_ਵੀਰਵਾਰ_ਸ਼ੁੱਕਰਵਾਰ_ਸ਼ਨੀਚਰਵਾਰ".split("_"),weekdaysShort:"ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ".split("_"),weekdaysMin:"ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ".split("_"),longDateFormat:{LT:"A h:mm ਵਜੇ",LTS:"A h:mm:ss ਵਜੇ",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm ਵਜੇ",LLLL:"dddd, D MMMM YYYY, A h:mm ਵਜੇ"},calendar:{sameDay:"[ਅਜ] LT",nextDay:"[ਕਲ] LT",nextWeek:"[ਅਗਲਾ] dddd, LT",lastDay:"[ਕਲ] LT",lastWeek:"[ਪਿਛਲੇ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s ਵਿੱਚ",past:"%s ਪਿਛਲੇ",s:"ਕੁਝ ਸਕਿੰਟ",ss:"%d ਸਕਿੰਟ",m:"ਇਕ ਮਿੰਟ",mm:"%d ਮਿੰਟ",h:"ਇੱਕ ਘੰਟਾ",hh:"%d ਘੰਟੇ",d:"ਇੱਕ ਦਿਨ",dd:"%d ਦਿਨ",M:"ਇੱਕ ਮਹੀਨਾ",MM:"%d ਮਹੀਨੇ",y:"ਇੱਕ ਸਾਲ",yy:"%d ਸਾਲ"},preparse:function(e){return e.replace(/[੧੨੩੪੫੬੭੮੯੦]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/ਰਾਤ|ਸਵੇਰ|ਦੁਪਹਿਰ|ਸ਼ਾਮ/,meridiemHour:function(e,a){return 12===e&&(e=0),"ਰਾਤ"===a?e<4?e:e+12:"ਸਵੇਰ"===a?e:"ਦੁਪਹਿਰ"===a?e>=10?e:e+12:"ਸ਼ਾਮ"===a?e+12:void 0},meridiem:function(e,a,t){return e<4?"ਰਾਤ":e<10?"ਸਵੇਰ":e<17?"ਦੁਪਹਿਰ":e<20?"ਸ਼ਾਮ":"ਰਾਤ"},week:{dow:0,doy:6}})}(t(5093))},4418(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a="styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień".split("_"),t="stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia".split("_"),s=[/^sty/i,/^lut/i,/^mar/i,/^kwi/i,/^maj/i,/^cze/i,/^lip/i,/^sie/i,/^wrz/i,/^paź/i,/^lis/i,/^gru/i];function n(e){return e%10<5&&e%10>1&&~~(e/10)%10!=1}function r(e,a,t){var s=e+" ";switch(t){case"ss":return s+(n(e)?"sekundy":"sekund");case"m":return a?"minuta":"minutę";case"mm":return s+(n(e)?"minuty":"minut");case"h":return a?"godzina":"godzinę";case"hh":return s+(n(e)?"godziny":"godzin");case"ww":return s+(n(e)?"tygodnie":"tygodni");case"MM":return s+(n(e)?"miesiące":"miesięcy");case"yy":return s+(n(e)?"lata":"lat")}}e.defineLocale("pl",{months:function(e,s){return e?/D MMMM/.test(s)?t[e.month()]:a[e.month()]:a},monthsShort:"sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru".split("_"),monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota".split("_"),weekdaysShort:"ndz_pon_wt_śr_czw_pt_sob".split("_"),weekdaysMin:"Nd_Pn_Wt_Śr_Cz_Pt_So".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Dziś o] LT",nextDay:"[Jutro o] LT",nextWeek:function(){switch(this.day()){case 0:return"[W niedzielę o] LT";case 2:return"[We wtorek o] LT";case 3:return"[W środę o] LT";case 6:return"[W sobotę o] LT";default:return"[W] dddd [o] LT"}},lastDay:"[Wczoraj o] LT",lastWeek:function(){switch(this.day()){case 0:return"[W zeszłą niedzielę o] LT";case 3:return"[W zeszłą środę o] LT";case 6:return"[W zeszłą sobotę o] LT";default:return"[W zeszły] dddd [o] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"%s temu",s:"kilka sekund",ss:r,m:r,mm:r,h:r,hh:r,d:"1 dzień",dd:"%d dni",w:"tydzień",ww:r,M:"miesiąc",MM:r,y:"rok",yy:r},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},8303:function(e,a,t){!function(e){"use strict"; +var a="styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień".split("_"),t="stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia".split("_"),s=[/^sty/i,/^lut/i,/^mar/i,/^kwi/i,/^maj/i,/^cze/i,/^lip/i,/^sie/i,/^wrz/i,/^paź/i,/^lis/i,/^gru/i];function n(e){return e%10<5&&e%10>1&&~~(e/10)%10!=1}function r(e,a,t){var s=e+" ";switch(t){case"ss":return s+(n(e)?"sekundy":"sekund");case"m":return a?"minuta":"minutę";case"mm":return s+(n(e)?"minuty":"minut");case"h":return a?"godzina":"godzinę";case"hh":return s+(n(e)?"godziny":"godzin");case"ww":return s+(n(e)?"tygodnie":"tygodni");case"MM":return s+(n(e)?"miesiące":"miesięcy");case"yy":return s+(n(e)?"lata":"lat")}}e.defineLocale("pl",{months:function(e,s){return e?/D MMMM/.test(s)?t[e.month()]:a[e.month()]:a},monthsShort:"sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru".split("_"),monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota".split("_"),weekdaysShort:"ndz_pon_wt_śr_czw_pt_sob".split("_"),weekdaysMin:"Nd_Pn_Wt_Śr_Cz_Pt_So".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Dziś o] LT",nextDay:"[Jutro o] LT",nextWeek:function(){switch(this.day()){case 0:return"[W niedzielę o] LT";case 2:return"[We wtorek o] LT";case 3:return"[W środę o] LT";case 6:return"[W sobotę o] LT";default:return"[W] dddd [o] LT"}},lastDay:"[Wczoraj o] LT",lastWeek:function(){switch(this.day()){case 0:return"[W zeszłą niedzielę o] LT";case 3:return"[W zeszłą środę o] LT";case 6:return"[W zeszłą sobotę o] LT";default:return"[W zeszły] dddd [o] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"%s temu",s:"kilka sekund",ss:r,m:r,mm:r,h:r,hh:r,d:"1 dzień",dd:"%d dni",w:"tydzień",ww:r,M:"miesiąc",MM:r,y:"rok",yy:r},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},8303(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("pt-br",{months:"janeiro_fevereiro_março_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro".split("_"),monthsShort:"jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez".split("_"),weekdays:"domingo_segunda-feira_terça-feira_quarta-feira_quinta-feira_sexta-feira_sábado".split("_"),weekdaysShort:"dom_seg_ter_qua_qui_sex_sáb".split("_"),weekdaysMin:"do_2ª_3ª_4ª_5ª_6ª_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY [às] HH:mm",LLLL:"dddd, D [de] MMMM [de] YYYY [às] HH:mm"},calendar:{sameDay:"[Hoje às] LT",nextDay:"[Amanhã às] LT",nextWeek:"dddd [às] LT",lastDay:"[Ontem às] LT",lastWeek:function(){return 0===this.day()||6===this.day()?"[Último] dddd [às] LT":"[Última] dddd [às] LT"},sameElse:"L"},relativeTime:{future:"em %s",past:"há %s",s:"poucos segundos",ss:"%d segundos",m:"um minuto",mm:"%d minutos",h:"uma hora",hh:"%d horas",d:"um dia",dd:"%d dias",M:"um mês",MM:"%d meses",y:"um ano",yy:"%d anos"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",invalidDate:"Data inválida"})}(t(5093))},9834:function(e,a,t){!function(e){"use strict"; +e.defineLocale("pt-br",{months:"janeiro_fevereiro_março_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro".split("_"),monthsShort:"jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez".split("_"),weekdays:"domingo_segunda-feira_terça-feira_quarta-feira_quinta-feira_sexta-feira_sábado".split("_"),weekdaysShort:"dom_seg_ter_qua_qui_sex_sáb".split("_"),weekdaysMin:"do_2ª_3ª_4ª_5ª_6ª_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY [às] HH:mm",LLLL:"dddd, D [de] MMMM [de] YYYY [às] HH:mm"},calendar:{sameDay:"[Hoje às] LT",nextDay:"[Amanhã às] LT",nextWeek:"dddd [às] LT",lastDay:"[Ontem às] LT",lastWeek:function(){return 0===this.day()||6===this.day()?"[Último] dddd [às] LT":"[Última] dddd [às] LT"},sameElse:"L"},relativeTime:{future:"em %s",past:"há %s",s:"poucos segundos",ss:"%d segundos",m:"um minuto",mm:"%d minutos",h:"uma hora",hh:"%d horas",d:"um dia",dd:"%d dias",M:"um mês",MM:"%d meses",y:"um ano",yy:"%d anos"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",invalidDate:"Data inválida"})}(t(5093))},9834(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("pt",{months:"janeiro_fevereiro_março_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro".split("_"),monthsShort:"jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez".split("_"),weekdays:"Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado".split("_"),weekdaysShort:"Dom_Seg_Ter_Qua_Qui_Sex_Sáb".split("_"),weekdaysMin:"Do_2ª_3ª_4ª_5ª_6ª_Sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY HH:mm",LLLL:"dddd, D [de] MMMM [de] YYYY HH:mm"},calendar:{sameDay:"[Hoje às] LT",nextDay:"[Amanhã às] LT",nextWeek:"dddd [às] LT",lastDay:"[Ontem às] LT",lastWeek:function(){return 0===this.day()||6===this.day()?"[Último] dddd [às] LT":"[Última] dddd [às] LT"},sameElse:"L"},relativeTime:{future:"em %s",past:"há %s",s:"segundos",ss:"%d segundos",m:"um minuto",mm:"%d minutos",h:"uma hora",hh:"%d horas",d:"um dia",dd:"%d dias",w:"uma semana",ww:"%d semanas",M:"um mês",MM:"%d meses",y:"um ano",yy:"%d anos"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(t(5093))},4457:function(e,a,t){!function(e){"use strict"; +e.defineLocale("pt",{months:"janeiro_fevereiro_março_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro".split("_"),monthsShort:"jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez".split("_"),weekdays:"Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado".split("_"),weekdaysShort:"Dom_Seg_Ter_Qua_Qui_Sex_Sáb".split("_"),weekdaysMin:"Do_2ª_3ª_4ª_5ª_6ª_Sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY HH:mm",LLLL:"dddd, D [de] MMMM [de] YYYY HH:mm"},calendar:{sameDay:"[Hoje às] LT",nextDay:"[Amanhã às] LT",nextWeek:"dddd [às] LT",lastDay:"[Ontem às] LT",lastWeek:function(){return 0===this.day()||6===this.day()?"[Último] dddd [às] LT":"[Última] dddd [às] LT"},sameElse:"L"},relativeTime:{future:"em %s",past:"há %s",s:"segundos",ss:"%d segundos",m:"um minuto",mm:"%d minutos",h:"uma hora",hh:"%d horas",d:"um dia",dd:"%d dias",w:"uma semana",ww:"%d semanas",M:"um mês",MM:"%d meses",y:"um ano",yy:"%d anos"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(t(5093))},4457(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e,a,t){var s=" ";return(e%100>=20||e>=100&&e%100==0)&&(s=" de "),e+s+{ss:"secunde",mm:"minute",hh:"ore",dd:"zile",ww:"săptămâni",MM:"luni",yy:"ani"}[t]}e.defineLocale("ro",{months:"ianuarie_februarie_martie_aprilie_mai_iunie_iulie_august_septembrie_octombrie_noiembrie_decembrie".split("_"),monthsShort:"ian._feb._mart._apr._mai_iun._iul._aug._sept._oct._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"duminică_luni_marți_miercuri_joi_vineri_sâmbătă".split("_"),weekdaysShort:"Dum_Lun_Mar_Mie_Joi_Vin_Sâm".split("_"),weekdaysMin:"Du_Lu_Ma_Mi_Jo_Vi_Sâ".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[azi la] LT",nextDay:"[mâine la] LT",nextWeek:"dddd [la] LT",lastDay:"[ieri la] LT",lastWeek:"[fosta] dddd [la] LT",sameElse:"L"},relativeTime:{future:"peste %s",past:"%s în urmă",s:"câteva secunde",ss:a,m:"un minut",mm:a,h:"o oră",hh:a,d:"o zi",dd:a,w:"o săptămână",ww:a,M:"o lună",MM:a,y:"un an",yy:a},week:{dow:1,doy:7}})}(t(5093))},2271:function(e,a,t){!function(e){"use strict"; +function a(e,a,t){var s=" ";return(e%100>=20||e>=100&&e%100==0)&&(s=" de "),e+s+{ss:"secunde",mm:"minute",hh:"ore",dd:"zile",ww:"săptămâni",MM:"luni",yy:"ani"}[t]}e.defineLocale("ro",{months:"ianuarie_februarie_martie_aprilie_mai_iunie_iulie_august_septembrie_octombrie_noiembrie_decembrie".split("_"),monthsShort:"ian._feb._mart._apr._mai_iun._iul._aug._sept._oct._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"duminică_luni_marți_miercuri_joi_vineri_sâmbătă".split("_"),weekdaysShort:"Dum_Lun_Mar_Mie_Joi_Vin_Sâm".split("_"),weekdaysMin:"Du_Lu_Ma_Mi_Jo_Vi_Sâ".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[azi la] LT",nextDay:"[mâine la] LT",nextWeek:"dddd [la] LT",lastDay:"[ieri la] LT",lastWeek:"[fosta] dddd [la] LT",sameElse:"L"},relativeTime:{future:"peste %s",past:"%s în urmă",s:"câteva secunde",ss:a,m:"un minut",mm:a,h:"o oră",hh:a,d:"o zi",dd:a,w:"o săptămână",ww:a,M:"o lună",MM:a,y:"un an",yy:a},week:{dow:1,doy:7}})}(t(5093))},2271(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e,a){var t=e.split("_");return a%10==1&&a%100!=11?t[0]:a%10>=2&&a%10<=4&&(a%100<10||a%100>=20)?t[1]:t[2]}function t(e,t,s){return"m"===s?t?"минута":"минуту":e+" "+a({ss:t?"секунда_секунды_секунд":"секунду_секунды_секунд",mm:t?"минута_минуты_минут":"минуту_минуты_минут",hh:"час_часа_часов",dd:"день_дня_дней",ww:"неделя_недели_недель",MM:"месяц_месяца_месяцев",yy:"год_года_лет"}[s],+e)}var s=[/^янв/i,/^фев/i,/^мар/i,/^апр/i,/^ма[йя]/i,/^июн/i,/^июл/i,/^авг/i,/^сен/i,/^окт/i,/^ноя/i,/^дек/i];e.defineLocale("ru",{months:{format:"января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря".split("_"),standalone:"январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь".split("_")},monthsShort:{format:"янв._февр._мар._апр._мая_июня_июля_авг._сент._окт._нояб._дек.".split("_"),standalone:"янв._февр._март_апр._май_июнь_июль_авг._сент._окт._нояб._дек.".split("_")},weekdays:{standalone:"воскресенье_понедельник_вторник_среда_четверг_пятница_суббота".split("_"),format:"воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу".split("_"),isFormat:/\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?] ?dddd/},weekdaysShort:"вс_пн_вт_ср_чт_пт_сб".split("_"),weekdaysMin:"вс_пн_вт_ср_чт_пт_сб".split("_"),monthsParse:s,longMonthsParse:s,shortMonthsParse:s,monthsRegex:/^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,monthsShortRegex:/^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,monthsStrictRegex:/^(январ[яь]|феврал[яь]|марта?|апрел[яь]|ма[яй]|июн[яь]|июл[яь]|августа?|сентябр[яь]|октябр[яь]|ноябр[яь]|декабр[яь])/i,monthsShortStrictRegex:/^(янв\.|февр?\.|мар[т.]|апр\.|ма[яй]|июн[ья.]|июл[ья.]|авг\.|сент?\.|окт\.|нояб?\.|дек\.)/i,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY г.",LLL:"D MMMM YYYY г., H:mm",LLLL:"dddd, D MMMM YYYY г., H:mm"},calendar:{sameDay:"[Сегодня, в] LT",nextDay:"[Завтра, в] LT",lastDay:"[Вчера, в] LT",nextWeek:function(e){if(e.week()===this.week())return 2===this.day()?"[Во] dddd, [в] LT":"[В] dddd, [в] LT";switch(this.day()){case 0:return"[В следующее] dddd, [в] LT";case 1:case 2:case 4:return"[В следующий] dddd, [в] LT";case 3:case 5:case 6:return"[В следующую] dddd, [в] LT"}},lastWeek:function(e){if(e.week()===this.week())return 2===this.day()?"[Во] dddd, [в] LT":"[В] dddd, [в] LT";switch(this.day()){case 0:return"[В прошлое] dddd, [в] LT";case 1:case 2:case 4:return"[В прошлый] dddd, [в] LT";case 3:case 5:case 6:return"[В прошлую] dddd, [в] LT"}},sameElse:"L"},relativeTime:{future:"через %s",past:"%s назад",s:"несколько секунд",ss:t,m:t,mm:t,h:"час",hh:t,d:"день",dd:t,w:"неделя",ww:t,M:"месяц",MM:t,y:"год",yy:t},meridiemParse:/ночи|утра|дня|вечера/i,isPM:function(e){return/^(дня|вечера)$/.test(e)},meridiem:function(e,a,t){return e<4?"ночи":e<12?"утра":e<17?"дня":"вечера"},dayOfMonthOrdinalParse:/\d{1,2}-(й|го|я)/,ordinal:function(e,a){switch(a){case"M":case"d":case"DDD":return e+"-й";case"D":return e+"-го";case"w":case"W":return e+"-я";default:return e}},week:{dow:1,doy:4}})}(t(5093))},1221:function(e,a,t){!function(e){"use strict"; +function a(e,a){var t=e.split("_");return a%10==1&&a%100!=11?t[0]:a%10>=2&&a%10<=4&&(a%100<10||a%100>=20)?t[1]:t[2]}function t(e,t,s){return"m"===s?t?"минута":"минуту":e+" "+a({ss:t?"секунда_секунды_секунд":"секунду_секунды_секунд",mm:t?"минута_минуты_минут":"минуту_минуты_минут",hh:"час_часа_часов",dd:"день_дня_дней",ww:"неделя_недели_недель",MM:"месяц_месяца_месяцев",yy:"год_года_лет"}[s],+e)}var s=[/^янв/i,/^фев/i,/^мар/i,/^апр/i,/^ма[йя]/i,/^июн/i,/^июл/i,/^авг/i,/^сен/i,/^окт/i,/^ноя/i,/^дек/i];e.defineLocale("ru",{months:{format:"января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря".split("_"),standalone:"январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь".split("_")},monthsShort:{format:"янв._февр._мар._апр._мая_июня_июля_авг._сент._окт._нояб._дек.".split("_"),standalone:"янв._февр._март_апр._май_июнь_июль_авг._сент._окт._нояб._дек.".split("_")},weekdays:{standalone:"воскресенье_понедельник_вторник_среда_четверг_пятница_суббота".split("_"),format:"воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу".split("_"),isFormat:/\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?] ?dddd/},weekdaysShort:"вс_пн_вт_ср_чт_пт_сб".split("_"),weekdaysMin:"вс_пн_вт_ср_чт_пт_сб".split("_"),monthsParse:s,longMonthsParse:s,shortMonthsParse:s,monthsRegex:/^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,monthsShortRegex:/^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,monthsStrictRegex:/^(январ[яь]|феврал[яь]|марта?|апрел[яь]|ма[яй]|июн[яь]|июл[яь]|августа?|сентябр[яь]|октябр[яь]|ноябр[яь]|декабр[яь])/i,monthsShortStrictRegex:/^(янв\.|февр?\.|мар[т.]|апр\.|ма[яй]|июн[ья.]|июл[ья.]|авг\.|сент?\.|окт\.|нояб?\.|дек\.)/i,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY г.",LLL:"D MMMM YYYY г., H:mm",LLLL:"dddd, D MMMM YYYY г., H:mm"},calendar:{sameDay:"[Сегодня, в] LT",nextDay:"[Завтра, в] LT",lastDay:"[Вчера, в] LT",nextWeek:function(e){if(e.week()===this.week())return 2===this.day()?"[Во] dddd, [в] LT":"[В] dddd, [в] LT";switch(this.day()){case 0:return"[В следующее] dddd, [в] LT";case 1:case 2:case 4:return"[В следующий] dddd, [в] LT";case 3:case 5:case 6:return"[В следующую] dddd, [в] LT"}},lastWeek:function(e){if(e.week()===this.week())return 2===this.day()?"[Во] dddd, [в] LT":"[В] dddd, [в] LT";switch(this.day()){case 0:return"[В прошлое] dddd, [в] LT";case 1:case 2:case 4:return"[В прошлый] dddd, [в] LT";case 3:case 5:case 6:return"[В прошлую] dddd, [в] LT"}},sameElse:"L"},relativeTime:{future:"через %s",past:"%s назад",s:"несколько секунд",ss:t,m:t,mm:t,h:"час",hh:t,d:"день",dd:t,w:"неделя",ww:t,M:"месяц",MM:t,y:"год",yy:t},meridiemParse:/ночи|утра|дня|вечера/i,isPM:function(e){return/^(дня|вечера)$/.test(e)},meridiem:function(e,a,t){return e<4?"ночи":e<12?"утра":e<17?"дня":"вечера"},dayOfMonthOrdinalParse:/\d{1,2}-(й|го|я)/,ordinal:function(e,a){switch(a){case"M":case"d":case"DDD":return e+"-й";case"D":return e+"-го";case"w":case"W":return e+"-я";default:return e}},week:{dow:1,doy:4}})}(t(5093))},1221(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a=["جنوري","فيبروري","مارچ","اپريل","مئي","جون","جولاءِ","آگسٽ","سيپٽمبر","آڪٽوبر","نومبر","ڊسمبر"],t=["آچر","سومر","اڱارو","اربع","خميس","جمع","ڇنڇر"];e.defineLocale("sd",{months:a,monthsShort:a,weekdays:t,weekdaysShort:t,weekdaysMin:t,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd، D MMMM YYYY HH:mm"},meridiemParse:/صبح|شام/,isPM:function(e){return"شام"===e},meridiem:function(e,a,t){return e<12?"صبح":"شام"},calendar:{sameDay:"[اڄ] LT",nextDay:"[سڀاڻي] LT",nextWeek:"dddd [اڳين هفتي تي] LT",lastDay:"[ڪالهه] LT",lastWeek:"[گزريل هفتي] dddd [تي] LT",sameElse:"L"},relativeTime:{future:"%s پوء",past:"%s اڳ",s:"چند سيڪنڊ",ss:"%d سيڪنڊ",m:"هڪ منٽ",mm:"%d منٽ",h:"هڪ ڪلاڪ",hh:"%d ڪلاڪ",d:"هڪ ڏينهن",dd:"%d ڏينهن",M:"هڪ مهينو",MM:"%d مهينا",y:"هڪ سال",yy:"%d سال"},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:1,doy:4}})}(t(5093))},3478:function(e,a,t){!function(e){"use strict"; +var a=["جنوري","فيبروري","مارچ","اپريل","مئي","جون","جولاءِ","آگسٽ","سيپٽمبر","آڪٽوبر","نومبر","ڊسمبر"],t=["آچر","سومر","اڱارو","اربع","خميس","جمع","ڇنڇر"];e.defineLocale("sd",{months:a,monthsShort:a,weekdays:t,weekdaysShort:t,weekdaysMin:t,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd، D MMMM YYYY HH:mm"},meridiemParse:/صبح|شام/,isPM:function(e){return"شام"===e},meridiem:function(e,a,t){return e<12?"صبح":"شام"},calendar:{sameDay:"[اڄ] LT",nextDay:"[سڀاڻي] LT",nextWeek:"dddd [اڳين هفتي تي] LT",lastDay:"[ڪالهه] LT",lastWeek:"[گزريل هفتي] dddd [تي] LT",sameElse:"L"},relativeTime:{future:"%s پوء",past:"%s اڳ",s:"چند سيڪنڊ",ss:"%d سيڪنڊ",m:"هڪ منٽ",mm:"%d منٽ",h:"هڪ ڪلاڪ",hh:"%d ڪلاڪ",d:"هڪ ڏينهن",dd:"%d ڏينهن",M:"هڪ مهينو",MM:"%d مهينا",y:"هڪ سال",yy:"%d سال"},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:1,doy:4}})}(t(5093))},3478(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("se",{months:"ođđajagemánnu_guovvamánnu_njukčamánnu_cuoŋománnu_miessemánnu_geassemánnu_suoidnemánnu_borgemánnu_čakčamánnu_golggotmánnu_skábmamánnu_juovlamánnu".split("_"),monthsShort:"ođđj_guov_njuk_cuo_mies_geas_suoi_borg_čakč_golg_skáb_juov".split("_"),weekdays:"sotnabeaivi_vuossárga_maŋŋebárga_gaskavahkku_duorastat_bearjadat_lávvardat".split("_"),weekdaysShort:"sotn_vuos_maŋ_gask_duor_bear_láv".split("_"),weekdaysMin:"s_v_m_g_d_b_L".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"MMMM D. [b.] YYYY",LLL:"MMMM D. [b.] YYYY [ti.] HH:mm",LLLL:"dddd, MMMM D. [b.] YYYY [ti.] HH:mm"},calendar:{sameDay:"[otne ti] LT",nextDay:"[ihttin ti] LT",nextWeek:"dddd [ti] LT",lastDay:"[ikte ti] LT",lastWeek:"[ovddit] dddd [ti] LT",sameElse:"L"},relativeTime:{future:"%s geažes",past:"maŋit %s",s:"moadde sekunddat",ss:"%d sekunddat",m:"okta minuhta",mm:"%d minuhtat",h:"okta diimmu",hh:"%d diimmut",d:"okta beaivi",dd:"%d beaivvit",M:"okta mánnu",MM:"%d mánut",y:"okta jahki",yy:"%d jagit"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},7538:function(e,a,t){!function(e){"use strict"; +e.defineLocale("se",{months:"ođđajagemánnu_guovvamánnu_njukčamánnu_cuoŋománnu_miessemánnu_geassemánnu_suoidnemánnu_borgemánnu_čakčamánnu_golggotmánnu_skábmamánnu_juovlamánnu".split("_"),monthsShort:"ođđj_guov_njuk_cuo_mies_geas_suoi_borg_čakč_golg_skáb_juov".split("_"),weekdays:"sotnabeaivi_vuossárga_maŋŋebárga_gaskavahkku_duorastat_bearjadat_lávvardat".split("_"),weekdaysShort:"sotn_vuos_maŋ_gask_duor_bear_láv".split("_"),weekdaysMin:"s_v_m_g_d_b_L".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"MMMM D. [b.] YYYY",LLL:"MMMM D. [b.] YYYY [ti.] HH:mm",LLLL:"dddd, MMMM D. [b.] YYYY [ti.] HH:mm"},calendar:{sameDay:"[otne ti] LT",nextDay:"[ihttin ti] LT",nextWeek:"dddd [ti] LT",lastDay:"[ikte ti] LT",lastWeek:"[ovddit] dddd [ti] LT",sameElse:"L"},relativeTime:{future:"%s geažes",past:"maŋit %s",s:"moadde sekunddat",ss:"%d sekunddat",m:"okta minuhta",mm:"%d minuhtat",h:"okta diimmu",hh:"%d diimmut",d:"okta beaivi",dd:"%d beaivvit",M:"okta mánnu",MM:"%d mánut",y:"okta jahki",yy:"%d jagit"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},7538(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("si",{months:"ජනවාරි_පෙබරවාරි_මාර්තු_අප්‍රේල්_මැයි_ජූනි_ජූලි_අගෝස්තු_සැප්තැම්බර්_ඔක්තෝබර්_නොවැම්බර්_දෙසැම්බර්".split("_"),monthsShort:"ජන_පෙබ_මාර්_අප්_මැයි_ජූනි_ජූලි_අගෝ_සැප්_ඔක්_නොවැ_දෙසැ".split("_"),weekdays:"ඉරිදා_සඳුදා_අඟහරුවාදා_බදාදා_බ්‍රහස්පතින්දා_සිකුරාදා_සෙනසුරාදා".split("_"),weekdaysShort:"ඉරි_සඳු_අඟ_බදා_බ්‍රහ_සිකු_සෙන".split("_"),weekdaysMin:"ඉ_ස_අ_බ_බ්‍ර_සි_සෙ".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"a h:mm",LTS:"a h:mm:ss",L:"YYYY/MM/DD",LL:"YYYY MMMM D",LLL:"YYYY MMMM D, a h:mm",LLLL:"YYYY MMMM D [වැනි] dddd, a h:mm:ss"},calendar:{sameDay:"[අද] LT[ට]",nextDay:"[හෙට] LT[ට]",nextWeek:"dddd LT[ට]",lastDay:"[ඊයේ] LT[ට]",lastWeek:"[පසුගිය] dddd LT[ට]",sameElse:"L"},relativeTime:{future:"%sකින්",past:"%sකට පෙර",s:"තත්පර කිහිපය",ss:"තත්පර %d",m:"මිනිත්තුව",mm:"මිනිත්තු %d",h:"පැය",hh:"පැය %d",d:"දිනය",dd:"දින %d",M:"මාසය",MM:"මාස %d",y:"වසර",yy:"වසර %d"},dayOfMonthOrdinalParse:/\d{1,2} වැනි/,ordinal:function(e){return e+" වැනි"},meridiemParse:/පෙර වරු|පස් වරු|පෙ.ව|ප.ව./,isPM:function(e){return"ප.ව."===e||"පස් වරු"===e},meridiem:function(e,a,t){return e>11?t?"ප.ව.":"පස් වරු":t?"පෙ.ව.":"පෙර වරු"}})}(t(5093))},5784:function(e,a,t){!function(e){"use strict"; +e.defineLocale("si",{months:"ජනවාරි_පෙබරවාරි_මාර්තු_අප්‍රේල්_මැයි_ජූනි_ජූලි_අගෝස්තු_සැප්තැම්බර්_ඔක්තෝබර්_නොවැම්බර්_දෙසැම්බර්".split("_"),monthsShort:"ජන_පෙබ_මාර්_අප්_මැයි_ජූනි_ජූලි_අගෝ_සැප්_ඔක්_නොවැ_දෙසැ".split("_"),weekdays:"ඉරිදා_සඳුදා_අඟහරුවාදා_බදාදා_බ්‍රහස්පතින්දා_සිකුරාදා_සෙනසුරාදා".split("_"),weekdaysShort:"ඉරි_සඳු_අඟ_බදා_බ්‍රහ_සිකු_සෙන".split("_"),weekdaysMin:"ඉ_ස_අ_බ_බ්‍ර_සි_සෙ".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"a h:mm",LTS:"a h:mm:ss",L:"YYYY/MM/DD",LL:"YYYY MMMM D",LLL:"YYYY MMMM D, a h:mm",LLLL:"YYYY MMMM D [වැනි] dddd, a h:mm:ss"},calendar:{sameDay:"[අද] LT[ට]",nextDay:"[හෙට] LT[ට]",nextWeek:"dddd LT[ට]",lastDay:"[ඊයේ] LT[ට]",lastWeek:"[පසුගිය] dddd LT[ට]",sameElse:"L"},relativeTime:{future:"%sකින්",past:"%sකට පෙර",s:"තත්පර කිහිපය",ss:"තත්පර %d",m:"මිනිත්තුව",mm:"මිනිත්තු %d",h:"පැය",hh:"පැය %d",d:"දිනය",dd:"දින %d",M:"මාසය",MM:"මාස %d",y:"වසර",yy:"වසර %d"},dayOfMonthOrdinalParse:/\d{1,2} වැනි/,ordinal:function(e){return e+" වැනි"},meridiemParse:/පෙර වරු|පස් වරු|පෙ.ව|ප.ව./,isPM:function(e){return"ප.ව."===e||"පස් වරු"===e},meridiem:function(e,a,t){return e>11?t?"ප.ව.":"පස් වරු":t?"පෙ.ව.":"පෙර වරු"}})}(t(5093))},5784(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a="január_február_marec_apríl_máj_jún_júl_august_september_október_november_december".split("_"),t="jan_feb_mar_apr_máj_jún_júl_aug_sep_okt_nov_dec".split("_");function s(e){return e>1&&e<5}function n(e,a,t,n){var r=e+" ";switch(t){case"s":return a||n?"pár sekúnd":"pár sekundami";case"ss":return a||n?r+(s(e)?"sekundy":"sekúnd"):r+"sekundami";case"m":return a?"minúta":n?"minútu":"minútou";case"mm":return a||n?r+(s(e)?"minúty":"minút"):r+"minútami";case"h":return a?"hodina":n?"hodinu":"hodinou";case"hh":return a||n?r+(s(e)?"hodiny":"hodín"):r+"hodinami";case"d":return a||n?"deň":"dňom";case"dd":return a||n?r+(s(e)?"dni":"dní"):r+"dňami";case"M":return a||n?"mesiac":"mesiacom";case"MM":return a||n?r+(s(e)?"mesiace":"mesiacov"):r+"mesiacmi";case"y":return a||n?"rok":"rokom";case"yy":return a||n?r+(s(e)?"roky":"rokov"):r+"rokmi"}}e.defineLocale("sk",{months:a,monthsShort:t,weekdays:"nedeľa_pondelok_utorok_streda_štvrtok_piatok_sobota".split("_"),weekdaysShort:"ne_po_ut_st_št_pi_so".split("_"),weekdaysMin:"ne_po_ut_st_št_pi_so".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd D. MMMM YYYY H:mm"},calendar:{sameDay:"[dnes o] LT",nextDay:"[zajtra o] LT",nextWeek:function(){switch(this.day()){case 0:return"[v nedeľu o] LT";case 1:case 2:return"[v] dddd [o] LT";case 3:return"[v stredu o] LT";case 4:return"[vo štvrtok o] LT";case 5:return"[v piatok o] LT";case 6:return"[v sobotu o] LT"}},lastDay:"[včera o] LT",lastWeek:function(){switch(this.day()){case 0:return"[minulú nedeľu o] LT";case 1:case 2:case 4:case 5:return"[minulý] dddd [o] LT";case 3:return"[minulú stredu o] LT";case 6:return"[minulú sobotu o] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"pred %s",s:n,ss:n,m:n,mm:n,h:n,hh:n,d:n,dd:n,M:n,MM:n,y:n,yy:n},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},6637:function(e,a,t){!function(e){"use strict"; +var a="január_február_marec_apríl_máj_jún_júl_august_september_október_november_december".split("_"),t="jan_feb_mar_apr_máj_jún_júl_aug_sep_okt_nov_dec".split("_");function s(e){return e>1&&e<5}function n(e,a,t,n){var r=e+" ";switch(t){case"s":return a||n?"pár sekúnd":"pár sekundami";case"ss":return a||n?r+(s(e)?"sekundy":"sekúnd"):r+"sekundami";case"m":return a?"minúta":n?"minútu":"minútou";case"mm":return a||n?r+(s(e)?"minúty":"minút"):r+"minútami";case"h":return a?"hodina":n?"hodinu":"hodinou";case"hh":return a||n?r+(s(e)?"hodiny":"hodín"):r+"hodinami";case"d":return a||n?"deň":"dňom";case"dd":return a||n?r+(s(e)?"dni":"dní"):r+"dňami";case"M":return a||n?"mesiac":"mesiacom";case"MM":return a||n?r+(s(e)?"mesiace":"mesiacov"):r+"mesiacmi";case"y":return a||n?"rok":"rokom";case"yy":return a||n?r+(s(e)?"roky":"rokov"):r+"rokmi"}}e.defineLocale("sk",{months:a,monthsShort:t,weekdays:"nedeľa_pondelok_utorok_streda_štvrtok_piatok_sobota".split("_"),weekdaysShort:"ne_po_ut_st_št_pi_so".split("_"),weekdaysMin:"ne_po_ut_st_št_pi_so".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd D. MMMM YYYY H:mm"},calendar:{sameDay:"[dnes o] LT",nextDay:"[zajtra o] LT",nextWeek:function(){switch(this.day()){case 0:return"[v nedeľu o] LT";case 1:case 2:return"[v] dddd [o] LT";case 3:return"[v stredu o] LT";case 4:return"[vo štvrtok o] LT";case 5:return"[v piatok o] LT";case 6:return"[v sobotu o] LT"}},lastDay:"[včera o] LT",lastWeek:function(){switch(this.day()){case 0:return"[minulú nedeľu o] LT";case 1:case 2:case 4:case 5:return"[minulý] dddd [o] LT";case 3:return"[minulú stredu o] LT";case 6:return"[minulú sobotu o] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"pred %s",s:n,ss:n,m:n,mm:n,h:n,hh:n,d:n,dd:n,M:n,MM:n,y:n,yy:n},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},6637(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e,a,t,s){var n=e+" ";switch(t){case"s":return a||s?"nekaj sekund":"nekaj sekundami";case"ss":return n+=1===e?a?"sekundo":"sekundi":2===e?a||s?"sekundi":"sekundah":e<5?a||s?"sekunde":"sekundah":"sekund";case"m":return a?"ena minuta":"eno minuto";case"mm":return n+=1===e?a?"minuta":"minuto":2===e?a||s?"minuti":"minutama":e<5?a||s?"minute":"minutami":a||s?"minut":"minutami";case"h":return a?"ena ura":"eno uro";case"hh":return n+=1===e?a?"ura":"uro":2===e?a||s?"uri":"urama":e<5?a||s?"ure":"urami":a||s?"ur":"urami";case"d":return a||s?"en dan":"enim dnem";case"dd":return n+=1===e?a||s?"dan":"dnem":2===e?a||s?"dni":"dnevoma":a||s?"dni":"dnevi";case"M":return a||s?"en mesec":"enim mesecem";case"MM":return n+=1===e?a||s?"mesec":"mesecem":2===e?a||s?"meseca":"mesecema":e<5?a||s?"mesece":"meseci":a||s?"mesecev":"meseci";case"y":return a||s?"eno leto":"enim letom";case"yy":return n+=1===e?a||s?"leto":"letom":2===e?a||s?"leti":"letoma":e<5?a||s?"leta":"leti":a||s?"let":"leti"}}e.defineLocale("sl",{months:"januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december".split("_"),monthsShort:"jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota".split("_"),weekdaysShort:"ned._pon._tor._sre._čet._pet._sob.".split("_"),weekdaysMin:"ne_po_to_sr_če_pe_so".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD. MM. YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danes ob] LT",nextDay:"[jutri ob] LT",nextWeek:function(){switch(this.day()){case 0:return"[v] [nedeljo] [ob] LT";case 3:return"[v] [sredo] [ob] LT";case 6:return"[v] [soboto] [ob] LT";case 1:case 2:case 4:case 5:return"[v] dddd [ob] LT"}},lastDay:"[včeraj ob] LT",lastWeek:function(){switch(this.day()){case 0:return"[prejšnjo] [nedeljo] [ob] LT";case 3:return"[prejšnjo] [sredo] [ob] LT";case 6:return"[prejšnjo] [soboto] [ob] LT";case 1:case 2:case 4:case 5:return"[prejšnji] dddd [ob] LT"}},sameElse:"L"},relativeTime:{future:"čez %s",past:"pred %s",s:a,ss:a,m:a,mm:a,h:a,hh:a,d:a,dd:a,M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(t(5093))},6794:function(e,a,t){!function(e){"use strict"; +function a(e,a,t,s){var n=e+" ";switch(t){case"s":return a||s?"nekaj sekund":"nekaj sekundami";case"ss":return n+=1===e?a?"sekundo":"sekundi":2===e?a||s?"sekundi":"sekundah":e<5?a||s?"sekunde":"sekundah":"sekund";case"m":return a?"ena minuta":"eno minuto";case"mm":return n+=1===e?a?"minuta":"minuto":2===e?a||s?"minuti":"minutama":e<5?a||s?"minute":"minutami":a||s?"minut":"minutami";case"h":return a?"ena ura":"eno uro";case"hh":return n+=1===e?a?"ura":"uro":2===e?a||s?"uri":"urama":e<5?a||s?"ure":"urami":a||s?"ur":"urami";case"d":return a||s?"en dan":"enim dnem";case"dd":return n+=1===e?a||s?"dan":"dnem":2===e?a||s?"dni":"dnevoma":a||s?"dni":"dnevi";case"M":return a||s?"en mesec":"enim mesecem";case"MM":return n+=1===e?a||s?"mesec":"mesecem":2===e?a||s?"meseca":"mesecema":e<5?a||s?"mesece":"meseci":a||s?"mesecev":"meseci";case"y":return a||s?"eno leto":"enim letom";case"yy":return n+=1===e?a||s?"leto":"letom":2===e?a||s?"leti":"letoma":e<5?a||s?"leta":"leti":a||s?"let":"leti"}}e.defineLocale("sl",{months:"januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december".split("_"),monthsShort:"jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota".split("_"),weekdaysShort:"ned._pon._tor._sre._čet._pet._sob.".split("_"),weekdaysMin:"ne_po_to_sr_če_pe_so".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD. MM. YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danes ob] LT",nextDay:"[jutri ob] LT",nextWeek:function(){switch(this.day()){case 0:return"[v] [nedeljo] [ob] LT";case 3:return"[v] [sredo] [ob] LT";case 6:return"[v] [soboto] [ob] LT";case 1:case 2:case 4:case 5:return"[v] dddd [ob] LT"}},lastDay:"[včeraj ob] LT",lastWeek:function(){switch(this.day()){case 0:return"[prejšnjo] [nedeljo] [ob] LT";case 3:return"[prejšnjo] [sredo] [ob] LT";case 6:return"[prejšnjo] [soboto] [ob] LT";case 1:case 2:case 4:case 5:return"[prejšnji] dddd [ob] LT"}},sameElse:"L"},relativeTime:{future:"čez %s",past:"pred %s",s:a,ss:a,m:a,mm:a,h:a,hh:a,d:a,dd:a,M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(t(5093))},6794(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("sq",{months:"Janar_Shkurt_Mars_Prill_Maj_Qershor_Korrik_Gusht_Shtator_Tetor_Nëntor_Dhjetor".split("_"),monthsShort:"Jan_Shk_Mar_Pri_Maj_Qer_Kor_Gus_Sht_Tet_Nën_Dhj".split("_"),weekdays:"E Diel_E Hënë_E Martë_E Mërkurë_E Enjte_E Premte_E Shtunë".split("_"),weekdaysShort:"Die_Hën_Mar_Mër_Enj_Pre_Sht".split("_"),weekdaysMin:"D_H_Ma_Më_E_P_Sh".split("_"),weekdaysParseExact:!0,meridiemParse:/PD|MD/,isPM:function(e){return"M"===e.charAt(0)},meridiem:function(e,a,t){return e<12?"PD":"MD"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Sot në] LT",nextDay:"[Nesër në] LT",nextWeek:"dddd [në] LT",lastDay:"[Dje në] LT",lastWeek:"dddd [e kaluar në] LT",sameElse:"L"},relativeTime:{future:"në %s",past:"%s më parë",s:"disa sekonda",ss:"%d sekonda",m:"një minutë",mm:"%d minuta",h:"një orë",hh:"%d orë",d:"një ditë",dd:"%d ditë",M:"një muaj",MM:"%d muaj",y:"një vit",yy:"%d vite"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},3322:function(e,a,t){!function(e){"use strict"; +e.defineLocale("sq",{months:"Janar_Shkurt_Mars_Prill_Maj_Qershor_Korrik_Gusht_Shtator_Tetor_Nëntor_Dhjetor".split("_"),monthsShort:"Jan_Shk_Mar_Pri_Maj_Qer_Kor_Gus_Sht_Tet_Nën_Dhj".split("_"),weekdays:"E Diel_E Hënë_E Martë_E Mërkurë_E Enjte_E Premte_E Shtunë".split("_"),weekdaysShort:"Die_Hën_Mar_Mër_Enj_Pre_Sht".split("_"),weekdaysMin:"D_H_Ma_Më_E_P_Sh".split("_"),weekdaysParseExact:!0,meridiemParse:/PD|MD/,isPM:function(e){return"M"===e.charAt(0)},meridiem:function(e,a,t){return e<12?"PD":"MD"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Sot në] LT",nextDay:"[Nesër në] LT",nextWeek:"dddd [në] LT",lastDay:"[Dje në] LT",lastWeek:"dddd [e kaluar në] LT",sameElse:"L"},relativeTime:{future:"në %s",past:"%s më parë",s:"disa sekonda",ss:"%d sekonda",m:"një minutë",mm:"%d minuta",h:"një orë",hh:"%d orë",d:"një ditë",dd:"%d ditë",M:"një muaj",MM:"%d muaj",y:"një vit",yy:"%d vite"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},3322(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={words:{ss:["секунда","секунде","секунди"],m:["један минут","једног минута"],mm:["минут","минута","минута"],h:["један сат","једног сата"],hh:["сат","сата","сати"],d:["један дан","једног дана"],dd:["дан","дана","дана"],M:["један месец","једног месеца"],MM:["месец","месеца","месеци"],y:["једну годину","једне године"],yy:["годину","године","година"]},correctGrammaticalCase:function(e,a){return e%10>=1&&e%10<=4&&(e%100<10||e%100>=20)?e%10==1?a[0]:a[1]:a[2]},translate:function(e,t,s,n){var r,i=a.words[s];return 1===s.length?"y"===s&&t?"једна година":n||t?i[0]:i[1]:(r=a.correctGrammaticalCase(e,i),"yy"===s&&t&&"годину"===r?e+" година":e+" "+r)}};e.defineLocale("sr-cyrl",{months:"јануар_фебруар_март_април_мај_јун_јул_август_септембар_октобар_новембар_децембар".split("_"),monthsShort:"јан._феб._мар._апр._мај_јун_јул_авг._сеп._окт._нов._дец.".split("_"),monthsParseExact:!0,weekdays:"недеља_понедељак_уторак_среда_четвртак_петак_субота".split("_"),weekdaysShort:"нед._пон._уто._сре._чет._пет._суб.".split("_"),weekdaysMin:"не_по_ут_ср_че_пе_су".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D. M. YYYY.",LL:"D. MMMM YYYY.",LLL:"D. MMMM YYYY. H:mm",LLLL:"dddd, D. MMMM YYYY. H:mm"},calendar:{sameDay:"[данас у] LT",nextDay:"[сутра у] LT",nextWeek:function(){switch(this.day()){case 0:return"[у] [недељу] [у] LT";case 3:return"[у] [среду] [у] LT";case 6:return"[у] [суботу] [у] LT";case 1:case 2:case 4:case 5:return"[у] dddd [у] LT"}},lastDay:"[јуче у] LT",lastWeek:function(){return["[прошле] [недеље] [у] LT","[прошлог] [понедељка] [у] LT","[прошлог] [уторка] [у] LT","[прошле] [среде] [у] LT","[прошлог] [четвртка] [у] LT","[прошлог] [петка] [у] LT","[прошле] [суботе] [у] LT"][this.day()]},sameElse:"L"},relativeTime:{future:"за %s",past:"пре %s",s:"неколико секунди",ss:a.translate,m:a.translate,mm:a.translate,h:a.translate,hh:a.translate,d:a.translate,dd:a.translate,M:a.translate,MM:a.translate,y:a.translate,yy:a.translate},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(t(5093))},5719:function(e,a,t){!function(e){"use strict"; +var a={words:{ss:["секунда","секунде","секунди"],m:["један минут","једног минута"],mm:["минут","минута","минута"],h:["један сат","једног сата"],hh:["сат","сата","сати"],d:["један дан","једног дана"],dd:["дан","дана","дана"],M:["један месец","једног месеца"],MM:["месец","месеца","месеци"],y:["једну годину","једне године"],yy:["годину","године","година"]},correctGrammaticalCase:function(e,a){return e%10>=1&&e%10<=4&&(e%100<10||e%100>=20)?e%10==1?a[0]:a[1]:a[2]},translate:function(e,t,s,n){var r,d=a.words[s];return 1===s.length?"y"===s&&t?"једна година":n||t?d[0]:d[1]:(r=a.correctGrammaticalCase(e,d),"yy"===s&&t&&"годину"===r?e+" година":e+" "+r)}};e.defineLocale("sr-cyrl",{months:"јануар_фебруар_март_април_мај_јун_јул_август_септембар_октобар_новембар_децембар".split("_"),monthsShort:"јан._феб._мар._апр._мај_јун_јул_авг._сеп._окт._нов._дец.".split("_"),monthsParseExact:!0,weekdays:"недеља_понедељак_уторак_среда_четвртак_петак_субота".split("_"),weekdaysShort:"нед._пон._уто._сре._чет._пет._суб.".split("_"),weekdaysMin:"не_по_ут_ср_че_пе_су".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D. M. YYYY.",LL:"D. MMMM YYYY.",LLL:"D. MMMM YYYY. H:mm",LLLL:"dddd, D. MMMM YYYY. H:mm"},calendar:{sameDay:"[данас у] LT",nextDay:"[сутра у] LT",nextWeek:function(){switch(this.day()){case 0:return"[у] [недељу] [у] LT";case 3:return"[у] [среду] [у] LT";case 6:return"[у] [суботу] [у] LT";case 1:case 2:case 4:case 5:return"[у] dddd [у] LT"}},lastDay:"[јуче у] LT",lastWeek:function(){return["[прошле] [недеље] [у] LT","[прошлог] [понедељка] [у] LT","[прошлог] [уторка] [у] LT","[прошле] [среде] [у] LT","[прошлог] [четвртка] [у] LT","[прошлог] [петка] [у] LT","[прошле] [суботе] [у] LT"][this.day()]},sameElse:"L"},relativeTime:{future:"за %s",past:"пре %s",s:"неколико секунди",ss:a.translate,m:a.translate,mm:a.translate,h:a.translate,hh:a.translate,d:a.translate,dd:a.translate,M:a.translate,MM:a.translate,y:a.translate,yy:a.translate},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(t(5093))},5719(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={words:{ss:["sekunda","sekunde","sekundi"],m:["jedan minut","jednog minuta"],mm:["minut","minuta","minuta"],h:["jedan sat","jednog sata"],hh:["sat","sata","sati"],d:["jedan dan","jednog dana"],dd:["dan","dana","dana"],M:["jedan mesec","jednog meseca"],MM:["mesec","meseca","meseci"],y:["jednu godinu","jedne godine"],yy:["godinu","godine","godina"]},correctGrammaticalCase:function(e,a){return e%10>=1&&e%10<=4&&(e%100<10||e%100>=20)?e%10==1?a[0]:a[1]:a[2]},translate:function(e,t,s,n){var r,i=a.words[s];return 1===s.length?"y"===s&&t?"jedna godina":n||t?i[0]:i[1]:(r=a.correctGrammaticalCase(e,i),"yy"===s&&t&&"godinu"===r?e+" godina":e+" "+r)}};e.defineLocale("sr",{months:"januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedelja_ponedeljak_utorak_sreda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sre._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D. M. YYYY.",LL:"D. MMMM YYYY.",LLL:"D. MMMM YYYY. H:mm",LLLL:"dddd, D. MMMM YYYY. H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedelju] [u] LT";case 3:return"[u] [sredu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[juče u] LT",lastWeek:function(){return["[prošle] [nedelje] [u] LT","[prošlog] [ponedeljka] [u] LT","[prošlog] [utorka] [u] LT","[prošle] [srede] [u] LT","[prošlog] [četvrtka] [u] LT","[prošlog] [petka] [u] LT","[prošle] [subote] [u] LT"][this.day()]},sameElse:"L"},relativeTime:{future:"za %s",past:"pre %s",s:"nekoliko sekundi",ss:a.translate,m:a.translate,mm:a.translate,h:a.translate,hh:a.translate,d:a.translate,dd:a.translate,M:a.translate,MM:a.translate,y:a.translate,yy:a.translate},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(t(5093))},6e3:function(e,a,t){!function(e){"use strict"; +var a={words:{ss:["sekunda","sekunde","sekundi"],m:["jedan minut","jednog minuta"],mm:["minut","minuta","minuta"],h:["jedan sat","jednog sata"],hh:["sat","sata","sati"],d:["jedan dan","jednog dana"],dd:["dan","dana","dana"],M:["jedan mesec","jednog meseca"],MM:["mesec","meseca","meseci"],y:["jednu godinu","jedne godine"],yy:["godinu","godine","godina"]},correctGrammaticalCase:function(e,a){return e%10>=1&&e%10<=4&&(e%100<10||e%100>=20)?e%10==1?a[0]:a[1]:a[2]},translate:function(e,t,s,n){var r,d=a.words[s];return 1===s.length?"y"===s&&t?"jedna godina":n||t?d[0]:d[1]:(r=a.correctGrammaticalCase(e,d),"yy"===s&&t&&"godinu"===r?e+" godina":e+" "+r)}};e.defineLocale("sr",{months:"januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedelja_ponedeljak_utorak_sreda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sre._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D. M. YYYY.",LL:"D. MMMM YYYY.",LLL:"D. MMMM YYYY. H:mm",LLLL:"dddd, D. MMMM YYYY. H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedelju] [u] LT";case 3:return"[u] [sredu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[juče u] LT",lastWeek:function(){return["[prošle] [nedelje] [u] LT","[prošlog] [ponedeljka] [u] LT","[prošlog] [utorka] [u] LT","[prošle] [srede] [u] LT","[prošlog] [četvrtka] [u] LT","[prošlog] [petka] [u] LT","[prošle] [subote] [u] LT"][this.day()]},sameElse:"L"},relativeTime:{future:"za %s",past:"pre %s",s:"nekoliko sekundi",ss:a.translate,m:a.translate,mm:a.translate,h:a.translate,hh:a.translate,d:a.translate,dd:a.translate,M:a.translate,MM:a.translate,y:a.translate,yy:a.translate},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(t(5093))},6e3(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("ss",{months:"Bhimbidvwane_Indlovana_Indlov'lenkhulu_Mabasa_Inkhwekhweti_Inhlaba_Kholwane_Ingci_Inyoni_Imphala_Lweti_Ingongoni".split("_"),monthsShort:"Bhi_Ina_Inu_Mab_Ink_Inh_Kho_Igc_Iny_Imp_Lwe_Igo".split("_"),weekdays:"Lisontfo_Umsombuluko_Lesibili_Lesitsatfu_Lesine_Lesihlanu_Umgcibelo".split("_"),weekdaysShort:"Lis_Umb_Lsb_Les_Lsi_Lsh_Umg".split("_"),weekdaysMin:"Li_Us_Lb_Lt_Ls_Lh_Ug".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Namuhla nga] LT",nextDay:"[Kusasa nga] LT",nextWeek:"dddd [nga] LT",lastDay:"[Itolo nga] LT",lastWeek:"dddd [leliphelile] [nga] LT",sameElse:"L"},relativeTime:{future:"nga %s",past:"wenteka nga %s",s:"emizuzwana lomcane",ss:"%d mzuzwana",m:"umzuzu",mm:"%d emizuzu",h:"lihora",hh:"%d emahora",d:"lilanga",dd:"%d emalanga",M:"inyanga",MM:"%d tinyanga",y:"umnyaka",yy:"%d iminyaka"},meridiemParse:/ekuseni|emini|entsambama|ebusuku/,meridiem:function(e,a,t){return e<11?"ekuseni":e<15?"emini":e<19?"entsambama":"ebusuku"},meridiemHour:function(e,a){return 12===e&&(e=0),"ekuseni"===a?e:"emini"===a?e>=11?e:e+12:"entsambama"===a||"ebusuku"===a?0===e?0:e+12:void 0},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:"%d",week:{dow:1,doy:4}})}(t(5093))},1011:function(e,a,t){!function(e){"use strict"; +e.defineLocale("ss",{months:"Bhimbidvwane_Indlovana_Indlov'lenkhulu_Mabasa_Inkhwekhweti_Inhlaba_Kholwane_Ingci_Inyoni_Imphala_Lweti_Ingongoni".split("_"),monthsShort:"Bhi_Ina_Inu_Mab_Ink_Inh_Kho_Igc_Iny_Imp_Lwe_Igo".split("_"),weekdays:"Lisontfo_Umsombuluko_Lesibili_Lesitsatfu_Lesine_Lesihlanu_Umgcibelo".split("_"),weekdaysShort:"Lis_Umb_Lsb_Les_Lsi_Lsh_Umg".split("_"),weekdaysMin:"Li_Us_Lb_Lt_Ls_Lh_Ug".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Namuhla nga] LT",nextDay:"[Kusasa nga] LT",nextWeek:"dddd [nga] LT",lastDay:"[Itolo nga] LT",lastWeek:"dddd [leliphelile] [nga] LT",sameElse:"L"},relativeTime:{future:"nga %s",past:"wenteka nga %s",s:"emizuzwana lomcane",ss:"%d mzuzwana",m:"umzuzu",mm:"%d emizuzu",h:"lihora",hh:"%d emahora",d:"lilanga",dd:"%d emalanga",M:"inyanga",MM:"%d tinyanga",y:"umnyaka",yy:"%d iminyaka"},meridiemParse:/ekuseni|emini|entsambama|ebusuku/,meridiem:function(e,a,t){return e<11?"ekuseni":e<15?"emini":e<19?"entsambama":"ebusuku"},meridiemHour:function(e,a){return 12===e&&(e=0),"ekuseni"===a?e:"emini"===a?e>=11?e:e+12:"entsambama"===a||"ebusuku"===a?0===e?0:e+12:void 0},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:"%d",week:{dow:1,doy:4}})}(t(5093))},1011(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("sv",{months:"januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december".split("_"),monthsShort:"jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec".split("_"),weekdays:"söndag_måndag_tisdag_onsdag_torsdag_fredag_lördag".split("_"),weekdaysShort:"sön_mån_tis_ons_tor_fre_lör".split("_"),weekdaysMin:"sö_må_ti_on_to_fr_lö".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [kl.] HH:mm",LLLL:"dddd D MMMM YYYY [kl.] HH:mm",lll:"D MMM YYYY HH:mm",llll:"ddd D MMM YYYY HH:mm"},calendar:{sameDay:"[Idag] LT",nextDay:"[Imorgon] LT",lastDay:"[Igår] LT",nextWeek:"[På] dddd LT",lastWeek:"[I] dddd[s] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"för %s sedan",s:"några sekunder",ss:"%d sekunder",m:"en minut",mm:"%d minuter",h:"en timme",hh:"%d timmar",d:"en dag",dd:"%d dagar",M:"en månad",MM:"%d månader",y:"ett år",yy:"%d år"},dayOfMonthOrdinalParse:/\d{1,2}(\:e|\:a)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?":e":1===a||2===a?":a":":e")},week:{dow:1,doy:4}})}(t(5093))},748:function(e,a,t){!function(e){"use strict"; +e.defineLocale("sv",{months:"januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december".split("_"),monthsShort:"jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec".split("_"),weekdays:"söndag_måndag_tisdag_onsdag_torsdag_fredag_lördag".split("_"),weekdaysShort:"sön_mån_tis_ons_tor_fre_lör".split("_"),weekdaysMin:"sö_må_ti_on_to_fr_lö".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [kl.] HH:mm",LLLL:"dddd D MMMM YYYY [kl.] HH:mm",lll:"D MMM YYYY HH:mm",llll:"ddd D MMM YYYY HH:mm"},calendar:{sameDay:"[Idag] LT",nextDay:"[Imorgon] LT",lastDay:"[Igår] LT",nextWeek:"[På] dddd LT",lastWeek:"[I] dddd[s] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"för %s sedan",s:"några sekunder",ss:"%d sekunder",m:"en minut",mm:"%d minuter",h:"en timme",hh:"%d timmar",d:"en dag",dd:"%d dagar",M:"en månad",MM:"%d månader",y:"ett år",yy:"%d år"},dayOfMonthOrdinalParse:/\d{1,2}(\:e|\:a)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?":e":1===a||2===a?":a":":e")},week:{dow:1,doy:4}})}(t(5093))},748(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("sw",{months:"Januari_Februari_Machi_Aprili_Mei_Juni_Julai_Agosti_Septemba_Oktoba_Novemba_Desemba".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ago_Sep_Okt_Nov_Des".split("_"),weekdays:"Jumapili_Jumatatu_Jumanne_Jumatano_Alhamisi_Ijumaa_Jumamosi".split("_"),weekdaysShort:"Jpl_Jtat_Jnne_Jtan_Alh_Ijm_Jmos".split("_"),weekdaysMin:"J2_J3_J4_J5_Al_Ij_J1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"hh:mm A",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[leo saa] LT",nextDay:"[kesho saa] LT",nextWeek:"[wiki ijayo] dddd [saat] LT",lastDay:"[jana] LT",lastWeek:"[wiki iliyopita] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s baadaye",past:"tokea %s",s:"hivi punde",ss:"sekunde %d",m:"dakika moja",mm:"dakika %d",h:"saa limoja",hh:"masaa %d",d:"siku moja",dd:"siku %d",M:"mwezi mmoja",MM:"miezi %d",y:"mwaka mmoja",yy:"miaka %d"},week:{dow:1,doy:7}})}(t(5093))},1025:function(e,a,t){!function(e){"use strict"; +e.defineLocale("sw",{months:"Januari_Februari_Machi_Aprili_Mei_Juni_Julai_Agosti_Septemba_Oktoba_Novemba_Desemba".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ago_Sep_Okt_Nov_Des".split("_"),weekdays:"Jumapili_Jumatatu_Jumanne_Jumatano_Alhamisi_Ijumaa_Jumamosi".split("_"),weekdaysShort:"Jpl_Jtat_Jnne_Jtan_Alh_Ijm_Jmos".split("_"),weekdaysMin:"J2_J3_J4_J5_Al_Ij_J1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"hh:mm A",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[leo saa] LT",nextDay:"[kesho saa] LT",nextWeek:"[wiki ijayo] dddd [saat] LT",lastDay:"[jana] LT",lastWeek:"[wiki iliyopita] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s baadaye",past:"tokea %s",s:"hivi punde",ss:"sekunde %d",m:"dakika moja",mm:"dakika %d",h:"saa limoja",hh:"masaa %d",d:"siku moja",dd:"siku %d",M:"mwezi mmoja",MM:"miezi %d",y:"mwaka mmoja",yy:"miaka %d"},week:{dow:1,doy:7}})}(t(5093))},1025(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"௧",2:"௨",3:"௩",4:"௪",5:"௫",6:"௬",7:"௭",8:"௮",9:"௯",0:"௦"},t={"௧":"1","௨":"2","௩":"3","௪":"4","௫":"5","௬":"6","௭":"7","௮":"8","௯":"9","௦":"0"};e.defineLocale("ta",{months:"ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்".split("_"),monthsShort:"ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்".split("_"),weekdays:"ஞாயிற்றுக்கிழமை_திங்கட்கிழமை_செவ்வாய்கிழமை_புதன்கிழமை_வியாழக்கிழமை_வெள்ளிக்கிழமை_சனிக்கிழமை".split("_"),weekdaysShort:"ஞாயிறு_திங்கள்_செவ்வாய்_புதன்_வியாழன்_வெள்ளி_சனி".split("_"),weekdaysMin:"ஞா_தி_செ_பு_வி_வெ_ச".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, HH:mm",LLLL:"dddd, D MMMM YYYY, HH:mm"},calendar:{sameDay:"[இன்று] LT",nextDay:"[நாளை] LT",nextWeek:"dddd, LT",lastDay:"[நேற்று] LT",lastWeek:"[கடந்த வாரம்] dddd, LT",sameElse:"L"},relativeTime:{future:"%s இல்",past:"%s முன்",s:"ஒரு சில விநாடிகள்",ss:"%d விநாடிகள்",m:"ஒரு நிமிடம்",mm:"%d நிமிடங்கள்",h:"ஒரு மணி நேரம்",hh:"%d மணி நேரம்",d:"ஒரு நாள்",dd:"%d நாட்கள்",M:"ஒரு மாதம்",MM:"%d மாதங்கள்",y:"ஒரு வருடம்",yy:"%d ஆண்டுகள்"},dayOfMonthOrdinalParse:/\d{1,2}வது/,ordinal:function(e){return e+"வது"},preparse:function(e){return e.replace(/[௧௨௩௪௫௬௭௮௯௦]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/யாமம்|வைகறை|காலை|நண்பகல்|எற்பாடு|மாலை/,meridiem:function(e,a,t){return e<2?" யாமம்":e<6?" வைகறை":e<10?" காலை":e<14?" நண்பகல்":e<18?" எற்பாடு":e<22?" மாலை":" யாமம்"},meridiemHour:function(e,a){return 12===e&&(e=0),"யாமம்"===a?e<2?e:e+12:"வைகறை"===a||"காலை"===a||"நண்பகல்"===a&&e>=10?e:e+12},week:{dow:0,doy:6}})}(t(5093))},1885:function(e,a,t){!function(e){"use strict"; +var a={1:"௧",2:"௨",3:"௩",4:"௪",5:"௫",6:"௬",7:"௭",8:"௮",9:"௯",0:"௦"},t={"௧":"1","௨":"2","௩":"3","௪":"4","௫":"5","௬":"6","௭":"7","௮":"8","௯":"9","௦":"0"};e.defineLocale("ta",{months:"ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்".split("_"),monthsShort:"ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்".split("_"),weekdays:"ஞாயிற்றுக்கிழமை_திங்கட்கிழமை_செவ்வாய்கிழமை_புதன்கிழமை_வியாழக்கிழமை_வெள்ளிக்கிழமை_சனிக்கிழமை".split("_"),weekdaysShort:"ஞாயிறு_திங்கள்_செவ்வாய்_புதன்_வியாழன்_வெள்ளி_சனி".split("_"),weekdaysMin:"ஞா_தி_செ_பு_வி_வெ_ச".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, HH:mm",LLLL:"dddd, D MMMM YYYY, HH:mm"},calendar:{sameDay:"[இன்று] LT",nextDay:"[நாளை] LT",nextWeek:"dddd, LT",lastDay:"[நேற்று] LT",lastWeek:"[கடந்த வாரம்] dddd, LT",sameElse:"L"},relativeTime:{future:"%s இல்",past:"%s முன்",s:"ஒரு சில விநாடிகள்",ss:"%d விநாடிகள்",m:"ஒரு நிமிடம்",mm:"%d நிமிடங்கள்",h:"ஒரு மணி நேரம்",hh:"%d மணி நேரம்",d:"ஒரு நாள்",dd:"%d நாட்கள்",M:"ஒரு மாதம்",MM:"%d மாதங்கள்",y:"ஒரு வருடம்",yy:"%d ஆண்டுகள்"},dayOfMonthOrdinalParse:/\d{1,2}வது/,ordinal:function(e){return e+"வது"},preparse:function(e){return e.replace(/[௧௨௩௪௫௬௭௮௯௦]/g,(function(e){return t[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return a[e]}))},meridiemParse:/யாமம்|வைகறை|காலை|நண்பகல்|எற்பாடு|மாலை/,meridiem:function(e,a,t){return e<2?" யாமம்":e<6?" வைகறை":e<10?" காலை":e<14?" நண்பகல்":e<18?" எற்பாடு":e<22?" மாலை":" யாமம்"},meridiemHour:function(e,a){return 12===e&&(e=0),"யாமம்"===a?e<2?e:e+12:"வைகறை"===a||"காலை"===a||"நண்பகல்"===a&&e>=10?e:e+12},week:{dow:0,doy:6}})}(t(5093))},1885(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("te",{months:"జనవరి_ఫిబ్రవరి_మార్చి_ఏప్రిల్_మే_జూన్_జులై_ఆగస్టు_సెప్టెంబర్_అక్టోబర్_నవంబర్_డిసెంబర్".split("_"),monthsShort:"జన._ఫిబ్ర._మార్చి_ఏప్రి._మే_జూన్_జులై_ఆగ._సెప్._అక్టో._నవ._డిసె.".split("_"),monthsParseExact:!0,weekdays:"ఆదివారం_సోమవారం_మంగళవారం_బుధవారం_గురువారం_శుక్రవారం_శనివారం".split("_"),weekdaysShort:"ఆది_సోమ_మంగళ_బుధ_గురు_శుక్ర_శని".split("_"),weekdaysMin:"ఆ_సో_మం_బు_గు_శు_శ".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[నేడు] LT",nextDay:"[రేపు] LT",nextWeek:"dddd, LT",lastDay:"[నిన్న] LT",lastWeek:"[గత] dddd, LT",sameElse:"L"},relativeTime:{future:"%s లో",past:"%s క్రితం",s:"కొన్ని క్షణాలు",ss:"%d సెకన్లు",m:"ఒక నిమిషం",mm:"%d నిమిషాలు",h:"ఒక గంట",hh:"%d గంటలు",d:"ఒక రోజు",dd:"%d రోజులు",M:"ఒక నెల",MM:"%d నెలలు",y:"ఒక సంవత్సరం",yy:"%d సంవత్సరాలు"},dayOfMonthOrdinalParse:/\d{1,2}వ/,ordinal:"%dవ",meridiemParse:/రాత్రి|ఉదయం|మధ్యాహ్నం|సాయంత్రం/,meridiemHour:function(e,a){return 12===e&&(e=0),"రాత్రి"===a?e<4?e:e+12:"ఉదయం"===a?e:"మధ్యాహ్నం"===a?e>=10?e:e+12:"సాయంత్రం"===a?e+12:void 0},meridiem:function(e,a,t){return e<4?"రాత్రి":e<10?"ఉదయం":e<17?"మధ్యాహ్నం":e<20?"సాయంత్రం":"రాత్రి"},week:{dow:0,doy:6}})}(t(5093))},8861:function(e,a,t){!function(e){"use strict"; +e.defineLocale("te",{months:"జనవరి_ఫిబ్రవరి_మార్చి_ఏప్రిల్_మే_జూన్_జులై_ఆగస్టు_సెప్టెంబర్_అక్టోబర్_నవంబర్_డిసెంబర్".split("_"),monthsShort:"జన._ఫిబ్ర._మార్చి_ఏప్రి._మే_జూన్_జులై_ఆగ._సెప్._అక్టో._నవ._డిసె.".split("_"),monthsParseExact:!0,weekdays:"ఆదివారం_సోమవారం_మంగళవారం_బుధవారం_గురువారం_శుక్రవారం_శనివారం".split("_"),weekdaysShort:"ఆది_సోమ_మంగళ_బుధ_గురు_శుక్ర_శని".split("_"),weekdaysMin:"ఆ_సో_మం_బు_గు_శు_శ".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[నేడు] LT",nextDay:"[రేపు] LT",nextWeek:"dddd, LT",lastDay:"[నిన్న] LT",lastWeek:"[గత] dddd, LT",sameElse:"L"},relativeTime:{future:"%s లో",past:"%s క్రితం",s:"కొన్ని క్షణాలు",ss:"%d సెకన్లు",m:"ఒక నిమిషం",mm:"%d నిమిషాలు",h:"ఒక గంట",hh:"%d గంటలు",d:"ఒక రోజు",dd:"%d రోజులు",M:"ఒక నెల",MM:"%d నెలలు",y:"ఒక సంవత్సరం",yy:"%d సంవత్సరాలు"},dayOfMonthOrdinalParse:/\d{1,2}వ/,ordinal:"%dవ",meridiemParse:/రాత్రి|ఉదయం|మధ్యాహ్నం|సాయంత్రం/,meridiemHour:function(e,a){return 12===e&&(e=0),"రాత్రి"===a?e<4?e:e+12:"ఉదయం"===a?e:"మధ్యాహ్నం"===a?e>=10?e:e+12:"సాయంత్రం"===a?e+12:void 0},meridiem:function(e,a,t){return e<4?"రాత్రి":e<10?"ఉదయం":e<17?"మధ్యాహ్నం":e<20?"సాయంత్రం":"రాత్రి"},week:{dow:0,doy:6}})}(t(5093))},8861(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("tet",{months:"Janeiru_Fevereiru_Marsu_Abril_Maiu_Juñu_Jullu_Agustu_Setembru_Outubru_Novembru_Dezembru".split("_"),monthsShort:"Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez".split("_"),weekdays:"Domingu_Segunda_Tersa_Kuarta_Kinta_Sesta_Sabadu".split("_"),weekdaysShort:"Dom_Seg_Ters_Kua_Kint_Sest_Sab".split("_"),weekdaysMin:"Do_Seg_Te_Ku_Ki_Ses_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Ohin iha] LT",nextDay:"[Aban iha] LT",nextWeek:"dddd [iha] LT",lastDay:"[Horiseik iha] LT",lastWeek:"dddd [semana kotuk] [iha] LT",sameElse:"L"},relativeTime:{future:"iha %s",past:"%s liuba",s:"segundu balun",ss:"segundu %d",m:"minutu ida",mm:"minutu %d",h:"oras ida",hh:"oras %d",d:"loron ida",dd:"loron %d",M:"fulan ida",MM:"fulan %d",y:"tinan ida",yy:"tinan %d"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")},week:{dow:1,doy:4}})}(t(5093))},6571:function(e,a,t){!function(e){"use strict"; +e.defineLocale("tet",{months:"Janeiru_Fevereiru_Marsu_Abril_Maiu_Juñu_Jullu_Agustu_Setembru_Outubru_Novembru_Dezembru".split("_"),monthsShort:"Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez".split("_"),weekdays:"Domingu_Segunda_Tersa_Kuarta_Kinta_Sesta_Sabadu".split("_"),weekdaysShort:"Dom_Seg_Ters_Kua_Kint_Sest_Sab".split("_"),weekdaysMin:"Do_Seg_Te_Ku_Ki_Ses_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Ohin iha] LT",nextDay:"[Aban iha] LT",nextWeek:"dddd [iha] LT",lastDay:"[Horiseik iha] LT",lastWeek:"dddd [semana kotuk] [iha] LT",sameElse:"L"},relativeTime:{future:"iha %s",past:"%s liuba",s:"segundu balun",ss:"segundu %d",m:"minutu ida",mm:"minutu %d",h:"oras ida",hh:"oras %d",d:"loron ida",dd:"loron %d",M:"fulan ida",MM:"fulan %d",y:"tinan ida",yy:"tinan %d"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")},week:{dow:1,doy:4}})}(t(5093))},6571(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={0:"-ум",1:"-ум",2:"-юм",3:"-юм",4:"-ум",5:"-ум",6:"-ум",7:"-ум",8:"-ум",9:"-ум",10:"-ум",12:"-ум",13:"-ум",20:"-ум",30:"-юм",40:"-ум",50:"-ум",60:"-ум",70:"-ум",80:"-ум",90:"-ум",100:"-ум"};e.defineLocale("tg",{months:{format:"январи_феврали_марти_апрели_майи_июни_июли_августи_сентябри_октябри_ноябри_декабри".split("_"),standalone:"январ_феврал_март_апрел_май_июн_июл_август_сентябр_октябр_ноябр_декабр".split("_")},monthsShort:"янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек".split("_"),weekdays:"якшанбе_душанбе_сешанбе_чоршанбе_панҷшанбе_ҷумъа_шанбе".split("_"),weekdaysShort:"яшб_дшб_сшб_чшб_пшб_ҷум_шнб".split("_"),weekdaysMin:"яш_дш_сш_чш_пш_ҷм_шб".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Имрӯз соати] LT",nextDay:"[Фардо соати] LT",lastDay:"[Дирӯз соати] LT",nextWeek:"dddd[и] [ҳафтаи оянда соати] LT",lastWeek:"dddd[и] [ҳафтаи гузашта соати] LT",sameElse:"L"},relativeTime:{future:"баъди %s",past:"%s пеш",s:"якчанд сония",m:"як дақиқа",mm:"%d дақиқа",h:"як соат",hh:"%d соат",d:"як рӯз",dd:"%d рӯз",M:"як моҳ",MM:"%d моҳ",y:"як сол",yy:"%d сол"},meridiemParse:/шаб|субҳ|рӯз|бегоҳ/,meridiemHour:function(e,a){return 12===e&&(e=0),"шаб"===a?e<4?e:e+12:"субҳ"===a?e:"рӯз"===a?e>=11?e:e+12:"бегоҳ"===a?e+12:void 0},meridiem:function(e,a,t){return e<4?"шаб":e<11?"субҳ":e<16?"рӯз":e<19?"бегоҳ":"шаб"},dayOfMonthOrdinalParse:/\d{1,2}-(ум|юм)/,ordinal:function(e){var t=e%10,s=e>=100?100:null;return e+(a[e]||a[t]||a[s])},week:{dow:1,doy:7}})}(t(5093))},5802:function(e,a,t){!function(e){"use strict"; +var a={0:"-ум",1:"-ум",2:"-юм",3:"-юм",4:"-ум",5:"-ум",6:"-ум",7:"-ум",8:"-ум",9:"-ум",10:"-ум",12:"-ум",13:"-ум",20:"-ум",30:"-юм",40:"-ум",50:"-ум",60:"-ум",70:"-ум",80:"-ум",90:"-ум",100:"-ум"};e.defineLocale("tg",{months:{format:"январи_феврали_марти_апрели_майи_июни_июли_августи_сентябри_октябри_ноябри_декабри".split("_"),standalone:"январ_феврал_март_апрел_май_июн_июл_август_сентябр_октябр_ноябр_декабр".split("_")},monthsShort:"янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек".split("_"),weekdays:"якшанбе_душанбе_сешанбе_чоршанбе_панҷшанбе_ҷумъа_шанбе".split("_"),weekdaysShort:"яшб_дшб_сшб_чшб_пшб_ҷум_шнб".split("_"),weekdaysMin:"яш_дш_сш_чш_пш_ҷм_шб".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Имрӯз соати] LT",nextDay:"[Фардо соати] LT",lastDay:"[Дирӯз соати] LT",nextWeek:"dddd[и] [ҳафтаи оянда соати] LT",lastWeek:"dddd[и] [ҳафтаи гузашта соати] LT",sameElse:"L"},relativeTime:{future:"баъди %s",past:"%s пеш",s:"якчанд сония",m:"як дақиқа",mm:"%d дақиқа",h:"як соат",hh:"%d соат",d:"як рӯз",dd:"%d рӯз",M:"як моҳ",MM:"%d моҳ",y:"як сол",yy:"%d сол"},meridiemParse:/шаб|субҳ|рӯз|бегоҳ/,meridiemHour:function(e,a){return 12===e&&(e=0),"шаб"===a?e<4?e:e+12:"субҳ"===a?e:"рӯз"===a?e>=11?e:e+12:"бегоҳ"===a?e+12:void 0},meridiem:function(e,a,t){return e<4?"шаб":e<11?"субҳ":e<16?"рӯз":e<19?"бегоҳ":"шаб"},dayOfMonthOrdinalParse:/\d{1,2}-(ум|юм)/,ordinal:function(e){var t=e%10,s=e>=100?100:null;return e+(a[e]||a[t]||a[s])},week:{dow:1,doy:7}})}(t(5093))},5802(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("th",{months:"มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม".split("_"),monthsShort:"ม.ค._ก.พ._มี.ค._เม.ย._พ.ค._มิ.ย._ก.ค._ส.ค._ก.ย._ต.ค._พ.ย._ธ.ค.".split("_"),monthsParseExact:!0,weekdays:"อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์".split("_"),weekdaysShort:"อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัส_ศุกร์_เสาร์".split("_"),weekdaysMin:"อา._จ._อ._พ._พฤ._ศ._ส.".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY เวลา H:mm",LLLL:"วันddddที่ D MMMM YYYY เวลา H:mm"},meridiemParse:/ก่อนเที่ยง|หลังเที่ยง/,isPM:function(e){return"หลังเที่ยง"===e},meridiem:function(e,a,t){return e<12?"ก่อนเที่ยง":"หลังเที่ยง"},calendar:{sameDay:"[วันนี้ เวลา] LT",nextDay:"[พรุ่งนี้ เวลา] LT",nextWeek:"dddd[หน้า เวลา] LT",lastDay:"[เมื่อวานนี้ เวลา] LT",lastWeek:"[วัน]dddd[ที่แล้ว เวลา] LT",sameElse:"L"},relativeTime:{future:"อีก %s",past:"%sที่แล้ว",s:"ไม่กี่วินาที",ss:"%d วินาที",m:"1 นาที",mm:"%d นาที",h:"1 ชั่วโมง",hh:"%d ชั่วโมง",d:"1 วัน",dd:"%d วัน",w:"1 สัปดาห์",ww:"%d สัปดาห์",M:"1 เดือน",MM:"%d เดือน",y:"1 ปี",yy:"%d ปี"}})}(t(5093))},9527:function(e,a,t){!function(e){"use strict"; +e.defineLocale("th",{months:"มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม".split("_"),monthsShort:"ม.ค._ก.พ._มี.ค._เม.ย._พ.ค._มิ.ย._ก.ค._ส.ค._ก.ย._ต.ค._พ.ย._ธ.ค.".split("_"),monthsParseExact:!0,weekdays:"อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์".split("_"),weekdaysShort:"อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัส_ศุกร์_เสาร์".split("_"),weekdaysMin:"อา._จ._อ._พ._พฤ._ศ._ส.".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY เวลา H:mm",LLLL:"วันddddที่ D MMMM YYYY เวลา H:mm"},meridiemParse:/ก่อนเที่ยง|หลังเที่ยง/,isPM:function(e){return"หลังเที่ยง"===e},meridiem:function(e,a,t){return e<12?"ก่อนเที่ยง":"หลังเที่ยง"},calendar:{sameDay:"[วันนี้ เวลา] LT",nextDay:"[พรุ่งนี้ เวลา] LT",nextWeek:"dddd[หน้า เวลา] LT",lastDay:"[เมื่อวานนี้ เวลา] LT",lastWeek:"[วัน]dddd[ที่แล้ว เวลา] LT",sameElse:"L"},relativeTime:{future:"อีก %s",past:"%sที่แล้ว",s:"ไม่กี่วินาที",ss:"%d วินาที",m:"1 นาที",mm:"%d นาที",h:"1 ชั่วโมง",hh:"%d ชั่วโมง",d:"1 วัน",dd:"%d วัน",w:"1 สัปดาห์",ww:"%d สัปดาห์",M:"1 เดือน",MM:"%d เดือน",y:"1 ปี",yy:"%d ปี"}})}(t(5093))},9527(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"'inji",5:"'inji",8:"'inji",70:"'inji",80:"'inji",2:"'nji",7:"'nji",20:"'nji",50:"'nji",3:"'ünji",4:"'ünji",100:"'ünji",6:"'njy",9:"'unjy",10:"'unjy",30:"'unjy",60:"'ynjy",90:"'ynjy"};e.defineLocale("tk",{months:"Ýanwar_Fewral_Mart_Aprel_Maý_Iýun_Iýul_Awgust_Sentýabr_Oktýabr_Noýabr_Dekabr".split("_"),monthsShort:"Ýan_Few_Mar_Apr_Maý_Iýn_Iýl_Awg_Sen_Okt_Noý_Dek".split("_"),weekdays:"Ýekşenbe_Duşenbe_Sişenbe_Çarşenbe_Penşenbe_Anna_Şenbe".split("_"),weekdaysShort:"Ýek_Duş_Siş_Çar_Pen_Ann_Şen".split("_"),weekdaysMin:"Ýk_Dş_Sş_Çr_Pn_An_Şn".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bugün sagat] LT",nextDay:"[ertir sagat] LT",nextWeek:"[indiki] dddd [sagat] LT",lastDay:"[düýn] LT",lastWeek:"[geçen] dddd [sagat] LT",sameElse:"L"},relativeTime:{future:"%s soň",past:"%s öň",s:"birnäçe sekunt",m:"bir minut",mm:"%d minut",h:"bir sagat",hh:"%d sagat",d:"bir gün",dd:"%d gün",M:"bir aý",MM:"%d aý",y:"bir ýyl",yy:"%d ýyl"},ordinal:function(e,t){switch(t){case"d":case"D":case"Do":case"DD":return e;default:if(0===e)return e+"'unjy";var s=e%10,n=e%100-s,r=e>=100?100:null;return e+(a[s]||a[n]||a[r])}},week:{dow:1,doy:7}})}(t(5093))},9231:function(e,a,t){!function(e){"use strict"; +var a={1:"'inji",5:"'inji",8:"'inji",70:"'inji",80:"'inji",2:"'nji",7:"'nji",20:"'nji",50:"'nji",3:"'ünji",4:"'ünji",100:"'ünji",6:"'njy",9:"'unjy",10:"'unjy",30:"'unjy",60:"'ynjy",90:"'ynjy"};e.defineLocale("tk",{months:"Ýanwar_Fewral_Mart_Aprel_Maý_Iýun_Iýul_Awgust_Sentýabr_Oktýabr_Noýabr_Dekabr".split("_"),monthsShort:"Ýan_Few_Mar_Apr_Maý_Iýn_Iýl_Awg_Sen_Okt_Noý_Dek".split("_"),weekdays:"Ýekşenbe_Duşenbe_Sişenbe_Çarşenbe_Penşenbe_Anna_Şenbe".split("_"),weekdaysShort:"Ýek_Duş_Siş_Çar_Pen_Ann_Şen".split("_"),weekdaysMin:"Ýk_Dş_Sş_Çr_Pn_An_Şn".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bugün sagat] LT",nextDay:"[ertir sagat] LT",nextWeek:"[indiki] dddd [sagat] LT",lastDay:"[düýn] LT",lastWeek:"[geçen] dddd [sagat] LT",sameElse:"L"},relativeTime:{future:"%s soň",past:"%s öň",s:"birnäçe sekunt",m:"bir minut",mm:"%d minut",h:"bir sagat",hh:"%d sagat",d:"bir gün",dd:"%d gün",M:"bir aý",MM:"%d aý",y:"bir ýyl",yy:"%d ýyl"},ordinal:function(e,t){switch(t){case"d":case"D":case"Do":case"DD":return e;default:if(0===e)return e+"'unjy";var s=e%10,n=e%100-s,r=e>=100?100:null;return e+(a[s]||a[n]||a[r])}},week:{dow:1,doy:7}})}(t(5093))},9231(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("tl-ph",{months:"Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre".split("_"),monthsShort:"Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis".split("_"),weekdays:"Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado".split("_"),weekdaysShort:"Lin_Lun_Mar_Miy_Huw_Biy_Sab".split("_"),weekdaysMin:"Li_Lu_Ma_Mi_Hu_Bi_Sab".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"MM/D/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY HH:mm",LLLL:"dddd, MMMM DD, YYYY HH:mm"},calendar:{sameDay:"LT [ngayong araw]",nextDay:"[Bukas ng] LT",nextWeek:"LT [sa susunod na] dddd",lastDay:"LT [kahapon]",lastWeek:"LT [noong nakaraang] dddd",sameElse:"L"},relativeTime:{future:"sa loob ng %s",past:"%s ang nakalipas",s:"ilang segundo",ss:"%d segundo",m:"isang minuto",mm:"%d minuto",h:"isang oras",hh:"%d oras",d:"isang araw",dd:"%d araw",M:"isang buwan",MM:"%d buwan",y:"isang taon",yy:"%d taon"},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:function(e){return e},week:{dow:1,doy:4}})}(t(5093))},1052:function(e,a,t){!function(e){"use strict"; +e.defineLocale("tl-ph",{months:"Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre".split("_"),monthsShort:"Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis".split("_"),weekdays:"Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado".split("_"),weekdaysShort:"Lin_Lun_Mar_Miy_Huw_Biy_Sab".split("_"),weekdaysMin:"Li_Lu_Ma_Mi_Hu_Bi_Sab".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"MM/D/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY HH:mm",LLLL:"dddd, MMMM DD, YYYY HH:mm"},calendar:{sameDay:"LT [ngayong araw]",nextDay:"[Bukas ng] LT",nextWeek:"LT [sa susunod na] dddd",lastDay:"LT [kahapon]",lastWeek:"LT [noong nakaraang] dddd",sameElse:"L"},relativeTime:{future:"sa loob ng %s",past:"%s ang nakalipas",s:"ilang segundo",ss:"%d segundo",m:"isang minuto",mm:"%d minuto",h:"isang oras",hh:"%d oras",d:"isang araw",dd:"%d araw",M:"isang buwan",MM:"%d buwan",y:"isang taon",yy:"%d taon"},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:function(e){return e},week:{dow:1,doy:4}})}(t(5093))},1052(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a="pagh_wa’_cha’_wej_loS_vagh_jav_Soch_chorgh_Hut".split("_");function t(e){var a=e;return a=-1!==e.indexOf("jaj")?a.slice(0,-3)+"leS":-1!==e.indexOf("jar")?a.slice(0,-3)+"waQ":-1!==e.indexOf("DIS")?a.slice(0,-3)+"nem":a+" pIq"}function s(e){var a=e;return a=-1!==e.indexOf("jaj")?a.slice(0,-3)+"Hu’":-1!==e.indexOf("jar")?a.slice(0,-3)+"wen":-1!==e.indexOf("DIS")?a.slice(0,-3)+"ben":a+" ret"}function n(e,a,t,s){var n=r(e);switch(t){case"ss":return n+" lup";case"mm":return n+" tup";case"hh":return n+" rep";case"dd":return n+" jaj";case"MM":return n+" jar";case"yy":return n+" DIS"}}function r(e){var t=Math.floor(e%1e3/100),s=Math.floor(e%100/10),n=e%10,r="";return t>0&&(r+=a[t]+"vatlh"),s>0&&(r+=(""!==r?" ":"")+a[s]+"maH"),n>0&&(r+=(""!==r?" ":"")+a[n]),""===r?"pagh":r}e.defineLocale("tlh",{months:"tera’ jar wa’_tera’ jar cha’_tera’ jar wej_tera’ jar loS_tera’ jar vagh_tera’ jar jav_tera’ jar Soch_tera’ jar chorgh_tera’ jar Hut_tera’ jar wa’maH_tera’ jar wa’maH wa’_tera’ jar wa’maH cha’".split("_"),monthsShort:"jar wa’_jar cha’_jar wej_jar loS_jar vagh_jar jav_jar Soch_jar chorgh_jar Hut_jar wa’maH_jar wa’maH wa’_jar wa’maH cha’".split("_"),monthsParseExact:!0,weekdays:"lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"),weekdaysShort:"lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"),weekdaysMin:"lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[DaHjaj] LT",nextDay:"[wa’leS] LT",nextWeek:"LLL",lastDay:"[wa’Hu’] LT",lastWeek:"LLL",sameElse:"L"},relativeTime:{future:t,past:s,s:"puS lup",ss:n,m:"wa’ tup",mm:n,h:"wa’ rep",hh:n,d:"wa’ jaj",dd:n,M:"wa’ jar",MM:n,y:"wa’ DIS",yy:n},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},5096:function(e,a,t){!function(e){"use strict"; +var a="pagh_wa’_cha’_wej_loS_vagh_jav_Soch_chorgh_Hut".split("_");function t(e){var a=e;return a=-1!==e.indexOf("jaj")?a.slice(0,-3)+"leS":-1!==e.indexOf("jar")?a.slice(0,-3)+"waQ":-1!==e.indexOf("DIS")?a.slice(0,-3)+"nem":a+" pIq"}function s(e){var a=e;return a=-1!==e.indexOf("jaj")?a.slice(0,-3)+"Hu’":-1!==e.indexOf("jar")?a.slice(0,-3)+"wen":-1!==e.indexOf("DIS")?a.slice(0,-3)+"ben":a+" ret"}function n(e,a,t,s){var n=r(e);switch(t){case"ss":return n+" lup";case"mm":return n+" tup";case"hh":return n+" rep";case"dd":return n+" jaj";case"MM":return n+" jar";case"yy":return n+" DIS"}}function r(e){var t=Math.floor(e%1e3/100),s=Math.floor(e%100/10),n=e%10,r="";return t>0&&(r+=a[t]+"vatlh"),s>0&&(r+=(""!==r?" ":"")+a[s]+"maH"),n>0&&(r+=(""!==r?" ":"")+a[n]),""===r?"pagh":r}e.defineLocale("tlh",{months:"tera’ jar wa’_tera’ jar cha’_tera’ jar wej_tera’ jar loS_tera’ jar vagh_tera’ jar jav_tera’ jar Soch_tera’ jar chorgh_tera’ jar Hut_tera’ jar wa’maH_tera’ jar wa’maH wa’_tera’ jar wa’maH cha’".split("_"),monthsShort:"jar wa’_jar cha’_jar wej_jar loS_jar vagh_jar jav_jar Soch_jar chorgh_jar Hut_jar wa’maH_jar wa’maH wa’_jar wa’maH cha’".split("_"),monthsParseExact:!0,weekdays:"lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"),weekdaysShort:"lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"),weekdaysMin:"lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[DaHjaj] LT",nextDay:"[wa’leS] LT",nextWeek:"LLL",lastDay:"[wa’Hu’] LT",lastWeek:"LLL",sameElse:"L"},relativeTime:{future:t,past:s,s:"puS lup",ss:n,m:"wa’ tup",mm:n,h:"wa’ rep",hh:n,d:"wa’ jaj",dd:n,M:"wa’ jar",MM:n,y:"wa’ DIS",yy:n},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},5096(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a={1:"'inci",5:"'inci",8:"'inci",70:"'inci",80:"'inci",2:"'nci",7:"'nci",20:"'nci",50:"'nci",3:"'üncü",4:"'üncü",100:"'üncü",6:"'ncı",9:"'uncu",10:"'uncu",30:"'uncu",60:"'ıncı",90:"'ıncı"};e.defineLocale("tr",{months:"Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık".split("_"),monthsShort:"Oca_Şub_Mar_Nis_May_Haz_Tem_Ağu_Eyl_Eki_Kas_Ara".split("_"),weekdays:"Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi".split("_"),weekdaysShort:"Paz_Pzt_Sal_Çar_Per_Cum_Cmt".split("_"),weekdaysMin:"Pz_Pt_Sa_Ça_Pe_Cu_Ct".split("_"),meridiem:function(e,a,t){return e<12?t?"öö":"ÖÖ":t?"ös":"ÖS"},meridiemParse:/öö|ÖÖ|ös|ÖS/,isPM:function(e){return"ös"===e||"ÖS"===e},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bugün saat] LT",nextDay:"[yarın saat] LT",nextWeek:"[gelecek] dddd [saat] LT",lastDay:"[dün] LT",lastWeek:"[geçen] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s sonra",past:"%s önce",s:"birkaç saniye",ss:"%d saniye",m:"bir dakika",mm:"%d dakika",h:"bir saat",hh:"%d saat",d:"bir gün",dd:"%d gün",w:"bir hafta",ww:"%d hafta",M:"bir ay",MM:"%d ay",y:"bir yıl",yy:"%d yıl"},ordinal:function(e,t){switch(t){case"d":case"D":case"Do":case"DD":return e;default:if(0===e)return e+"'ıncı";var s=e%10,n=e%100-s,r=e>=100?100:null;return e+(a[s]||a[n]||a[r])}},week:{dow:1,doy:7}})}(t(5093))},9846:function(e,a,t){!function(e){"use strict"; +var a={1:"'inci",5:"'inci",8:"'inci",70:"'inci",80:"'inci",2:"'nci",7:"'nci",20:"'nci",50:"'nci",3:"'üncü",4:"'üncü",100:"'üncü",6:"'ncı",9:"'uncu",10:"'uncu",30:"'uncu",60:"'ıncı",90:"'ıncı"};e.defineLocale("tr",{months:"Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık".split("_"),monthsShort:"Oca_Şub_Mar_Nis_May_Haz_Tem_Ağu_Eyl_Eki_Kas_Ara".split("_"),weekdays:"Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi".split("_"),weekdaysShort:"Paz_Pzt_Sal_Çar_Per_Cum_Cmt".split("_"),weekdaysMin:"Pz_Pt_Sa_Ça_Pe_Cu_Ct".split("_"),meridiem:function(e,a,t){return e<12?t?"öö":"ÖÖ":t?"ös":"ÖS"},meridiemParse:/öö|ÖÖ|ös|ÖS/,isPM:function(e){return"ös"===e||"ÖS"===e},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bugün saat] LT",nextDay:"[yarın saat] LT",nextWeek:"[gelecek] dddd [saat] LT",lastDay:"[dün] LT",lastWeek:"[geçen] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s sonra",past:"%s önce",s:"birkaç saniye",ss:"%d saniye",m:"bir dakika",mm:"%d dakika",h:"bir saat",hh:"%d saat",d:"bir gün",dd:"%d gün",w:"bir hafta",ww:"%d hafta",M:"bir ay",MM:"%d ay",y:"bir yıl",yy:"%d yıl"},ordinal:function(e,t){switch(t){case"d":case"D":case"Do":case"DD":return e;default:if(0===e)return e+"'ıncı";var s=e%10,n=e%100-s,r=e>=100?100:null;return e+(a[s]||a[n]||a[r])}},week:{dow:1,doy:7}})}(t(5093))},9846(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e,a,t,s){var n={s:["viensas secunds","'iensas secunds"],ss:[e+" secunds",e+" secunds"],m:["'n míut","'iens míut"],mm:[e+" míuts",e+" míuts"],h:["'n þora","'iensa þora"],hh:[e+" þoras",e+" þoras"],d:["'n ziua","'iensa ziua"],dd:[e+" ziuas",e+" ziuas"],M:["'n mes","'iens mes"],MM:[e+" mesen",e+" mesen"],y:["'n ar","'iens ar"],yy:[e+" ars",e+" ars"]};return s||a?n[t][0]:n[t][1]}e.defineLocale("tzl",{months:"Januar_Fevraglh_Març_Avrïu_Mai_Gün_Julia_Guscht_Setemvar_Listopäts_Noemvar_Zecemvar".split("_"),monthsShort:"Jan_Fev_Mar_Avr_Mai_Gün_Jul_Gus_Set_Lis_Noe_Zec".split("_"),weekdays:"Súladi_Lúneçi_Maitzi_Márcuri_Xhúadi_Viénerçi_Sáturi".split("_"),weekdaysShort:"Súl_Lún_Mai_Már_Xhú_Vié_Sát".split("_"),weekdaysMin:"Sú_Lú_Ma_Má_Xh_Vi_Sá".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD.MM.YYYY",LL:"D. MMMM [dallas] YYYY",LLL:"D. MMMM [dallas] YYYY HH.mm",LLLL:"dddd, [li] D. MMMM [dallas] YYYY HH.mm"},meridiemParse:/d\'o|d\'a/i,isPM:function(e){return"d'o"===e.toLowerCase()},meridiem:function(e,a,t){return e>11?t?"d'o":"D'O":t?"d'a":"D'A"},calendar:{sameDay:"[oxhi à] LT",nextDay:"[demà à] LT",nextWeek:"dddd [à] LT",lastDay:"[ieiri à] LT",lastWeek:"[sür el] dddd [lasteu à] LT",sameElse:"L"},relativeTime:{future:"osprei %s",past:"ja%s",s:a,ss:a,m:a,mm:a,h:a,hh:a,d:a,dd:a,M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},7711:function(e,a,t){!function(e){"use strict"; +function a(e,a,t,s){var n={s:["viensas secunds","'iensas secunds"],ss:[e+" secunds",e+" secunds"],m:["'n míut","'iens míut"],mm:[e+" míuts",e+" míuts"],h:["'n þora","'iensa þora"],hh:[e+" þoras",e+" þoras"],d:["'n ziua","'iensa ziua"],dd:[e+" ziuas",e+" ziuas"],M:["'n mes","'iens mes"],MM:[e+" mesen",e+" mesen"],y:["'n ar","'iens ar"],yy:[e+" ars",e+" ars"]};return s||a?n[t][0]:n[t][1]}e.defineLocale("tzl",{months:"Januar_Fevraglh_Març_Avrïu_Mai_Gün_Julia_Guscht_Setemvar_Listopäts_Noemvar_Zecemvar".split("_"),monthsShort:"Jan_Fev_Mar_Avr_Mai_Gün_Jul_Gus_Set_Lis_Noe_Zec".split("_"),weekdays:"Súladi_Lúneçi_Maitzi_Márcuri_Xhúadi_Viénerçi_Sáturi".split("_"),weekdaysShort:"Súl_Lún_Mai_Már_Xhú_Vié_Sát".split("_"),weekdaysMin:"Sú_Lú_Ma_Má_Xh_Vi_Sá".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD.MM.YYYY",LL:"D. MMMM [dallas] YYYY",LLL:"D. MMMM [dallas] YYYY HH.mm",LLLL:"dddd, [li] D. MMMM [dallas] YYYY HH.mm"},meridiemParse:/d\'o|d\'a/i,isPM:function(e){return"d'o"===e.toLowerCase()},meridiem:function(e,a,t){return e>11?t?"d'o":"D'O":t?"d'a":"D'A"},calendar:{sameDay:"[oxhi à] LT",nextDay:"[demà à] LT",nextWeek:"dddd [à] LT",lastDay:"[ieiri à] LT",lastWeek:"[sür el] dddd [lasteu à] LT",sameElse:"L"},relativeTime:{future:"osprei %s",past:"ja%s",s:a,ss:a,m:a,mm:a,h:a,hh:a,d:a,dd:a,M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(t(5093))},7711(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("tzm-latn",{months:"innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir".split("_"),monthsShort:"innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir".split("_"),weekdays:"asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"),weekdaysShort:"asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"),weekdaysMin:"asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[asdkh g] LT",nextDay:"[aska g] LT",nextWeek:"dddd [g] LT",lastDay:"[assant g] LT",lastWeek:"dddd [g] LT",sameElse:"L"},relativeTime:{future:"dadkh s yan %s",past:"yan %s",s:"imik",ss:"%d imik",m:"minuḍ",mm:"%d minuḍ",h:"saɛa",hh:"%d tassaɛin",d:"ass",dd:"%d ossan",M:"ayowr",MM:"%d iyyirn",y:"asgas",yy:"%d isgasn"},week:{dow:6,doy:12}})}(t(5093))},1765:function(e,a,t){!function(e){"use strict"; +e.defineLocale("tzm-latn",{months:"innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir".split("_"),monthsShort:"innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir".split("_"),weekdays:"asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"),weekdaysShort:"asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"),weekdaysMin:"asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[asdkh g] LT",nextDay:"[aska g] LT",nextWeek:"dddd [g] LT",lastDay:"[assant g] LT",lastWeek:"dddd [g] LT",sameElse:"L"},relativeTime:{future:"dadkh s yan %s",past:"yan %s",s:"imik",ss:"%d imik",m:"minuḍ",mm:"%d minuḍ",h:"saɛa",hh:"%d tassaɛin",d:"ass",dd:"%d ossan",M:"ayowr",MM:"%d iyyirn",y:"asgas",yy:"%d isgasn"},week:{dow:6,doy:12}})}(t(5093))},1765(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("tzm",{months:"ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ".split("_"),monthsShort:"ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ".split("_"),weekdays:"ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"),weekdaysShort:"ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"),weekdaysMin:"ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[ⴰⵙⴷⵅ ⴴ] LT",nextDay:"[ⴰⵙⴽⴰ ⴴ] LT",nextWeek:"dddd [ⴴ] LT",lastDay:"[ⴰⵚⴰⵏⵜ ⴴ] LT",lastWeek:"dddd [ⴴ] LT",sameElse:"L"},relativeTime:{future:"ⴷⴰⴷⵅ ⵙ ⵢⴰⵏ %s",past:"ⵢⴰⵏ %s",s:"ⵉⵎⵉⴽ",ss:"%d ⵉⵎⵉⴽ",m:"ⵎⵉⵏⵓⴺ",mm:"%d ⵎⵉⵏⵓⴺ",h:"ⵙⴰⵄⴰ",hh:"%d ⵜⴰⵙⵙⴰⵄⵉⵏ",d:"ⴰⵙⵙ",dd:"%d oⵙⵙⴰⵏ",M:"ⴰⵢoⵓⵔ",MM:"%d ⵉⵢⵢⵉⵔⵏ",y:"ⴰⵙⴳⴰⵙ",yy:"%d ⵉⵙⴳⴰⵙⵏ"},week:{dow:6,doy:12}})}(t(5093))},8414:function(e,a,t){!function(e){"use strict"; +e.defineLocale("tzm",{months:"ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ".split("_"),monthsShort:"ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ".split("_"),weekdays:"ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"),weekdaysShort:"ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"),weekdaysMin:"ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[ⴰⵙⴷⵅ ⴴ] LT",nextDay:"[ⴰⵙⴽⴰ ⴴ] LT",nextWeek:"dddd [ⴴ] LT",lastDay:"[ⴰⵚⴰⵏⵜ ⴴ] LT",lastWeek:"dddd [ⴴ] LT",sameElse:"L"},relativeTime:{future:"ⴷⴰⴷⵅ ⵙ ⵢⴰⵏ %s",past:"ⵢⴰⵏ %s",s:"ⵉⵎⵉⴽ",ss:"%d ⵉⵎⵉⴽ",m:"ⵎⵉⵏⵓⴺ",mm:"%d ⵎⵉⵏⵓⴺ",h:"ⵙⴰⵄⴰ",hh:"%d ⵜⴰⵙⵙⴰⵄⵉⵏ",d:"ⴰⵙⵙ",dd:"%d oⵙⵙⴰⵏ",M:"ⴰⵢoⵓⵔ",MM:"%d ⵉⵢⵢⵉⵔⵏ",y:"ⴰⵙⴳⴰⵙ",yy:"%d ⵉⵙⴳⴰⵙⵏ"},week:{dow:6,doy:12}})}(t(5093))},8414(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("ug-cn",{months:"يانۋار_فېۋرال_مارت_ئاپرېل_ماي_ئىيۇن_ئىيۇل_ئاۋغۇست_سېنتەبىر_ئۆكتەبىر_نويابىر_دېكابىر".split("_"),monthsShort:"يانۋار_فېۋرال_مارت_ئاپرېل_ماي_ئىيۇن_ئىيۇل_ئاۋغۇست_سېنتەبىر_ئۆكتەبىر_نويابىر_دېكابىر".split("_"),weekdays:"يەكشەنبە_دۈشەنبە_سەيشەنبە_چارشەنبە_پەيشەنبە_جۈمە_شەنبە".split("_"),weekdaysShort:"يە_دۈ_سە_چا_پە_جۈ_شە".split("_"),weekdaysMin:"يە_دۈ_سە_چا_پە_جۈ_شە".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY-يىلىM-ئاينىڭD-كۈنى",LLL:"YYYY-يىلىM-ئاينىڭD-كۈنى، HH:mm",LLLL:"dddd، YYYY-يىلىM-ئاينىڭD-كۈنى، HH:mm"},meridiemParse:/يېرىم كېچە|سەھەر|چۈشتىن بۇرۇن|چۈش|چۈشتىن كېيىن|كەچ/,meridiemHour:function(e,a){return 12===e&&(e=0),"يېرىم كېچە"===a||"سەھەر"===a||"چۈشتىن بۇرۇن"===a?e:"چۈشتىن كېيىن"===a||"كەچ"===a?e+12:e>=11?e:e+12},meridiem:function(e,a,t){var s=100*e+a;return s<600?"يېرىم كېچە":s<900?"سەھەر":s<1130?"چۈشتىن بۇرۇن":s<1230?"چۈش":s<1800?"چۈشتىن كېيىن":"كەچ"},calendar:{sameDay:"[بۈگۈن سائەت] LT",nextDay:"[ئەتە سائەت] LT",nextWeek:"[كېلەركى] dddd [سائەت] LT",lastDay:"[تۆنۈگۈن] LT",lastWeek:"[ئالدىنقى] dddd [سائەت] LT",sameElse:"L"},relativeTime:{future:"%s كېيىن",past:"%s بۇرۇن",s:"نەچچە سېكونت",ss:"%d سېكونت",m:"بىر مىنۇت",mm:"%d مىنۇت",h:"بىر سائەت",hh:"%d سائەت",d:"بىر كۈن",dd:"%d كۈن",M:"بىر ئاي",MM:"%d ئاي",y:"بىر يىل",yy:"%d يىل"},dayOfMonthOrdinalParse:/\d{1,2}(-كۈنى|-ئاي|-ھەپتە)/,ordinal:function(e,a){switch(a){case"d":case"D":case"DDD":return e+"-كۈنى";case"w":case"W":return e+"-ھەپتە";default:return e}},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:1,doy:7}})}(t(5093))},6618:function(e,a,t){!function(e){"use strict"; +e.defineLocale("ug-cn",{months:"يانۋار_فېۋرال_مارت_ئاپرېل_ماي_ئىيۇن_ئىيۇل_ئاۋغۇست_سېنتەبىر_ئۆكتەبىر_نويابىر_دېكابىر".split("_"),monthsShort:"يانۋار_فېۋرال_مارت_ئاپرېل_ماي_ئىيۇن_ئىيۇل_ئاۋغۇست_سېنتەبىر_ئۆكتەبىر_نويابىر_دېكابىر".split("_"),weekdays:"يەكشەنبە_دۈشەنبە_سەيشەنبە_چارشەنبە_پەيشەنبە_جۈمە_شەنبە".split("_"),weekdaysShort:"يە_دۈ_سە_چا_پە_جۈ_شە".split("_"),weekdaysMin:"يە_دۈ_سە_چا_پە_جۈ_شە".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY-يىلىM-ئاينىڭD-كۈنى",LLL:"YYYY-يىلىM-ئاينىڭD-كۈنى، HH:mm",LLLL:"dddd، YYYY-يىلىM-ئاينىڭD-كۈنى، HH:mm"},meridiemParse:/يېرىم كېچە|سەھەر|چۈشتىن بۇرۇن|چۈش|چۈشتىن كېيىن|كەچ/,meridiemHour:function(e,a){return 12===e&&(e=0),"يېرىم كېچە"===a||"سەھەر"===a||"چۈشتىن بۇرۇن"===a?e:"چۈشتىن كېيىن"===a||"كەچ"===a?e+12:e>=11?e:e+12},meridiem:function(e,a,t){var s=100*e+a;return s<600?"يېرىم كېچە":s<900?"سەھەر":s<1130?"چۈشتىن بۇرۇن":s<1230?"چۈش":s<1800?"چۈشتىن كېيىن":"كەچ"},calendar:{sameDay:"[بۈگۈن سائەت] LT",nextDay:"[ئەتە سائەت] LT",nextWeek:"[كېلەركى] dddd [سائەت] LT",lastDay:"[تۆنۈگۈن] LT",lastWeek:"[ئالدىنقى] dddd [سائەت] LT",sameElse:"L"},relativeTime:{future:"%s كېيىن",past:"%s بۇرۇن",s:"نەچچە سېكونت",ss:"%d سېكونت",m:"بىر مىنۇت",mm:"%d مىنۇت",h:"بىر سائەت",hh:"%d سائەت",d:"بىر كۈن",dd:"%d كۈن",M:"بىر ئاي",MM:"%d ئاي",y:"بىر يىل",yy:"%d يىل"},dayOfMonthOrdinalParse:/\d{1,2}(-كۈنى|-ئاي|-ھەپتە)/,ordinal:function(e,a){switch(a){case"d":case"D":case"DDD":return e+"-كۈنى";case"w":case"W":return e+"-ھەپتە";default:return e}},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:1,doy:7}})}(t(5093))},6618(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -function a(e,a){var t=e.split("_");return a%10==1&&a%100!=11?t[0]:a%10>=2&&a%10<=4&&(a%100<10||a%100>=20)?t[1]:t[2]}function t(e,t,s){return"m"===s?t?"хвилина":"хвилину":"h"===s?t?"година":"годину":e+" "+a({ss:t?"секунда_секунди_секунд":"секунду_секунди_секунд",mm:t?"хвилина_хвилини_хвилин":"хвилину_хвилини_хвилин",hh:t?"година_години_годин":"годину_години_годин",dd:"день_дні_днів",MM:"місяць_місяці_місяців",yy:"рік_роки_років"}[s],+e)}function s(e,a){var t={nominative:"неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота".split("_"),accusative:"неділю_понеділок_вівторок_середу_четвер_п’ятницю_суботу".split("_"),genitive:"неділі_понеділка_вівторка_середи_четверга_п’ятниці_суботи".split("_")};return!0===e?t.nominative.slice(1,7).concat(t.nominative.slice(0,1)):e?t[/(\[[ВвУу]\]) ?dddd/.test(a)?"accusative":/\[?(?:минулої|наступної)? ?\] ?dddd/.test(a)?"genitive":"nominative"][e.day()]:t.nominative}function n(e){return function(){return e+"о"+(11===this.hours()?"б":"")+"] LT"}}e.defineLocale("uk",{months:{format:"січня_лютого_березня_квітня_травня_червня_липня_серпня_вересня_жовтня_листопада_грудня".split("_"),standalone:"січень_лютий_березень_квітень_травень_червень_липень_серпень_вересень_жовтень_листопад_грудень".split("_")},monthsShort:"січ_лют_бер_квіт_трав_черв_лип_серп_вер_жовт_лист_груд".split("_"),weekdays:s,weekdaysShort:"нд_пн_вт_ср_чт_пт_сб".split("_"),weekdaysMin:"нд_пн_вт_ср_чт_пт_сб".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY р.",LLL:"D MMMM YYYY р., HH:mm",LLLL:"dddd, D MMMM YYYY р., HH:mm"},calendar:{sameDay:n("[Сьогодні "),nextDay:n("[Завтра "),lastDay:n("[Вчора "),nextWeek:n("[У] dddd ["),lastWeek:function(){switch(this.day()){case 0:case 3:case 5:case 6:return n("[Минулої] dddd [").call(this);case 1:case 2:case 4:return n("[Минулого] dddd [").call(this)}},sameElse:"L"},relativeTime:{future:"за %s",past:"%s тому",s:"декілька секунд",ss:t,m:t,mm:t,h:"годину",hh:t,d:"день",dd:t,M:"місяць",MM:t,y:"рік",yy:t},meridiemParse:/ночі|ранку|дня|вечора/,isPM:function(e){return/^(дня|вечора)$/.test(e)},meridiem:function(e,a,t){return e<4?"ночі":e<12?"ранку":e<17?"дня":"вечора"},dayOfMonthOrdinalParse:/\d{1,2}-(й|го)/,ordinal:function(e,a){switch(a){case"M":case"d":case"DDD":case"w":case"W":return e+"-й";case"D":return e+"-го";default:return e}},week:{dow:1,doy:7}})}(t(5093))},158:function(e,a,t){!function(e){"use strict"; +function a(e,a){var t=e.split("_");return a%10==1&&a%100!=11?t[0]:a%10>=2&&a%10<=4&&(a%100<10||a%100>=20)?t[1]:t[2]}function t(e,t,s){return"m"===s?t?"хвилина":"хвилину":"h"===s?t?"година":"годину":e+" "+a({ss:t?"секунда_секунди_секунд":"секунду_секунди_секунд",mm:t?"хвилина_хвилини_хвилин":"хвилину_хвилини_хвилин",hh:t?"година_години_годин":"годину_години_годин",dd:"день_дні_днів",MM:"місяць_місяці_місяців",yy:"рік_роки_років"}[s],+e)}function s(e,a){var t={nominative:"неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота".split("_"),accusative:"неділю_понеділок_вівторок_середу_четвер_п’ятницю_суботу".split("_"),genitive:"неділі_понеділка_вівторка_середи_четверга_п’ятниці_суботи".split("_")};return!0===e?t.nominative.slice(1,7).concat(t.nominative.slice(0,1)):e?t[/(\[[ВвУу]\]) ?dddd/.test(a)?"accusative":/\[?(?:минулої|наступної)? ?\] ?dddd/.test(a)?"genitive":"nominative"][e.day()]:t.nominative}function n(e){return function(){return e+"о"+(11===this.hours()?"б":"")+"] LT"}}e.defineLocale("uk",{months:{format:"січня_лютого_березня_квітня_травня_червня_липня_серпня_вересня_жовтня_листопада_грудня".split("_"),standalone:"січень_лютий_березень_квітень_травень_червень_липень_серпень_вересень_жовтень_листопад_грудень".split("_")},monthsShort:"січ_лют_бер_квіт_трав_черв_лип_серп_вер_жовт_лист_груд".split("_"),weekdays:s,weekdaysShort:"нд_пн_вт_ср_чт_пт_сб".split("_"),weekdaysMin:"нд_пн_вт_ср_чт_пт_сб".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY р.",LLL:"D MMMM YYYY р., HH:mm",LLLL:"dddd, D MMMM YYYY р., HH:mm"},calendar:{sameDay:n("[Сьогодні "),nextDay:n("[Завтра "),lastDay:n("[Вчора "),nextWeek:n("[У] dddd ["),lastWeek:function(){switch(this.day()){case 0:case 3:case 5:case 6:return n("[Минулої] dddd [").call(this);case 1:case 2:case 4:return n("[Минулого] dddd [").call(this)}},sameElse:"L"},relativeTime:{future:"за %s",past:"%s тому",s:"декілька секунд",ss:t,m:t,mm:t,h:"годину",hh:t,d:"день",dd:t,M:"місяць",MM:t,y:"рік",yy:t},meridiemParse:/ночі|ранку|дня|вечора/,isPM:function(e){return/^(дня|вечора)$/.test(e)},meridiem:function(e,a,t){return e<4?"ночі":e<12?"ранку":e<17?"дня":"вечора"},dayOfMonthOrdinalParse:/\d{1,2}-(й|го)/,ordinal:function(e,a){switch(a){case"M":case"d":case"DDD":case"w":case"W":return e+"-й";case"D":return e+"-го";default:return e}},week:{dow:1,doy:7}})}(t(5093))},158(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -var a=["جنوری","فروری","مارچ","اپریل","مئی","جون","جولائی","اگست","ستمبر","اکتوبر","نومبر","دسمبر"],t=["اتوار","پیر","منگل","بدھ","جمعرات","جمعہ","ہفتہ"];e.defineLocale("ur",{months:a,monthsShort:a,weekdays:t,weekdaysShort:t,weekdaysMin:t,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd، D MMMM YYYY HH:mm"},meridiemParse:/صبح|شام/,isPM:function(e){return"شام"===e},meridiem:function(e,a,t){return e<12?"صبح":"شام"},calendar:{sameDay:"[آج بوقت] LT",nextDay:"[کل بوقت] LT",nextWeek:"dddd [بوقت] LT",lastDay:"[گذشتہ روز بوقت] LT",lastWeek:"[گذشتہ] dddd [بوقت] LT",sameElse:"L"},relativeTime:{future:"%s بعد",past:"%s قبل",s:"چند سیکنڈ",ss:"%d سیکنڈ",m:"ایک منٹ",mm:"%d منٹ",h:"ایک گھنٹہ",hh:"%d گھنٹے",d:"ایک دن",dd:"%d دن",M:"ایک ماہ",MM:"%d ماہ",y:"ایک سال",yy:"%d سال"},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:1,doy:4}})}(t(5093))},2475:function(e,a,t){!function(e){"use strict"; +var a=["جنوری","فروری","مارچ","اپریل","مئی","جون","جولائی","اگست","ستمبر","اکتوبر","نومبر","دسمبر"],t=["اتوار","پیر","منگل","بدھ","جمعرات","جمعہ","ہفتہ"];e.defineLocale("ur",{months:a,monthsShort:a,weekdays:t,weekdaysShort:t,weekdaysMin:t,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd، D MMMM YYYY HH:mm"},meridiemParse:/صبح|شام/,isPM:function(e){return"شام"===e},meridiem:function(e,a,t){return e<12?"صبح":"شام"},calendar:{sameDay:"[آج بوقت] LT",nextDay:"[کل بوقت] LT",nextWeek:"dddd [بوقت] LT",lastDay:"[گذشتہ روز بوقت] LT",lastWeek:"[گذشتہ] dddd [بوقت] LT",sameElse:"L"},relativeTime:{future:"%s بعد",past:"%s قبل",s:"چند سیکنڈ",ss:"%d سیکنڈ",m:"ایک منٹ",mm:"%d منٹ",h:"ایک گھنٹہ",hh:"%d گھنٹے",d:"ایک دن",dd:"%d دن",M:"ایک ماہ",MM:"%d ماہ",y:"ایک سال",yy:"%d سال"},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:1,doy:4}})}(t(5093))},2475(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("uz-latn",{months:"Yanvar_Fevral_Mart_Aprel_May_Iyun_Iyul_Avgust_Sentabr_Oktabr_Noyabr_Dekabr".split("_"),monthsShort:"Yan_Fev_Mar_Apr_May_Iyun_Iyul_Avg_Sen_Okt_Noy_Dek".split("_"),weekdays:"Yakshanba_Dushanba_Seshanba_Chorshanba_Payshanba_Juma_Shanba".split("_"),weekdaysShort:"Yak_Dush_Sesh_Chor_Pay_Jum_Shan".split("_"),weekdaysMin:"Ya_Du_Se_Cho_Pa_Ju_Sha".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"D MMMM YYYY, dddd HH:mm"},calendar:{sameDay:"[Bugun soat] LT [da]",nextDay:"[Ertaga] LT [da]",nextWeek:"dddd [kuni soat] LT [da]",lastDay:"[Kecha soat] LT [da]",lastWeek:"[O'tgan] dddd [kuni soat] LT [da]",sameElse:"L"},relativeTime:{future:"Yaqin %s ichida",past:"Bir necha %s oldin",s:"soniya",ss:"%d soniya",m:"bir daqiqa",mm:"%d daqiqa",h:"bir soat",hh:"%d soat",d:"bir kun",dd:"%d kun",M:"bir oy",MM:"%d oy",y:"bir yil",yy:"%d yil"},week:{dow:1,doy:7}})}(t(5093))},7609:function(e,a,t){!function(e){"use strict"; +e.defineLocale("uz-latn",{months:"Yanvar_Fevral_Mart_Aprel_May_Iyun_Iyul_Avgust_Sentabr_Oktabr_Noyabr_Dekabr".split("_"),monthsShort:"Yan_Fev_Mar_Apr_May_Iyun_Iyul_Avg_Sen_Okt_Noy_Dek".split("_"),weekdays:"Yakshanba_Dushanba_Seshanba_Chorshanba_Payshanba_Juma_Shanba".split("_"),weekdaysShort:"Yak_Dush_Sesh_Chor_Pay_Jum_Shan".split("_"),weekdaysMin:"Ya_Du_Se_Cho_Pa_Ju_Sha".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"D MMMM YYYY, dddd HH:mm"},calendar:{sameDay:"[Bugun soat] LT [da]",nextDay:"[Ertaga] LT [da]",nextWeek:"dddd [kuni soat] LT [da]",lastDay:"[Kecha soat] LT [da]",lastWeek:"[O'tgan] dddd [kuni soat] LT [da]",sameElse:"L"},relativeTime:{future:"Yaqin %s ichida",past:"Bir necha %s oldin",s:"soniya",ss:"%d soniya",m:"bir daqiqa",mm:"%d daqiqa",h:"bir soat",hh:"%d soat",d:"bir kun",dd:"%d kun",M:"bir oy",MM:"%d oy",y:"bir yil",yy:"%d yil"},week:{dow:1,doy:7}})}(t(5093))},7609(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("uz",{months:"январ_феврал_март_апрел_май_июн_июл_август_сентябр_октябр_ноябр_декабр".split("_"),monthsShort:"янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек".split("_"),weekdays:"Якшанба_Душанба_Сешанба_Чоршанба_Пайшанба_Жума_Шанба".split("_"),weekdaysShort:"Якш_Душ_Сеш_Чор_Пай_Жум_Шан".split("_"),weekdaysMin:"Як_Ду_Се_Чо_Па_Жу_Ша".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"D MMMM YYYY, dddd HH:mm"},calendar:{sameDay:"[Бугун соат] LT [да]",nextDay:"[Эртага] LT [да]",nextWeek:"dddd [куни соат] LT [да]",lastDay:"[Кеча соат] LT [да]",lastWeek:"[Утган] dddd [куни соат] LT [да]",sameElse:"L"},relativeTime:{future:"Якин %s ичида",past:"Бир неча %s олдин",s:"фурсат",ss:"%d фурсат",m:"бир дакика",mm:"%d дакика",h:"бир соат",hh:"%d соат",d:"бир кун",dd:"%d кун",M:"бир ой",MM:"%d ой",y:"бир йил",yy:"%d йил"},week:{dow:1,doy:7}})}(t(5093))},1135:function(e,a,t){!function(e){"use strict"; +e.defineLocale("uz",{months:"январ_феврал_март_апрел_май_июн_июл_август_сентябр_октябр_ноябр_декабр".split("_"),monthsShort:"янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек".split("_"),weekdays:"Якшанба_Душанба_Сешанба_Чоршанба_Пайшанба_Жума_Шанба".split("_"),weekdaysShort:"Якш_Душ_Сеш_Чор_Пай_Жум_Шан".split("_"),weekdaysMin:"Як_Ду_Се_Чо_Па_Жу_Ша".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"D MMMM YYYY, dddd HH:mm"},calendar:{sameDay:"[Бугун соат] LT [да]",nextDay:"[Эртага] LT [да]",nextWeek:"dddd [куни соат] LT [да]",lastDay:"[Кеча соат] LT [да]",lastWeek:"[Утган] dddd [куни соат] LT [да]",sameElse:"L"},relativeTime:{future:"Якин %s ичида",past:"Бир неча %s олдин",s:"фурсат",ss:"%d фурсат",m:"бир дакика",mm:"%d дакика",h:"бир соат",hh:"%d соат",d:"бир кун",dd:"%d кун",M:"бир ой",MM:"%d ой",y:"бир йил",yy:"%d йил"},week:{dow:1,doy:7}})}(t(5093))},1135(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("vi",{months:"tháng 1_tháng 2_tháng 3_tháng 4_tháng 5_tháng 6_tháng 7_tháng 8_tháng 9_tháng 10_tháng 11_tháng 12".split("_"),monthsShort:"Thg 01_Thg 02_Thg 03_Thg 04_Thg 05_Thg 06_Thg 07_Thg 08_Thg 09_Thg 10_Thg 11_Thg 12".split("_"),monthsParseExact:!0,weekdays:"chủ nhật_thứ hai_thứ ba_thứ tư_thứ năm_thứ sáu_thứ bảy".split("_"),weekdaysShort:"CN_T2_T3_T4_T5_T6_T7".split("_"),weekdaysMin:"CN_T2_T3_T4_T5_T6_T7".split("_"),weekdaysParseExact:!0,meridiemParse:/sa|ch/i,isPM:function(e){return/^ch$/i.test(e)},meridiem:function(e,a,t){return e<12?t?"sa":"SA":t?"ch":"CH"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM [năm] YYYY",LLL:"D MMMM [năm] YYYY HH:mm",LLLL:"dddd, D MMMM [năm] YYYY HH:mm",l:"DD/M/YYYY",ll:"D MMM YYYY",lll:"D MMM YYYY HH:mm",llll:"ddd, D MMM YYYY HH:mm"},calendar:{sameDay:"[Hôm nay lúc] LT",nextDay:"[Ngày mai lúc] LT",nextWeek:"dddd [tuần tới lúc] LT",lastDay:"[Hôm qua lúc] LT",lastWeek:"dddd [tuần trước lúc] LT",sameElse:"L"},relativeTime:{future:"%s tới",past:"%s trước",s:"vài giây",ss:"%d giây",m:"một phút",mm:"%d phút",h:"một giờ",hh:"%d giờ",d:"một ngày",dd:"%d ngày",w:"một tuần",ww:"%d tuần",M:"một tháng",MM:"%d tháng",y:"một năm",yy:"%d năm"},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:function(e){return e},week:{dow:1,doy:4}})}(t(5093))},4051:function(e,a,t){!function(e){"use strict"; +e.defineLocale("vi",{months:"tháng 1_tháng 2_tháng 3_tháng 4_tháng 5_tháng 6_tháng 7_tháng 8_tháng 9_tháng 10_tháng 11_tháng 12".split("_"),monthsShort:"Thg 01_Thg 02_Thg 03_Thg 04_Thg 05_Thg 06_Thg 07_Thg 08_Thg 09_Thg 10_Thg 11_Thg 12".split("_"),monthsParseExact:!0,weekdays:"chủ nhật_thứ hai_thứ ba_thứ tư_thứ năm_thứ sáu_thứ bảy".split("_"),weekdaysShort:"CN_T2_T3_T4_T5_T6_T7".split("_"),weekdaysMin:"CN_T2_T3_T4_T5_T6_T7".split("_"),weekdaysParseExact:!0,meridiemParse:/sa|ch/i,isPM:function(e){return/^ch$/i.test(e)},meridiem:function(e,a,t){return e<12?t?"sa":"SA":t?"ch":"CH"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM [năm] YYYY",LLL:"D MMMM [năm] YYYY HH:mm",LLLL:"dddd, D MMMM [năm] YYYY HH:mm",l:"DD/M/YYYY",ll:"D MMM YYYY",lll:"D MMM YYYY HH:mm",llll:"ddd, D MMM YYYY HH:mm"},calendar:{sameDay:"[Hôm nay lúc] LT",nextDay:"[Ngày mai lúc] LT",nextWeek:"dddd [tuần tới lúc] LT",lastDay:"[Hôm qua lúc] LT",lastWeek:"dddd [tuần trước lúc] LT",sameElse:"L"},relativeTime:{future:"%s tới",past:"%s trước",s:"vài giây",ss:"%d giây",m:"một phút",mm:"%d phút",h:"một giờ",hh:"%d giờ",d:"một ngày",dd:"%d ngày",w:"một tuần",ww:"%d tuần",M:"một tháng",MM:"%d tháng",y:"một năm",yy:"%d năm"},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:function(e){return e},week:{dow:1,doy:4}})}(t(5093))},4051(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("x-pseudo",{months:"J~áñúá~rý_F~ébrú~árý_~Márc~h_Áp~ríl_~Máý_~Júñé~_Júl~ý_Áú~gúst~_Sép~témb~ér_Ó~ctób~ér_Ñ~óvém~bér_~Décé~mbér".split("_"),monthsShort:"J~áñ_~Féb_~Már_~Ápr_~Máý_~Júñ_~Júl_~Áúg_~Sép_~Óct_~Ñóv_~Déc".split("_"),monthsParseExact:!0,weekdays:"S~úñdá~ý_Mó~ñdáý~_Túé~sdáý~_Wéd~ñésd~áý_T~húrs~dáý_~Fríd~áý_S~átúr~dáý".split("_"),weekdaysShort:"S~úñ_~Móñ_~Túé_~Wéd_~Thú_~Frí_~Sát".split("_"),weekdaysMin:"S~ú_Mó~_Tú_~Wé_T~h_Fr~_Sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[T~ódá~ý át] LT",nextDay:"[T~ómó~rró~w át] LT",nextWeek:"dddd [át] LT",lastDay:"[Ý~ést~érdá~ý át] LT",lastWeek:"[L~ást] dddd [át] LT",sameElse:"L"},relativeTime:{future:"í~ñ %s",past:"%s á~gó",s:"á ~féw ~sécó~ñds",ss:"%d s~écóñ~ds",m:"á ~míñ~úté",mm:"%d m~íñú~tés",h:"á~ñ hó~úr",hh:"%d h~óúrs",d:"á ~dáý",dd:"%d d~áýs",M:"á ~móñ~th",MM:"%d m~óñt~hs",y:"á ~ýéár",yy:"%d ý~éárs"},dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")},week:{dow:1,doy:4}})}(t(5093))},2218:function(e,a,t){!function(e){"use strict"; +e.defineLocale("x-pseudo",{months:"J~áñúá~rý_F~ébrú~árý_~Márc~h_Áp~ríl_~Máý_~Júñé~_Júl~ý_Áú~gúst~_Sép~témb~ér_Ó~ctób~ér_Ñ~óvém~bér_~Décé~mbér".split("_"),monthsShort:"J~áñ_~Féb_~Már_~Ápr_~Máý_~Júñ_~Júl_~Áúg_~Sép_~Óct_~Ñóv_~Déc".split("_"),monthsParseExact:!0,weekdays:"S~úñdá~ý_Mó~ñdáý~_Túé~sdáý~_Wéd~ñésd~áý_T~húrs~dáý_~Fríd~áý_S~átúr~dáý".split("_"),weekdaysShort:"S~úñ_~Móñ_~Túé_~Wéd_~Thú_~Frí_~Sát".split("_"),weekdaysMin:"S~ú_Mó~_Tú_~Wé_T~h_Fr~_Sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[T~ódá~ý át] LT",nextDay:"[T~ómó~rró~w át] LT",nextWeek:"dddd [át] LT",lastDay:"[Ý~ést~érdá~ý át] LT",lastWeek:"[L~ást] dddd [át] LT",sameElse:"L"},relativeTime:{future:"í~ñ %s",past:"%s á~gó",s:"á ~féw ~sécó~ñds",ss:"%d s~écóñ~ds",m:"á ~míñ~úté",mm:"%d m~íñú~tés",h:"á~ñ hó~úr",hh:"%d h~óúrs",d:"á ~dáý",dd:"%d d~áýs",M:"á ~móñ~th",MM:"%d m~óñt~hs",y:"á ~ýéár",yy:"%d ý~éárs"},dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(e){var a=e%10;return e+(1==~~(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")},week:{dow:1,doy:4}})}(t(5093))},2218(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("yo",{months:"Sẹ́rẹ́_Èrèlè_Ẹrẹ̀nà_Ìgbé_Èbibi_Òkùdu_Agẹmo_Ògún_Owewe_Ọ̀wàrà_Bélú_Ọ̀pẹ̀̀".split("_"),monthsShort:"Sẹ́r_Èrl_Ẹrn_Ìgb_Èbi_Òkù_Agẹ_Ògú_Owe_Ọ̀wà_Bél_Ọ̀pẹ̀̀".split("_"),weekdays:"Àìkú_Ajé_Ìsẹ́gun_Ọjọ́rú_Ọjọ́bọ_Ẹtì_Àbámẹ́ta".split("_"),weekdaysShort:"Àìk_Ajé_Ìsẹ́_Ọjr_Ọjb_Ẹtì_Àbá".split("_"),weekdaysMin:"Àì_Aj_Ìs_Ọr_Ọb_Ẹt_Àb".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Ònì ni] LT",nextDay:"[Ọ̀la ni] LT",nextWeek:"dddd [Ọsẹ̀ tón'bọ] [ni] LT",lastDay:"[Àna ni] LT",lastWeek:"dddd [Ọsẹ̀ tólọ́] [ni] LT",sameElse:"L"},relativeTime:{future:"ní %s",past:"%s kọjá",s:"ìsẹjú aayá die",ss:"aayá %d",m:"ìsẹjú kan",mm:"ìsẹjú %d",h:"wákati kan",hh:"wákati %d",d:"ọjọ́ kan",dd:"ọjọ́ %d",M:"osù kan",MM:"osù %d",y:"ọdún kan",yy:"ọdún %d"},dayOfMonthOrdinalParse:/ọjọ́\s\d{1,2}/,ordinal:"ọjọ́ %d",week:{dow:1,doy:4}})}(t(5093))},2648:function(e,a,t){!function(e){"use strict"; +e.defineLocale("yo",{months:"Sẹ́rẹ́_Èrèlè_Ẹrẹ̀nà_Ìgbé_Èbibi_Òkùdu_Agẹmo_Ògún_Owewe_Ọ̀wàrà_Bélú_Ọ̀pẹ̀̀".split("_"),monthsShort:"Sẹ́r_Èrl_Ẹrn_Ìgb_Èbi_Òkù_Agẹ_Ògú_Owe_Ọ̀wà_Bél_Ọ̀pẹ̀̀".split("_"),weekdays:"Àìkú_Ajé_Ìsẹ́gun_Ọjọ́rú_Ọjọ́bọ_Ẹtì_Àbámẹ́ta".split("_"),weekdaysShort:"Àìk_Ajé_Ìsẹ́_Ọjr_Ọjb_Ẹtì_Àbá".split("_"),weekdaysMin:"Àì_Aj_Ìs_Ọr_Ọb_Ẹt_Àb".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Ònì ni] LT",nextDay:"[Ọ̀la ni] LT",nextWeek:"dddd [Ọsẹ̀ tón'bọ] [ni] LT",lastDay:"[Àna ni] LT",lastWeek:"dddd [Ọsẹ̀ tólọ́] [ni] LT",sameElse:"L"},relativeTime:{future:"ní %s",past:"%s kọjá",s:"ìsẹjú aayá die",ss:"aayá %d",m:"ìsẹjú kan",mm:"ìsẹjú %d",h:"wákati kan",hh:"wákati %d",d:"ọjọ́ kan",dd:"ọjọ́ %d",M:"osù kan",MM:"osù %d",y:"ọdún kan",yy:"ọdún %d"},dayOfMonthOrdinalParse:/ọjọ́\s\d{1,2}/,ordinal:"ọjọ́ %d",week:{dow:1,doy:4}})}(t(5093))},2648(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("zh-cn",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"周日_周一_周二_周三_周四_周五_周六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日Ah点mm分",LLLL:"YYYY年M月D日ddddAh点mm分",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,a){return 12===e&&(e=0),"凌晨"===a||"早上"===a||"上午"===a?e:"下午"===a||"晚上"===a?e+12:e>=11?e:e+12},meridiem:function(e,a,t){var s=100*e+a;return s<600?"凌晨":s<900?"早上":s<1130?"上午":s<1230?"中午":s<1800?"下午":"晚上"},calendar:{sameDay:"[今天]LT",nextDay:"[明天]LT",nextWeek:function(e){return e.week()!==this.week()?"[下]dddLT":"[本]dddLT"},lastDay:"[昨天]LT",lastWeek:function(e){return this.week()!==e.week()?"[上]dddLT":"[本]dddLT"},sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|周)/,ordinal:function(e,a){switch(a){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"周";default:return e}},relativeTime:{future:"%s后",past:"%s前",s:"几秒",ss:"%d 秒",m:"1 分钟",mm:"%d 分钟",h:"1 小时",hh:"%d 小时",d:"1 天",dd:"%d 天",w:"1 周",ww:"%d 周",M:"1 个月",MM:"%d 个月",y:"1 年",yy:"%d 年"},week:{dow:1,doy:4}})}(t(5093))},1632:function(e,a,t){!function(e){"use strict"; +e.defineLocale("zh-cn",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"周日_周一_周二_周三_周四_周五_周六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日Ah点mm分",LLLL:"YYYY年M月D日ddddAh点mm分",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,a){return 12===e&&(e=0),"凌晨"===a||"早上"===a||"上午"===a?e:"下午"===a||"晚上"===a?e+12:e>=11?e:e+12},meridiem:function(e,a,t){var s=100*e+a;return s<600?"凌晨":s<900?"早上":s<1130?"上午":s<1230?"中午":s<1800?"下午":"晚上"},calendar:{sameDay:"[今天]LT",nextDay:"[明天]LT",nextWeek:function(e){return e.week()!==this.week()?"[下]dddLT":"[本]dddLT"},lastDay:"[昨天]LT",lastWeek:function(e){return this.week()!==e.week()?"[上]dddLT":"[本]dddLT"},sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|周)/,ordinal:function(e,a){switch(a){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"周";default:return e}},relativeTime:{future:"%s后",past:"%s前",s:"几秒",ss:"%d 秒",m:"1 分钟",mm:"%d 分钟",h:"1 小时",hh:"%d 小时",d:"1 天",dd:"%d 天",w:"1 周",ww:"%d 周",M:"1 个月",MM:"%d 个月",y:"1 年",yy:"%d 年"},week:{dow:1,doy:4}})}(t(5093))},1632(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("zh-hk",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日dddd HH:mm",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,a){return 12===e&&(e=0),"凌晨"===a||"早上"===a||"上午"===a?e:"中午"===a?e>=11?e:e+12:"下午"===a||"晚上"===a?e+12:void 0},meridiem:function(e,a,t){var s=100*e+a;return s<600?"凌晨":s<900?"早上":s<1200?"上午":1200===s?"中午":s<1800?"下午":"晚上"},calendar:{sameDay:"[今天]LT",nextDay:"[明天]LT",nextWeek:"[下]ddddLT",lastDay:"[昨天]LT",lastWeek:"[上]ddddLT",sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|週)/,ordinal:function(e,a){switch(a){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"週";default:return e}},relativeTime:{future:"%s後",past:"%s前",s:"幾秒",ss:"%d 秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}})}(t(5093))},1541:function(e,a,t){!function(e){"use strict"; +e.defineLocale("zh-hk",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日dddd HH:mm",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,a){return 12===e&&(e=0),"凌晨"===a||"早上"===a||"上午"===a?e:"中午"===a?e>=11?e:e+12:"下午"===a||"晚上"===a?e+12:void 0},meridiem:function(e,a,t){var s=100*e+a;return s<600?"凌晨":s<900?"早上":s<1200?"上午":1200===s?"中午":s<1800?"下午":"晚上"},calendar:{sameDay:"[今天]LT",nextDay:"[明天]LT",nextWeek:"[下]ddddLT",lastDay:"[昨天]LT",lastWeek:"[上]ddddLT",sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|週)/,ordinal:function(e,a){switch(a){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"週";default:return e}},relativeTime:{future:"%s後",past:"%s前",s:"幾秒",ss:"%d 秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}})}(t(5093))},1541(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("zh-mo",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日dddd HH:mm",l:"D/M/YYYY",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,a){return 12===e&&(e=0),"凌晨"===a||"早上"===a||"上午"===a?e:"中午"===a?e>=11?e:e+12:"下午"===a||"晚上"===a?e+12:void 0},meridiem:function(e,a,t){var s=100*e+a;return s<600?"凌晨":s<900?"早上":s<1130?"上午":s<1230?"中午":s<1800?"下午":"晚上"},calendar:{sameDay:"[今天] LT",nextDay:"[明天] LT",nextWeek:"[下]dddd LT",lastDay:"[昨天] LT",lastWeek:"[上]dddd LT",sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|週)/,ordinal:function(e,a){switch(a){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"週";default:return e}},relativeTime:{future:"%s內",past:"%s前",s:"幾秒",ss:"%d 秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}})}(t(5093))},304:function(e,a,t){!function(e){"use strict"; +e.defineLocale("zh-mo",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日dddd HH:mm",l:"D/M/YYYY",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,a){return 12===e&&(e=0),"凌晨"===a||"早上"===a||"上午"===a?e:"中午"===a?e>=11?e:e+12:"下午"===a||"晚上"===a?e+12:void 0},meridiem:function(e,a,t){var s=100*e+a;return s<600?"凌晨":s<900?"早上":s<1130?"上午":s<1230?"中午":s<1800?"下午":"晚上"},calendar:{sameDay:"[今天] LT",nextDay:"[明天] LT",nextWeek:"[下]dddd LT",lastDay:"[昨天] LT",lastWeek:"[上]dddd LT",sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|週)/,ordinal:function(e,a){switch(a){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"週";default:return e}},relativeTime:{future:"%s內",past:"%s前",s:"幾秒",ss:"%d 秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}})}(t(5093))},304(e,a,t){!function(e){"use strict"; //! moment.js locale configuration -e.defineLocale("zh-tw",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日dddd HH:mm",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,a){return 12===e&&(e=0),"凌晨"===a||"早上"===a||"上午"===a?e:"中午"===a?e>=11?e:e+12:"下午"===a||"晚上"===a?e+12:void 0},meridiem:function(e,a,t){var s=100*e+a;return s<600?"凌晨":s<900?"早上":s<1130?"上午":s<1230?"中午":s<1800?"下午":"晚上"},calendar:{sameDay:"[今天] LT",nextDay:"[明天] LT",nextWeek:"[下]dddd LT",lastDay:"[昨天] LT",lastWeek:"[上]dddd LT",sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|週)/,ordinal:function(e,a){switch(a){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"週";default:return e}},relativeTime:{future:"%s後",past:"%s前",s:"幾秒",ss:"%d 秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}})}(t(5093))},5358:(e,a,t)=>{var s={"./af":5177,"./af.js":5177,"./ar":1509,"./ar-dz":1488,"./ar-dz.js":1488,"./ar-kw":8676,"./ar-kw.js":8676,"./ar-ly":2353,"./ar-ly.js":2353,"./ar-ma":4496,"./ar-ma.js":4496,"./ar-ps":6947,"./ar-ps.js":6947,"./ar-sa":2682,"./ar-sa.js":2682,"./ar-tn":9756,"./ar-tn.js":9756,"./ar.js":1509,"./az":5533,"./az.js":5533,"./be":8959,"./be.js":8959,"./bg":7777,"./bg.js":7777,"./bm":4903,"./bm.js":4903,"./bn":1290,"./bn-bd":7357,"./bn-bd.js":7357,"./bn.js":1290,"./bo":1545,"./bo.js":1545,"./br":1470,"./br.js":1470,"./bs":4429,"./bs.js":4429,"./ca":7306,"./ca.js":7306,"./cs":6464,"./cs.js":6464,"./cv":3635,"./cv.js":3635,"./cy":4226,"./cy.js":4226,"./da":3601,"./da.js":3601,"./de":7853,"./de-at":6111,"./de-at.js":6111,"./de-ch":4697,"./de-ch.js":4697,"./de.js":7853,"./dv":708,"./dv.js":708,"./el":4691,"./el.js":4691,"./en-au":3872,"./en-au.js":3872,"./en-ca":8298,"./en-ca.js":8298,"./en-gb":6195,"./en-gb.js":6195,"./en-ie":6584,"./en-ie.js":6584,"./en-il":5543,"./en-il.js":5543,"./en-in":9033,"./en-in.js":9033,"./en-nz":9402,"./en-nz.js":9402,"./en-sg":3004,"./en-sg.js":3004,"./eo":2934,"./eo.js":2934,"./es":7650,"./es-do":838,"./es-do.js":838,"./es-mx":7730,"./es-mx.js":7730,"./es-us":6575,"./es-us.js":6575,"./es.js":7650,"./et":3035,"./et.js":3035,"./eu":3508,"./eu.js":3508,"./fa":119,"./fa.js":119,"./fi":527,"./fi.js":527,"./fil":5995,"./fil.js":5995,"./fo":2477,"./fo.js":2477,"./fr":5498,"./fr-ca":6435,"./fr-ca.js":6435,"./fr-ch":7892,"./fr-ch.js":7892,"./fr.js":5498,"./fy":7071,"./fy.js":7071,"./ga":1734,"./ga.js":1734,"./gd":217,"./gd.js":217,"./gl":7329,"./gl.js":7329,"./gom-deva":2124,"./gom-deva.js":2124,"./gom-latn":3383,"./gom-latn.js":3383,"./gu":5050,"./gu.js":5050,"./he":1713,"./he.js":1713,"./hi":3861,"./hi.js":3861,"./hr":6308,"./hr.js":6308,"./hu":609,"./hu.js":609,"./hy-am":7160,"./hy-am.js":7160,"./id":4063,"./id.js":4063,"./is":9374,"./is.js":9374,"./it":8383,"./it-ch":1827,"./it-ch.js":1827,"./it.js":8383,"./ja":3827,"./ja.js":3827,"./jv":9722,"./jv.js":9722,"./ka":1794,"./ka.js":1794,"./kk":7088,"./kk.js":7088,"./km":6870,"./km.js":6870,"./kn":4451,"./kn.js":4451,"./ko":3164,"./ko.js":3164,"./ku":8174,"./ku-kmr":6181,"./ku-kmr.js":6181,"./ku.js":8174,"./ky":8474,"./ky.js":8474,"./lb":9680,"./lb.js":9680,"./lo":5867,"./lo.js":5867,"./lt":5766,"./lt.js":5766,"./lv":9532,"./lv.js":9532,"./me":8076,"./me.js":8076,"./mi":1848,"./mi.js":1848,"./mk":306,"./mk.js":306,"./ml":3739,"./ml.js":3739,"./mn":9053,"./mn.js":9053,"./mr":6169,"./mr.js":6169,"./ms":3386,"./ms-my":2297,"./ms-my.js":2297,"./ms.js":3386,"./mt":7075,"./mt.js":7075,"./my":2264,"./my.js":2264,"./nb":2274,"./nb.js":2274,"./ne":8235,"./ne.js":8235,"./nl":2572,"./nl-be":3784,"./nl-be.js":3784,"./nl.js":2572,"./nn":4566,"./nn.js":4566,"./oc-lnc":9330,"./oc-lnc.js":9330,"./pa-in":9849,"./pa-in.js":9849,"./pl":4418,"./pl.js":4418,"./pt":9834,"./pt-br":8303,"./pt-br.js":8303,"./pt.js":9834,"./ro":4457,"./ro.js":4457,"./ru":2271,"./ru.js":2271,"./sd":1221,"./sd.js":1221,"./se":3478,"./se.js":3478,"./si":7538,"./si.js":7538,"./sk":5784,"./sk.js":5784,"./sl":6637,"./sl.js":6637,"./sq":6794,"./sq.js":6794,"./sr":5719,"./sr-cyrl":3322,"./sr-cyrl.js":3322,"./sr.js":5719,"./ss":6e3,"./ss.js":6e3,"./sv":1011,"./sv.js":1011,"./sw":748,"./sw.js":748,"./ta":1025,"./ta.js":1025,"./te":1885,"./te.js":1885,"./tet":8861,"./tet.js":8861,"./tg":6571,"./tg.js":6571,"./th":5802,"./th.js":5802,"./tk":9527,"./tk.js":9527,"./tl-ph":9231,"./tl-ph.js":9231,"./tlh":1052,"./tlh.js":1052,"./tr":5096,"./tr.js":5096,"./tzl":9846,"./tzl.js":9846,"./tzm":1765,"./tzm-latn":7711,"./tzm-latn.js":7711,"./tzm.js":1765,"./ug-cn":8414,"./ug-cn.js":8414,"./uk":6618,"./uk.js":6618,"./ur":158,"./ur.js":158,"./uz":7609,"./uz-latn":2475,"./uz-latn.js":2475,"./uz.js":7609,"./vi":1135,"./vi.js":1135,"./x-pseudo":4051,"./x-pseudo.js":4051,"./yo":2218,"./yo.js":2218,"./zh-cn":2648,"./zh-cn.js":2648,"./zh-hk":1632,"./zh-hk.js":1632,"./zh-mo":1541,"./zh-mo.js":1541,"./zh-tw":304,"./zh-tw.js":304};function n(e){var a=r(e);return t(a)}function r(e){if(!t.o(s,e)){var a=new Error("Cannot find module '"+e+"'");throw a.code="MODULE_NOT_FOUND",a}return s[e]}n.keys=function(){return Object.keys(s)},n.resolve=r,e.exports=n,n.id=5358},5093:function(e,a,t){(e=t.nmd(e)).exports=function(){"use strict";var a,s;function n(){return a.apply(null,arguments)}function r(e){a=e}function i(e){return e instanceof Array||"[object Array]"===Object.prototype.toString.call(e)}function d(e){return null!=e&&"[object Object]"===Object.prototype.toString.call(e)}function _(e,a){return Object.prototype.hasOwnProperty.call(e,a)}function o(e){if(Object.getOwnPropertyNames)return 0===Object.getOwnPropertyNames(e).length;var a;for(a in e)if(_(e,a))return!1;return!0}function u(e){return void 0===e}function m(e){return"number"==typeof e||"[object Number]"===Object.prototype.toString.call(e)}function l(e){return e instanceof Date||"[object Date]"===Object.prototype.toString.call(e)}function M(e,a){var t,s=[],n=e.length;for(t=0;t>>0;for(a=0;a0)for(t=0;t=0?t?"+":"":"-")+Math.pow(10,Math.max(0,n)).toString().substr(1)+s}var F=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,z=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,N={},J={};function R(e,a,t,s){var n=s;"string"==typeof s&&(n=function(){return this[s]()}),e&&(J[e]=n),a&&(J[a[0]]=function(){return E(n.apply(this,arguments),a[1],a[2])}),t&&(J[t]=function(){return this.localeData().ordinal(n.apply(this,arguments),e)})}function C(e){return e.match(/\[[\s\S]/)?e.replace(/^\[|\]$/g,""):e.replace(/\\/g,"")}function I(e){var a,t,s=e.match(F);for(a=0,t=s.length;a=0&&z.test(e);)e=e.replace(z,s),z.lastIndex=0,t-=1;return e}var V={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"};function q(e){var a=this._longDateFormat[e],t=this._longDateFormat[e.toUpperCase()];return a||!t?a:(this._longDateFormat[e]=t.match(F).map((function(e){return"MMMM"===e||"MM"===e||"DD"===e||"dddd"===e?e.slice(1):e})).join(""),this._longDateFormat[e])}var B="Invalid date";function K(){return this._invalidDate}var Z="%d",$=/\d{1,2}/;function Q(e){return this._ordinal.replace("%d",e)}var X={future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"};function ee(e,a,t,s){var n=this._relativeTime[t];return j(n)?n(e,a,t,s):n.replace(/%d/i,e)}function ae(e,a){var t=this._relativeTime[e>0?"future":"past"];return j(t)?t(a):t.replace(/%s/i,a)}var te={D:"date",dates:"date",date:"date",d:"day",days:"day",day:"day",e:"weekday",weekdays:"weekday",weekday:"weekday",E:"isoWeekday",isoweekdays:"isoWeekday",isoweekday:"isoWeekday",DDD:"dayOfYear",dayofyears:"dayOfYear",dayofyear:"dayOfYear",h:"hour",hours:"hour",hour:"hour",ms:"millisecond",milliseconds:"millisecond",millisecond:"millisecond",m:"minute",minutes:"minute",minute:"minute",M:"month",months:"month",month:"month",Q:"quarter",quarters:"quarter",quarter:"quarter",s:"second",seconds:"second",second:"second",gg:"weekYear",weekyears:"weekYear",weekyear:"weekYear",GG:"isoWeekYear",isoweekyears:"isoWeekYear",isoweekyear:"isoWeekYear",w:"week",weeks:"week",week:"week",W:"isoWeek",isoweeks:"isoWeek",isoweek:"isoWeek",y:"year",years:"year",year:"year"};function se(e){return"string"==typeof e?te[e]||te[e.toLowerCase()]:void 0}function ne(e){var a,t,s={};for(t in e)_(e,t)&&(a=se(t))&&(s[a]=e[t]);return s}var re={date:9,day:11,weekday:11,isoWeekday:11,dayOfYear:4,hour:13,millisecond:16,minute:14,month:8,quarter:7,second:15,weekYear:1,isoWeekYear:1,week:5,isoWeek:5,year:1};function ie(e){var a,t=[];for(a in e)_(e,a)&&t.push({unit:a,priority:re[a]});return t.sort((function(e,a){return e.priority-a.priority})),t}var de,_e=/\d/,oe=/\d\d/,ue=/\d{3}/,me=/\d{4}/,le=/[+-]?\d{6}/,Me=/\d\d?/,he=/\d\d\d\d?/,ce=/\d\d\d\d\d\d?/,Le=/\d{1,3}/,Ye=/\d{1,4}/,ye=/[+-]?\d{1,6}/,fe=/\d+/,ke=/[+-]?\d+/,pe=/Z|[+-]\d\d:?\d\d/gi,De=/Z|[+-]\d\d(?::?\d\d)?/gi,Te=/[+-]?\d+(\.\d{1,3})?/,ge=/[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i,we=/^[1-9]\d?/,ve=/^([1-9]\d|\d)/;function be(e,a,t){de[e]=j(a)?a:function(e,s){return e&&t?t:a}}function He(e,a){return _(de,e)?de[e](a._strict,a._locale):new RegExp(Se(e))}function Se(e){return je(e.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,(function(e,a,t,s,n){return a||t||s||n})))}function je(e){return e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function xe(e){return e<0?Math.ceil(e)||0:Math.floor(e)}function Pe(e){var a=+e,t=0;return 0!==a&&isFinite(a)&&(t=xe(a)),t}de={};var Oe={};function We(e,a){var t,s,n=a;for("string"==typeof e&&(e=[e]),m(a)&&(n=function(e,t){t[a]=Pe(e)}),s=e.length,t=0;t68?1900:2e3)};var Be,Ke=$e("FullYear",!0);function Ze(){return Fe(this.year())}function $e(e,a){return function(t){return null!=t?(Xe(this,e,t),n.updateOffset(this,a),this):Qe(this,e)}}function Qe(e,a){if(!e.isValid())return NaN;var t=e._d,s=e._isUTC;switch(a){case"Milliseconds":return s?t.getUTCMilliseconds():t.getMilliseconds();case"Seconds":return s?t.getUTCSeconds():t.getSeconds();case"Minutes":return s?t.getUTCMinutes():t.getMinutes();case"Hours":return s?t.getUTCHours():t.getHours();case"Date":return s?t.getUTCDate():t.getDate();case"Day":return s?t.getUTCDay():t.getDay();case"Month":return s?t.getUTCMonth():t.getMonth();case"FullYear":return s?t.getUTCFullYear():t.getFullYear();default:return NaN}}function Xe(e,a,t){var s,n,r,i,d;if(e.isValid()&&!isNaN(t)){switch(s=e._d,n=e._isUTC,a){case"Milliseconds":return void(n?s.setUTCMilliseconds(t):s.setMilliseconds(t));case"Seconds":return void(n?s.setUTCSeconds(t):s.setSeconds(t));case"Minutes":return void(n?s.setUTCMinutes(t):s.setMinutes(t));case"Hours":return void(n?s.setUTCHours(t):s.setHours(t));case"Date":return void(n?s.setUTCDate(t):s.setDate(t));case"FullYear":break;default:return}r=t,i=e.month(),d=29!==(d=e.date())||1!==i||Fe(r)?d:28,n?s.setUTCFullYear(r,i,d):s.setFullYear(r,i,d)}}function ea(e){return j(this[e=se(e)])?this[e]():this}function aa(e,a){if("object"==typeof e){var t,s=ie(e=ne(e)),n=s.length;for(t=0;t=0?(d=new Date(e+400,a,t,s,n,r,i),isFinite(d.getFullYear())&&d.setFullYear(e)):d=new Date(e,a,t,s,n,r,i),d}function ka(e){var a,t;return e<100&&e>=0?((t=Array.prototype.slice.call(arguments))[0]=e+400,a=new Date(Date.UTC.apply(null,t)),isFinite(a.getUTCFullYear())&&a.setUTCFullYear(e)):a=new Date(Date.UTC.apply(null,arguments)),a}function pa(e,a,t){var s=7+a-t;return-(7+ka(e,0,s).getUTCDay()-a)%7+s-1}function Da(e,a,t,s,n){var r,i,d=1+7*(a-1)+(7+t-s)%7+pa(e,s,n);return d<=0?i=qe(r=e-1)+d:d>qe(e)?(r=e+1,i=d-qe(e)):(r=e,i=d),{year:r,dayOfYear:i}}function Ta(e,a,t){var s,n,r=pa(e.year(),a,t),i=Math.floor((e.dayOfYear()-r-1)/7)+1;return i<1?s=i+ga(n=e.year()-1,a,t):i>ga(e.year(),a,t)?(s=i-ga(e.year(),a,t),n=e.year()+1):(n=e.year(),s=i),{week:s,year:n}}function ga(e,a,t){var s=pa(e,a,t),n=pa(e+1,a,t);return(qe(e)-s+n)/7}function wa(e){return Ta(e,this._week.dow,this._week.doy).week}R("w",["ww",2],"wo","week"),R("W",["WW",2],"Wo","isoWeek"),be("w",Me,we),be("ww",Me,oe),be("W",Me,we),be("WW",Me,oe),Ae(["w","ww","W","WW"],(function(e,a,t,s){a[s.substr(0,1)]=Pe(e)}));var va={dow:0,doy:6};function ba(){return this._week.dow}function Ha(){return this._week.doy}function Sa(e){var a=this.localeData().week(this);return null==e?a:this.add(7*(e-a),"d")}function ja(e){var a=Ta(this,1,4).week;return null==e?a:this.add(7*(e-a),"d")}function xa(e,a){return"string"!=typeof e?e:isNaN(e)?"number"==typeof(e=a.weekdaysParse(e))?e:null:parseInt(e,10)}function Pa(e,a){return"string"==typeof e?a.weekdaysParse(e)%7||7:isNaN(e)?null:e}function Oa(e,a){return e.slice(a,7).concat(e.slice(0,a))}R("d",0,"do","day"),R("dd",0,0,(function(e){return this.localeData().weekdaysMin(this,e)})),R("ddd",0,0,(function(e){return this.localeData().weekdaysShort(this,e)})),R("dddd",0,0,(function(e){return this.localeData().weekdays(this,e)})),R("e",0,0,"weekday"),R("E",0,0,"isoWeekday"),be("d",Me),be("e",Me),be("E",Me),be("dd",(function(e,a){return a.weekdaysMinRegex(e)})),be("ddd",(function(e,a){return a.weekdaysShortRegex(e)})),be("dddd",(function(e,a){return a.weekdaysRegex(e)})),Ae(["dd","ddd","dddd"],(function(e,a,t,s){var n=t._locale.weekdaysParse(e,s,t._strict);null!=n?a.d=n:Y(t).invalidWeekday=e})),Ae(["d","e","E"],(function(e,a,t,s){a[s]=Pe(e)}));var Wa="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Aa="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Ea="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),Fa=ge,za=ge,Na=ge;function Ja(e,a){var t=i(this._weekdays)?this._weekdays:this._weekdays[e&&!0!==e&&this._weekdays.isFormat.test(a)?"format":"standalone"];return!0===e?Oa(t,this._week.dow):e?t[e.day()]:t}function Ra(e){return!0===e?Oa(this._weekdaysShort,this._week.dow):e?this._weekdaysShort[e.day()]:this._weekdaysShort}function Ca(e){return!0===e?Oa(this._weekdaysMin,this._week.dow):e?this._weekdaysMin[e.day()]:this._weekdaysMin}function Ia(e,a,t){var s,n,r,i=e.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],s=0;s<7;++s)r=c([2e3,1]).day(s),this._minWeekdaysParse[s]=this.weekdaysMin(r,"").toLocaleLowerCase(),this._shortWeekdaysParse[s]=this.weekdaysShort(r,"").toLocaleLowerCase(),this._weekdaysParse[s]=this.weekdays(r,"").toLocaleLowerCase();return t?"dddd"===a?-1!==(n=Be.call(this._weekdaysParse,i))?n:null:"ddd"===a?-1!==(n=Be.call(this._shortWeekdaysParse,i))?n:null:-1!==(n=Be.call(this._minWeekdaysParse,i))?n:null:"dddd"===a?-1!==(n=Be.call(this._weekdaysParse,i))||-1!==(n=Be.call(this._shortWeekdaysParse,i))||-1!==(n=Be.call(this._minWeekdaysParse,i))?n:null:"ddd"===a?-1!==(n=Be.call(this._shortWeekdaysParse,i))||-1!==(n=Be.call(this._weekdaysParse,i))||-1!==(n=Be.call(this._minWeekdaysParse,i))?n:null:-1!==(n=Be.call(this._minWeekdaysParse,i))||-1!==(n=Be.call(this._weekdaysParse,i))||-1!==(n=Be.call(this._shortWeekdaysParse,i))?n:null}function Ua(e,a,t){var s,n,r;if(this._weekdaysParseExact)return Ia.call(this,e,a,t);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),s=0;s<7;s++){if(n=c([2e3,1]).day(s),t&&!this._fullWeekdaysParse[s]&&(this._fullWeekdaysParse[s]=new RegExp("^"+this.weekdays(n,"").replace(".","\\.?")+"$","i"),this._shortWeekdaysParse[s]=new RegExp("^"+this.weekdaysShort(n,"").replace(".","\\.?")+"$","i"),this._minWeekdaysParse[s]=new RegExp("^"+this.weekdaysMin(n,"").replace(".","\\.?")+"$","i")),this._weekdaysParse[s]||(r="^"+this.weekdays(n,"")+"|^"+this.weekdaysShort(n,"")+"|^"+this.weekdaysMin(n,""),this._weekdaysParse[s]=new RegExp(r.replace(".",""),"i")),t&&"dddd"===a&&this._fullWeekdaysParse[s].test(e))return s;if(t&&"ddd"===a&&this._shortWeekdaysParse[s].test(e))return s;if(t&&"dd"===a&&this._minWeekdaysParse[s].test(e))return s;if(!t&&this._weekdaysParse[s].test(e))return s}}function Ga(e){if(!this.isValid())return null!=e?this:NaN;var a=Qe(this,"Day");return null!=e?(e=xa(e,this.localeData()),this.add(e-a,"d")):a}function Va(e){if(!this.isValid())return null!=e?this:NaN;var a=(this.day()+7-this.localeData()._week.dow)%7;return null==e?a:this.add(e-a,"d")}function qa(e){if(!this.isValid())return null!=e?this:NaN;if(null!=e){var a=Pa(e,this.localeData());return this.day(this.day()%7?a:a-7)}return this.day()||7}function Ba(e){return this._weekdaysParseExact?(_(this,"_weekdaysRegex")||$a.call(this),e?this._weekdaysStrictRegex:this._weekdaysRegex):(_(this,"_weekdaysRegex")||(this._weekdaysRegex=Fa),this._weekdaysStrictRegex&&e?this._weekdaysStrictRegex:this._weekdaysRegex)}function Ka(e){return this._weekdaysParseExact?(_(this,"_weekdaysRegex")||$a.call(this),e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(_(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=za),this._weekdaysShortStrictRegex&&e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function Za(e){return this._weekdaysParseExact?(_(this,"_weekdaysRegex")||$a.call(this),e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(_(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=Na),this._weekdaysMinStrictRegex&&e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function $a(){function e(e,a){return a.length-e.length}var a,t,s,n,r,i=[],d=[],_=[],o=[];for(a=0;a<7;a++)t=c([2e3,1]).day(a),s=je(this.weekdaysMin(t,"")),n=je(this.weekdaysShort(t,"")),r=je(this.weekdays(t,"")),i.push(s),d.push(n),_.push(r),o.push(s),o.push(n),o.push(r);i.sort(e),d.sort(e),_.sort(e),o.sort(e),this._weekdaysRegex=new RegExp("^("+o.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+_.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+d.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+i.join("|")+")","i")}function Qa(){return this.hours()%12||12}function Xa(){return this.hours()||24}function et(e,a){R(e,0,0,(function(){return this.localeData().meridiem(this.hours(),this.minutes(),a)}))}function at(e,a){return a._meridiemParse}function tt(e){return"p"===(e+"").toLowerCase().charAt(0)}R("H",["HH",2],0,"hour"),R("h",["hh",2],0,Qa),R("k",["kk",2],0,Xa),R("hmm",0,0,(function(){return""+Qa.apply(this)+E(this.minutes(),2)})),R("hmmss",0,0,(function(){return""+Qa.apply(this)+E(this.minutes(),2)+E(this.seconds(),2)})),R("Hmm",0,0,(function(){return""+this.hours()+E(this.minutes(),2)})),R("Hmmss",0,0,(function(){return""+this.hours()+E(this.minutes(),2)+E(this.seconds(),2)})),et("a",!0),et("A",!1),be("a",at),be("A",at),be("H",Me,ve),be("h",Me,we),be("k",Me,we),be("HH",Me,oe),be("hh",Me,oe),be("kk",Me,oe),be("hmm",he),be("hmmss",ce),be("Hmm",he),be("Hmmss",ce),We(["H","HH"],Re),We(["k","kk"],(function(e,a,t){var s=Pe(e);a[Re]=24===s?0:s})),We(["a","A"],(function(e,a,t){t._isPm=t._locale.isPM(e),t._meridiem=e})),We(["h","hh"],(function(e,a,t){a[Re]=Pe(e),Y(t).bigHour=!0})),We("hmm",(function(e,a,t){var s=e.length-2;a[Re]=Pe(e.substr(0,s)),a[Ce]=Pe(e.substr(s)),Y(t).bigHour=!0})),We("hmmss",(function(e,a,t){var s=e.length-4,n=e.length-2;a[Re]=Pe(e.substr(0,s)),a[Ce]=Pe(e.substr(s,2)),a[Ie]=Pe(e.substr(n)),Y(t).bigHour=!0})),We("Hmm",(function(e,a,t){var s=e.length-2;a[Re]=Pe(e.substr(0,s)),a[Ce]=Pe(e.substr(s))})),We("Hmmss",(function(e,a,t){var s=e.length-4,n=e.length-2;a[Re]=Pe(e.substr(0,s)),a[Ce]=Pe(e.substr(s,2)),a[Ie]=Pe(e.substr(n))}));var st=/[ap]\.?m?\.?/i,nt=$e("Hours",!0);function rt(e,a,t){return e>11?t?"pm":"PM":t?"am":"AM"}var it,dt={calendar:W,longDateFormat:V,invalidDate:B,ordinal:Z,dayOfMonthOrdinalParse:$,relativeTime:X,months:na,monthsShort:ra,week:va,weekdays:Wa,weekdaysMin:Ea,weekdaysShort:Aa,meridiemParse:st},_t={},ot={};function ut(e,a){var t,s=Math.min(e.length,a.length);for(t=0;t0;){if(s=ht(n.slice(0,a).join("-")))return s;if(t&&t.length>=a&&ut(n,t)>=a-1)break;a--}r++}return it}function Mt(e){return!(!e||!e.match("^[^/\\\\]*$"))}function ht(a){var s=null;if(void 0===_t[a]&&e&&e.exports&&Mt(a))try{s=it._abbr,t(5358)("./"+a),ct(s)}catch(e){_t[a]=null}return _t[a]}function ct(e,a){var t;return e&&((t=u(a)?yt(e):Lt(e,a))?it=t:"undefined"!=typeof console&&console.warn&&console.warn("Locale "+e+" not found. Did you forget to load it?")),it._abbr}function Lt(e,a){if(null!==a){var t,s=dt;if(a.abbr=e,null!=_t[e])S("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),s=_t[e]._config;else if(null!=a.parentLocale)if(null!=_t[a.parentLocale])s=_t[a.parentLocale]._config;else{if(null==(t=ht(a.parentLocale)))return ot[a.parentLocale]||(ot[a.parentLocale]=[]),ot[a.parentLocale].push({name:e,config:a}),null;s=t._config}return _t[e]=new O(P(s,a)),ot[e]&&ot[e].forEach((function(e){Lt(e.name,e.config)})),ct(e),_t[e]}return delete _t[e],null}function Yt(e,a){if(null!=a){var t,s,n=dt;null!=_t[e]&&null!=_t[e].parentLocale?_t[e].set(P(_t[e]._config,a)):(null!=(s=ht(e))&&(n=s._config),a=P(n,a),null==s&&(a.abbr=e),(t=new O(a)).parentLocale=_t[e],_t[e]=t),ct(e)}else null!=_t[e]&&(null!=_t[e].parentLocale?(_t[e]=_t[e].parentLocale,e===ct()&&ct(e)):null!=_t[e]&&delete _t[e]);return _t[e]}function yt(e){var a;if(e&&e._locale&&e._locale._abbr&&(e=e._locale._abbr),!e)return it;if(!i(e)){if(a=ht(e))return a;e=[e]}return lt(e)}function ft(){return b(_t)}function kt(e){var a,t=e._a;return t&&-2===Y(e).overflow&&(a=t[Ne]<0||t[Ne]>11?Ne:t[Je]<1||t[Je]>sa(t[ze],t[Ne])?Je:t[Re]<0||t[Re]>24||24===t[Re]&&(0!==t[Ce]||0!==t[Ie]||0!==t[Ue])?Re:t[Ce]<0||t[Ce]>59?Ce:t[Ie]<0||t[Ie]>59?Ie:t[Ue]<0||t[Ue]>999?Ue:-1,Y(e)._overflowDayOfYear&&(aJe)&&(a=Je),Y(e)._overflowWeeks&&-1===a&&(a=Ge),Y(e)._overflowWeekday&&-1===a&&(a=Ve),Y(e).overflow=a),e}var pt=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Dt=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Tt=/Z|[+-]\d\d(?::?\d\d)?/,gt=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/],["YYYYMM",/\d{6}/,!1],["YYYY",/\d{4}/,!1]],wt=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],vt=/^\/?Date\((-?\d+)/i,bt=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/,Ht={UT:0,GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};function St(e){var a,t,s,n,r,i,d=e._i,_=pt.exec(d)||Dt.exec(d),o=gt.length,u=wt.length;if(_){for(Y(e).iso=!0,a=0,t=o;aqe(r)||0===e._dayOfYear)&&(Y(e)._overflowDayOfYear=!0),t=ka(r,0,e._dayOfYear),e._a[Ne]=t.getUTCMonth(),e._a[Je]=t.getUTCDate()),a=0;a<3&&null==e._a[a];++a)e._a[a]=i[a]=s[a];for(;a<7;a++)e._a[a]=i[a]=null==e._a[a]?2===a?1:0:e._a[a];24===e._a[Re]&&0===e._a[Ce]&&0===e._a[Ie]&&0===e._a[Ue]&&(e._nextDay=!0,e._a[Re]=0),e._d=(e._useUTC?ka:fa).apply(null,i),n=e._useUTC?e._d.getUTCDay():e._d.getDay(),null!=e._tzm&&e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),e._nextDay&&(e._a[Re]=24),e._w&&void 0!==e._w.d&&e._w.d!==n&&(Y(e).weekdayMismatch=!0)}}function Jt(e){var a,t,s,n,r,i,d,_,o;null!=(a=e._w).GG||null!=a.W||null!=a.E?(r=1,i=4,t=Ft(a.GG,e._a[ze],Ta(Kt(),1,4).year),s=Ft(a.W,1),((n=Ft(a.E,1))<1||n>7)&&(_=!0)):(r=e._locale._week.dow,i=e._locale._week.doy,o=Ta(Kt(),r,i),t=Ft(a.gg,e._a[ze],o.year),s=Ft(a.w,o.week),null!=a.d?((n=a.d)<0||n>6)&&(_=!0):null!=a.e?(n=a.e+r,(a.e<0||a.e>6)&&(_=!0)):n=r),s<1||s>ga(t,r,i)?Y(e)._overflowWeeks=!0:null!=_?Y(e)._overflowWeekday=!0:(d=Da(t,s,n,r,i),e._a[ze]=d.year,e._dayOfYear=d.dayOfYear)}function Rt(e){if(e._f!==n.ISO_8601)if(e._f!==n.RFC_2822){e._a=[],Y(e).empty=!0;var a,t,s,r,i,d,_,o=""+e._i,u=o.length,m=0;for(_=(s=G(e._f,e._locale).match(F)||[]).length,a=0;a<_;a++)r=s[a],(t=(o.match(He(r,e))||[])[0])&&((i=o.substr(0,o.indexOf(t))).length>0&&Y(e).unusedInput.push(i),o=o.slice(o.indexOf(t)+t.length),m+=t.length),J[r]?(t?Y(e).empty=!1:Y(e).unusedTokens.push(r),Ee(r,t,e)):e._strict&&!t&&Y(e).unusedTokens.push(r);Y(e).charsLeftOver=u-m,o.length>0&&Y(e).unusedInput.push(o),e._a[Re]<=12&&!0===Y(e).bigHour&&e._a[Re]>0&&(Y(e).bigHour=void 0),Y(e).parsedDateParts=e._a.slice(0),Y(e).meridiem=e._meridiem,e._a[Re]=Ct(e._locale,e._a[Re],e._meridiem),null!==(d=Y(e).era)&&(e._a[ze]=e._locale.erasConvertYear(d,e._a[ze])),Nt(e),kt(e)}else At(e);else St(e)}function Ct(e,a,t){var s;return null==t?a:null!=e.meridiemHour?e.meridiemHour(a,t):null!=e.isPM?((s=e.isPM(t))&&a<12&&(a+=12),s||12!==a||(a=0),a):a}function It(e){var a,t,s,n,r,i,d=!1,_=e._f.length;if(0===_)return Y(e).invalidFormat=!0,void(e._d=new Date(NaN));for(n=0;n<_;n++)r=0,i=!1,a=D({},e),null!=e._useUTC&&(a._useUTC=e._useUTC),a._f=e._f[n],Rt(a),y(a)&&(i=!0),r+=Y(a).charsLeftOver,r+=10*Y(a).unusedTokens.length,Y(a).score=r,d?rthis?this:e:f()}));function Qt(e,a){var t,s;if(1===a.length&&i(a[0])&&(a=a[0]),!a.length)return Kt();for(t=a[0],s=1;sthis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Ds(){if(!u(this._isDSTShifted))return this._isDSTShifted;var e,a={};return D(a,this),(a=Vt(a))._a?(e=a._isUTC?c(a._a):Kt(a._a),this._isDSTShifted=this.isValid()&&os(a._a,e.toArray())>0):this._isDSTShifted=!1,this._isDSTShifted}function Ts(){return!!this.isValid()&&!this._isUTC}function gs(){return!!this.isValid()&&this._isUTC}function ws(){return!!this.isValid()&&this._isUTC&&0===this._offset}n.updateOffset=function(){};var vs=/^(-|\+)?(?:(\d*)[. ])?(\d+):(\d+)(?::(\d+)(\.\d*)?)?$/,bs=/^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;function Hs(e,a){var t,s,n,r=e,i=null;return ds(e)?r={ms:e._milliseconds,d:e._days,M:e._months}:m(e)||!isNaN(+e)?(r={},a?r[a]=+e:r.milliseconds=+e):(i=vs.exec(e))?(t="-"===i[1]?-1:1,r={y:0,d:Pe(i[Je])*t,h:Pe(i[Re])*t,m:Pe(i[Ce])*t,s:Pe(i[Ie])*t,ms:Pe(_s(1e3*i[Ue]))*t}):(i=bs.exec(e))?(t="-"===i[1]?-1:1,r={y:Ss(i[2],t),M:Ss(i[3],t),w:Ss(i[4],t),d:Ss(i[5],t),h:Ss(i[6],t),m:Ss(i[7],t),s:Ss(i[8],t)}):null==r?r={}:"object"==typeof r&&("from"in r||"to"in r)&&(n=xs(Kt(r.from),Kt(r.to)),(r={}).ms=n.milliseconds,r.M=n.months),s=new is(r),ds(e)&&_(e,"_locale")&&(s._locale=e._locale),ds(e)&&_(e,"_isValid")&&(s._isValid=e._isValid),s}function Ss(e,a){var t=e&&parseFloat(e.replace(",","."));return(isNaN(t)?0:t)*a}function js(e,a){var t={};return t.months=a.month()-e.month()+12*(a.year()-e.year()),e.clone().add(t.months,"M").isAfter(a)&&--t.months,t.milliseconds=+a-+e.clone().add(t.months,"M"),t}function xs(e,a){var t;return e.isValid()&&a.isValid()?(a=Ms(a,e),e.isBefore(a)?t=js(e,a):((t=js(a,e)).milliseconds=-t.milliseconds,t.months=-t.months),t):{milliseconds:0,months:0}}function Ps(e,a){return function(t,s){var n;return null===s||isNaN(+s)||(S(a,"moment()."+a+"(period, number) is deprecated. Please use moment()."+a+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),n=t,t=s,s=n),Os(this,Hs(t,s),e),this}}function Os(e,a,t,s){var r=a._milliseconds,i=_s(a._days),d=_s(a._months);e.isValid()&&(s=null==s||s,d&&Ma(e,Qe(e,"Month")+d*t),i&&Xe(e,"Date",Qe(e,"Date")+i*t),r&&e._d.setTime(e._d.valueOf()+r*t),s&&n.updateOffset(e,i||d))}Hs.fn=is.prototype,Hs.invalid=rs;var Ws=Ps(1,"add"),As=Ps(-1,"subtract");function Es(e){return"string"==typeof e||e instanceof String}function Fs(e){return g(e)||l(e)||Es(e)||m(e)||Ns(e)||zs(e)||null==e}function zs(e){var a,t,s=d(e)&&!o(e),n=!1,r=["years","year","y","months","month","M","days","day","d","dates","date","D","hours","hour","h","minutes","minute","m","seconds","second","s","milliseconds","millisecond","ms"],i=r.length;for(a=0;at.valueOf():t.valueOf()9999?U(t,a?"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYYYY-MM-DD[T]HH:mm:ss.SSSZ"):j(Date.prototype.toISOString)?a?this.toDate().toISOString():new Date(this.valueOf()+60*this.utcOffset()*1e3).toISOString().replace("Z",U(t,"Z")):U(t,a?"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYY-MM-DD[T]HH:mm:ss.SSSZ")}function en(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var e,a,t,s,n="moment",r="";return this.isLocal()||(n=0===this.utcOffset()?"moment.utc":"moment.parseZone",r="Z"),e="["+n+'("]',a=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY",t="-MM-DD[T]HH:mm:ss.SSS",s=r+'[")]',this.format(e+a+t+s)}function an(e){e||(e=this.isUtc()?n.defaultFormatUtc:n.defaultFormat);var a=U(this,e);return this.localeData().postformat(a)}function tn(e,a){return this.isValid()&&(g(e)&&e.isValid()||Kt(e).isValid())?Hs({to:this,from:e}).locale(this.locale()).humanize(!a):this.localeData().invalidDate()}function sn(e){return this.from(Kt(),e)}function nn(e,a){return this.isValid()&&(g(e)&&e.isValid()||Kt(e).isValid())?Hs({from:this,to:e}).locale(this.locale()).humanize(!a):this.localeData().invalidDate()}function rn(e){return this.to(Kt(),e)}function dn(e){var a;return void 0===e?this._locale._abbr:(null!=(a=yt(e))&&(this._locale=a),this)}n.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",n.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var _n=v("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",(function(e){return void 0===e?this.localeData():this.locale(e)}));function on(){return this._locale}var un=1e3,mn=60*un,ln=60*mn,Mn=3506328*ln;function hn(e,a){return(e%a+a)%a}function cn(e,a,t){return e<100&&e>=0?new Date(e+400,a,t)-Mn:new Date(e,a,t).valueOf()}function Ln(e,a,t){return e<100&&e>=0?Date.UTC(e+400,a,t)-Mn:Date.UTC(e,a,t)}function Yn(e){var a,t;if(void 0===(e=se(e))||"millisecond"===e||!this.isValid())return this;switch(t=this._isUTC?Ln:cn,e){case"year":a=t(this.year(),0,1);break;case"quarter":a=t(this.year(),this.month()-this.month()%3,1);break;case"month":a=t(this.year(),this.month(),1);break;case"week":a=t(this.year(),this.month(),this.date()-this.weekday());break;case"isoWeek":a=t(this.year(),this.month(),this.date()-(this.isoWeekday()-1));break;case"day":case"date":a=t(this.year(),this.month(),this.date());break;case"hour":a=this._d.valueOf(),a-=hn(a+(this._isUTC?0:this.utcOffset()*mn),ln);break;case"minute":a=this._d.valueOf(),a-=hn(a,mn);break;case"second":a=this._d.valueOf(),a-=hn(a,un)}return this._d.setTime(a),n.updateOffset(this,!0),this}function yn(e){var a,t;if(void 0===(e=se(e))||"millisecond"===e||!this.isValid())return this;switch(t=this._isUTC?Ln:cn,e){case"year":a=t(this.year()+1,0,1)-1;break;case"quarter":a=t(this.year(),this.month()-this.month()%3+3,1)-1;break;case"month":a=t(this.year(),this.month()+1,1)-1;break;case"week":a=t(this.year(),this.month(),this.date()-this.weekday()+7)-1;break;case"isoWeek":a=t(this.year(),this.month(),this.date()-(this.isoWeekday()-1)+7)-1;break;case"day":case"date":a=t(this.year(),this.month(),this.date()+1)-1;break;case"hour":a=this._d.valueOf(),a+=ln-hn(a+(this._isUTC?0:this.utcOffset()*mn),ln)-1;break;case"minute":a=this._d.valueOf(),a+=mn-hn(a,mn)-1;break;case"second":a=this._d.valueOf(),a+=un-hn(a,un)-1}return this._d.setTime(a),n.updateOffset(this,!0),this}function fn(){return this._d.valueOf()-6e4*(this._offset||0)}function kn(){return Math.floor(this.valueOf()/1e3)}function pn(){return new Date(this.valueOf())}function Dn(){var e=this;return[e.year(),e.month(),e.date(),e.hour(),e.minute(),e.second(),e.millisecond()]}function Tn(){var e=this;return{years:e.year(),months:e.month(),date:e.date(),hours:e.hours(),minutes:e.minutes(),seconds:e.seconds(),milliseconds:e.milliseconds()}}function gn(){return this.isValid()?this.toISOString():null}function wn(){return y(this)}function vn(){return h({},Y(this))}function bn(){return Y(this).overflow}function Hn(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}}function Sn(e,a){var t,s,r,i=this._eras||yt("en")._eras;for(t=0,s=i.length;t=0)return _[s]}function xn(e,a){var t=e.since<=e.until?1:-1;return void 0===a?n(e.since).year():n(e.since).year()+(a-e.offset)*t}function Pn(){var e,a,t,s=this.localeData().eras();for(e=0,a=s.length;e(r=ga(e,s,n))&&(a=r),Qn.call(this,e,a,t,s,n))}function Qn(e,a,t,s,n){var r=Da(e,a,t,s,n),i=ka(r.year,0,r.dayOfYear);return this.year(i.getUTCFullYear()),this.month(i.getUTCMonth()),this.date(i.getUTCDate()),this}function Xn(e){return null==e?Math.ceil((this.month()+1)/3):this.month(3*(e-1)+this.month()%3)}R("N",0,0,"eraAbbr"),R("NN",0,0,"eraAbbr"),R("NNN",0,0,"eraAbbr"),R("NNNN",0,0,"eraName"),R("NNNNN",0,0,"eraNarrow"),R("y",["y",1],"yo","eraYear"),R("y",["yy",2],0,"eraYear"),R("y",["yyy",3],0,"eraYear"),R("y",["yyyy",4],0,"eraYear"),be("N",Nn),be("NN",Nn),be("NNN",Nn),be("NNNN",Jn),be("NNNNN",Rn),We(["N","NN","NNN","NNNN","NNNNN"],(function(e,a,t,s){var n=t._locale.erasParse(e,s,t._strict);n?Y(t).era=n:Y(t).invalidEra=e})),be("y",fe),be("yy",fe),be("yyy",fe),be("yyyy",fe),be("yo",Cn),We(["y","yy","yyy","yyyy"],ze),We(["yo"],(function(e,a,t,s){var n;t._locale._eraYearOrdinalRegex&&(n=e.match(t._locale._eraYearOrdinalRegex)),t._locale.eraYearOrdinalParse?a[ze]=t._locale.eraYearOrdinalParse(e,n):a[ze]=parseInt(e,10)})),R(0,["gg",2],0,(function(){return this.weekYear()%100})),R(0,["GG",2],0,(function(){return this.isoWeekYear()%100})),Un("gggg","weekYear"),Un("ggggg","weekYear"),Un("GGGG","isoWeekYear"),Un("GGGGG","isoWeekYear"),be("G",ke),be("g",ke),be("GG",Me,oe),be("gg",Me,oe),be("GGGG",Ye,me),be("gggg",Ye,me),be("GGGGG",ye,le),be("ggggg",ye,le),Ae(["gggg","ggggg","GGGG","GGGGG"],(function(e,a,t,s){a[s.substr(0,2)]=Pe(e)})),Ae(["gg","GG"],(function(e,a,t,s){a[s]=n.parseTwoDigitYear(e)})),R("Q",0,"Qo","quarter"),be("Q",_e),We("Q",(function(e,a){a[Ne]=3*(Pe(e)-1)})),R("D",["DD",2],"Do","date"),be("D",Me,we),be("DD",Me,oe),be("Do",(function(e,a){return e?a._dayOfMonthOrdinalParse||a._ordinalParse:a._dayOfMonthOrdinalParseLenient})),We(["D","DD"],Je),We("Do",(function(e,a){a[Je]=Pe(e.match(Me)[0])}));var er=$e("Date",!0);function ar(e){var a=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==e?a:this.add(e-a,"d")}R("DDD",["DDDD",3],"DDDo","dayOfYear"),be("DDD",Le),be("DDDD",ue),We(["DDD","DDDD"],(function(e,a,t){t._dayOfYear=Pe(e)})),R("m",["mm",2],0,"minute"),be("m",Me,ve),be("mm",Me,oe),We(["m","mm"],Ce);var tr=$e("Minutes",!1);R("s",["ss",2],0,"second"),be("s",Me,ve),be("ss",Me,oe),We(["s","ss"],Ie);var sr,nr,rr=$e("Seconds",!1);for(R("S",0,0,(function(){return~~(this.millisecond()/100)})),R(0,["SS",2],0,(function(){return~~(this.millisecond()/10)})),R(0,["SSS",3],0,"millisecond"),R(0,["SSSS",4],0,(function(){return 10*this.millisecond()})),R(0,["SSSSS",5],0,(function(){return 100*this.millisecond()})),R(0,["SSSSSS",6],0,(function(){return 1e3*this.millisecond()})),R(0,["SSSSSSS",7],0,(function(){return 1e4*this.millisecond()})),R(0,["SSSSSSSS",8],0,(function(){return 1e5*this.millisecond()})),R(0,["SSSSSSSSS",9],0,(function(){return 1e6*this.millisecond()})),be("S",Le,_e),be("SS",Le,oe),be("SSS",Le,ue),sr="SSSS";sr.length<=9;sr+="S")be(sr,fe);function ir(e,a){a[Ue]=Pe(1e3*("0."+e))}for(sr="S";sr.length<=9;sr+="S")We(sr,ir);function dr(){return this._isUTC?"UTC":""}function _r(){return this._isUTC?"Coordinated Universal Time":""}nr=$e("Milliseconds",!1),R("z",0,0,"zoneAbbr"),R("zz",0,0,"zoneName");var or=T.prototype;function ur(e){return Kt(1e3*e)}function mr(){return Kt.apply(null,arguments).parseZone()}function lr(e){return e}or.add=Ws,or.calendar=Cs,or.clone=Is,or.diff=Zs,or.endOf=yn,or.format=an,or.from=tn,or.fromNow=sn,or.to=nn,or.toNow=rn,or.get=ea,or.invalidAt=bn,or.isAfter=Us,or.isBefore=Gs,or.isBetween=Vs,or.isSame=qs,or.isSameOrAfter=Bs,or.isSameOrBefore=Ks,or.isValid=wn,or.lang=_n,or.locale=dn,or.localeData=on,or.max=$t,or.min=Zt,or.parsingFlags=vn,or.set=aa,or.startOf=Yn,or.subtract=As,or.toArray=Dn,or.toObject=Tn,or.toDate=pn,or.toISOString=Xs,or.inspect=en,"undefined"!=typeof Symbol&&null!=Symbol.for&&(or[Symbol.for("nodejs.util.inspect.custom")]=function(){return"Moment<"+this.format()+">"}),or.toJSON=gn,or.toString=Qs,or.unix=kn,or.valueOf=fn,or.creationData=Hn,or.eraName=Pn,or.eraNarrow=On,or.eraAbbr=Wn,or.eraYear=An,or.year=Ke,or.isLeapYear=Ze,or.weekYear=Gn,or.isoWeekYear=Vn,or.quarter=or.quarters=Xn,or.month=ha,or.daysInMonth=ca,or.week=or.weeks=Sa,or.isoWeek=or.isoWeeks=ja,or.weeksInYear=Kn,or.weeksInWeekYear=Zn,or.isoWeeksInYear=qn,or.isoWeeksInISOWeekYear=Bn,or.date=er,or.day=or.days=Ga,or.weekday=Va,or.isoWeekday=qa,or.dayOfYear=ar,or.hour=or.hours=nt,or.minute=or.minutes=tr,or.second=or.seconds=rr,or.millisecond=or.milliseconds=nr,or.utcOffset=cs,or.utc=Ys,or.local=ys,or.parseZone=fs,or.hasAlignedHourOffset=ks,or.isDST=ps,or.isLocal=Ts,or.isUtcOffset=gs,or.isUtc=ws,or.isUTC=ws,or.zoneAbbr=dr,or.zoneName=_r,or.dates=v("dates accessor is deprecated. Use date instead.",er),or.months=v("months accessor is deprecated. Use month instead",ha),or.years=v("years accessor is deprecated. Use year instead",Ke),or.zone=v("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",Ls),or.isDSTShifted=v("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",Ds);var Mr=O.prototype;function hr(e,a,t,s){var n=yt(),r=c().set(s,a);return n[t](r,e)}function cr(e,a,t){if(m(e)&&(a=e,e=void 0),e=e||"",null!=a)return hr(e,a,t,"month");var s,n=[];for(s=0;s<12;s++)n[s]=hr(e,s,t,"month");return n}function Lr(e,a,t,s){"boolean"==typeof e?(m(a)&&(t=a,a=void 0),a=a||""):(t=a=e,e=!1,m(a)&&(t=a,a=void 0),a=a||"");var n,r=yt(),i=e?r._week.dow:0,d=[];if(null!=t)return hr(a,(t+i)%7,s,"day");for(n=0;n<7;n++)d[n]=hr(a,(n+i)%7,s,"day");return d}function Yr(e,a){return cr(e,a,"months")}function yr(e,a){return cr(e,a,"monthsShort")}function fr(e,a,t){return Lr(e,a,t,"weekdays")}function kr(e,a,t){return Lr(e,a,t,"weekdaysShort")}function pr(e,a,t){return Lr(e,a,t,"weekdaysMin")}Mr.calendar=A,Mr.longDateFormat=q,Mr.invalidDate=K,Mr.ordinal=Q,Mr.preparse=lr,Mr.postformat=lr,Mr.relativeTime=ee,Mr.pastFuture=ae,Mr.set=x,Mr.eras=Sn,Mr.erasParse=jn,Mr.erasConvertYear=xn,Mr.erasAbbrRegex=Fn,Mr.erasNameRegex=En,Mr.erasNarrowRegex=zn,Mr.months=oa,Mr.monthsShort=ua,Mr.monthsParse=la,Mr.monthsRegex=Ya,Mr.monthsShortRegex=La,Mr.week=wa,Mr.firstDayOfYear=Ha,Mr.firstDayOfWeek=ba,Mr.weekdays=Ja,Mr.weekdaysMin=Ca,Mr.weekdaysShort=Ra,Mr.weekdaysParse=Ua,Mr.weekdaysRegex=Ba,Mr.weekdaysShortRegex=Ka,Mr.weekdaysMinRegex=Za,Mr.isPM=tt,Mr.meridiem=rt,ct("en",{eras:[{since:"0001-01-01",until:1/0,offset:1,name:"Anno Domini",narrow:"AD",abbr:"AD"},{since:"0000-12-31",until:-1/0,offset:1,name:"Before Christ",narrow:"BC",abbr:"BC"}],dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(e){var a=e%10;return e+(1===Pe(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")}}),n.lang=v("moment.lang is deprecated. Use moment.locale instead.",ct),n.langData=v("moment.langData is deprecated. Use moment.localeData instead.",yt);var Dr=Math.abs;function Tr(){var e=this._data;return this._milliseconds=Dr(this._milliseconds),this._days=Dr(this._days),this._months=Dr(this._months),e.milliseconds=Dr(e.milliseconds),e.seconds=Dr(e.seconds),e.minutes=Dr(e.minutes),e.hours=Dr(e.hours),e.months=Dr(e.months),e.years=Dr(e.years),this}function gr(e,a,t,s){var n=Hs(a,t);return e._milliseconds+=s*n._milliseconds,e._days+=s*n._days,e._months+=s*n._months,e._bubble()}function wr(e,a){return gr(this,e,a,1)}function vr(e,a){return gr(this,e,a,-1)}function br(e){return e<0?Math.floor(e):Math.ceil(e)}function Hr(){var e,a,t,s,n,r=this._milliseconds,i=this._days,d=this._months,_=this._data;return r>=0&&i>=0&&d>=0||r<=0&&i<=0&&d<=0||(r+=864e5*br(jr(d)+i),i=0,d=0),_.milliseconds=r%1e3,e=xe(r/1e3),_.seconds=e%60,a=xe(e/60),_.minutes=a%60,t=xe(a/60),_.hours=t%24,i+=xe(t/24),d+=n=xe(Sr(i)),i-=br(jr(n)),s=xe(d/12),d%=12,_.days=i,_.months=d,_.years=s,this}function Sr(e){return 4800*e/146097}function jr(e){return 146097*e/4800}function xr(e){if(!this.isValid())return NaN;var a,t,s=this._milliseconds;if("month"===(e=se(e))||"quarter"===e||"year"===e)switch(a=this._days+s/864e5,t=this._months+Sr(a),e){case"month":return t;case"quarter":return t/3;case"year":return t/12}else switch(a=this._days+Math.round(jr(this._months)),e){case"week":return a/7+s/6048e5;case"day":return a+s/864e5;case"hour":return 24*a+s/36e5;case"minute":return 1440*a+s/6e4;case"second":return 86400*a+s/1e3;case"millisecond":return Math.floor(864e5*a)+s;default:throw new Error("Unknown unit "+e)}}function Pr(e){return function(){return this.as(e)}}var Or=Pr("ms"),Wr=Pr("s"),Ar=Pr("m"),Er=Pr("h"),Fr=Pr("d"),zr=Pr("w"),Nr=Pr("M"),Jr=Pr("Q"),Rr=Pr("y"),Cr=Or;function Ir(){return Hs(this)}function Ur(e){return e=se(e),this.isValid()?this[e+"s"]():NaN}function Gr(e){return function(){return this.isValid()?this._data[e]:NaN}}var Vr=Gr("milliseconds"),qr=Gr("seconds"),Br=Gr("minutes"),Kr=Gr("hours"),Zr=Gr("days"),$r=Gr("months"),Qr=Gr("years");function Xr(){return xe(this.days()/7)}var ei=Math.round,ai={ss:44,s:45,m:45,h:22,d:26,w:null,M:11};function ti(e,a,t,s,n){return n.relativeTime(a||1,!!t,e,s)}function si(e,a,t,s){var n=Hs(e).abs(),r=ei(n.as("s")),i=ei(n.as("m")),d=ei(n.as("h")),_=ei(n.as("d")),o=ei(n.as("M")),u=ei(n.as("w")),m=ei(n.as("y")),l=r<=t.ss&&["s",r]||r0,l[4]=s,ti.apply(null,l)}function ni(e){return void 0===e?ei:"function"==typeof e&&(ei=e,!0)}function ri(e,a){return void 0!==ai[e]&&(void 0===a?ai[e]:(ai[e]=a,"s"===e&&(ai.ss=a-1),!0))}function ii(e,a){if(!this.isValid())return this.localeData().invalidDate();var t,s,n=!1,r=ai;return"object"==typeof e&&(a=e,e=!1),"boolean"==typeof e&&(n=e),"object"==typeof a&&(r=Object.assign({},ai,a),null!=a.s&&null==a.ss&&(r.ss=a.s-1)),s=si(this,!n,r,t=this.localeData()),n&&(s=t.pastFuture(+this,s)),t.postformat(s)}var di=Math.abs;function _i(e){return(e>0)-(e<0)||+e}function oi(){if(!this.isValid())return this.localeData().invalidDate();var e,a,t,s,n,r,i,d,_=di(this._milliseconds)/1e3,o=di(this._days),u=di(this._months),m=this.asSeconds();return m?(e=xe(_/60),a=xe(e/60),_%=60,e%=60,t=xe(u/12),u%=12,s=_?_.toFixed(3).replace(/\.?0+$/,""):"",n=m<0?"-":"",r=_i(this._months)!==_i(m)?"-":"",i=_i(this._days)!==_i(m)?"-":"",d=_i(this._milliseconds)!==_i(m)?"-":"",n+"P"+(t?r+t+"Y":"")+(u?r+u+"M":"")+(o?i+o+"D":"")+(a||e||_?"T":"")+(a?d+a+"H":"")+(e?d+e+"M":"")+(_?d+s+"S":"")):"P0D"}var ui=is.prototype;return ui.isValid=ns,ui.abs=Tr,ui.add=wr,ui.subtract=vr,ui.as=xr,ui.asMilliseconds=Or,ui.asSeconds=Wr,ui.asMinutes=Ar,ui.asHours=Er,ui.asDays=Fr,ui.asWeeks=zr,ui.asMonths=Nr,ui.asQuarters=Jr,ui.asYears=Rr,ui.valueOf=Cr,ui._bubble=Hr,ui.clone=Ir,ui.get=Ur,ui.milliseconds=Vr,ui.seconds=qr,ui.minutes=Br,ui.hours=Kr,ui.days=Zr,ui.weeks=Xr,ui.months=$r,ui.years=Qr,ui.humanize=ii,ui.toISOString=oi,ui.toString=oi,ui.toJSON=oi,ui.locale=dn,ui.localeData=on,ui.toIsoString=v("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",oi),ui.lang=_n,R("X",0,0,"unix"),R("x",0,0,"valueOf"),be("x",ke),be("X",Te),We("X",(function(e,a,t){t._d=new Date(1e3*parseFloat(e))})),We("x",(function(e,a,t){t._d=new Date(Pe(e))})), +e.defineLocale("zh-tw",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日dddd HH:mm",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,a){return 12===e&&(e=0),"凌晨"===a||"早上"===a||"上午"===a?e:"中午"===a?e>=11?e:e+12:"下午"===a||"晚上"===a?e+12:void 0},meridiem:function(e,a,t){var s=100*e+a;return s<600?"凌晨":s<900?"早上":s<1130?"上午":s<1230?"中午":s<1800?"下午":"晚上"},calendar:{sameDay:"[今天] LT",nextDay:"[明天] LT",nextWeek:"[下]dddd LT",lastDay:"[昨天] LT",lastWeek:"[上]dddd LT",sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|週)/,ordinal:function(e,a){switch(a){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"週";default:return e}},relativeTime:{future:"%s後",past:"%s前",s:"幾秒",ss:"%d 秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}})}(t(5093))},5358(e,a,t){var s={"./af":5177,"./af.js":5177,"./ar":1509,"./ar-dz":1488,"./ar-dz.js":1488,"./ar-kw":8676,"./ar-kw.js":8676,"./ar-ly":2353,"./ar-ly.js":2353,"./ar-ma":4496,"./ar-ma.js":4496,"./ar-ps":6947,"./ar-ps.js":6947,"./ar-sa":2682,"./ar-sa.js":2682,"./ar-tn":9756,"./ar-tn.js":9756,"./ar.js":1509,"./az":5533,"./az.js":5533,"./be":8959,"./be.js":8959,"./bg":7777,"./bg.js":7777,"./bm":4903,"./bm.js":4903,"./bn":1290,"./bn-bd":7357,"./bn-bd.js":7357,"./bn.js":1290,"./bo":1545,"./bo.js":1545,"./br":1470,"./br.js":1470,"./bs":4429,"./bs.js":4429,"./ca":7306,"./ca.js":7306,"./cs":6464,"./cs.js":6464,"./cv":3635,"./cv.js":3635,"./cy":4226,"./cy.js":4226,"./da":3601,"./da.js":3601,"./de":7853,"./de-at":6111,"./de-at.js":6111,"./de-ch":4697,"./de-ch.js":4697,"./de.js":7853,"./dv":708,"./dv.js":708,"./el":4691,"./el.js":4691,"./en-au":3872,"./en-au.js":3872,"./en-ca":8298,"./en-ca.js":8298,"./en-gb":6195,"./en-gb.js":6195,"./en-ie":6584,"./en-ie.js":6584,"./en-il":5543,"./en-il.js":5543,"./en-in":9033,"./en-in.js":9033,"./en-nz":9402,"./en-nz.js":9402,"./en-sg":3004,"./en-sg.js":3004,"./eo":2934,"./eo.js":2934,"./es":7650,"./es-do":838,"./es-do.js":838,"./es-mx":7730,"./es-mx.js":7730,"./es-us":6575,"./es-us.js":6575,"./es.js":7650,"./et":3035,"./et.js":3035,"./eu":3508,"./eu.js":3508,"./fa":119,"./fa.js":119,"./fi":527,"./fi.js":527,"./fil":5995,"./fil.js":5995,"./fo":2477,"./fo.js":2477,"./fr":5498,"./fr-ca":6435,"./fr-ca.js":6435,"./fr-ch":7892,"./fr-ch.js":7892,"./fr.js":5498,"./fy":7071,"./fy.js":7071,"./ga":1734,"./ga.js":1734,"./gd":217,"./gd.js":217,"./gl":7329,"./gl.js":7329,"./gom-deva":2124,"./gom-deva.js":2124,"./gom-latn":3383,"./gom-latn.js":3383,"./gu":5050,"./gu.js":5050,"./he":1713,"./he.js":1713,"./hi":3861,"./hi.js":3861,"./hr":6308,"./hr.js":6308,"./hu":609,"./hu.js":609,"./hy-am":7160,"./hy-am.js":7160,"./id":4063,"./id.js":4063,"./is":9374,"./is.js":9374,"./it":8383,"./it-ch":1827,"./it-ch.js":1827,"./it.js":8383,"./ja":3827,"./ja.js":3827,"./jv":9722,"./jv.js":9722,"./ka":1794,"./ka.js":1794,"./kk":7088,"./kk.js":7088,"./km":6870,"./km.js":6870,"./kn":4451,"./kn.js":4451,"./ko":3164,"./ko.js":3164,"./ku":8174,"./ku-kmr":6181,"./ku-kmr.js":6181,"./ku.js":8174,"./ky":8474,"./ky.js":8474,"./lb":9680,"./lb.js":9680,"./lo":5867,"./lo.js":5867,"./lt":5766,"./lt.js":5766,"./lv":9532,"./lv.js":9532,"./me":8076,"./me.js":8076,"./mi":1848,"./mi.js":1848,"./mk":306,"./mk.js":306,"./ml":3739,"./ml.js":3739,"./mn":9053,"./mn.js":9053,"./mr":6169,"./mr.js":6169,"./ms":3386,"./ms-my":2297,"./ms-my.js":2297,"./ms.js":3386,"./mt":7075,"./mt.js":7075,"./my":2264,"./my.js":2264,"./nb":2274,"./nb.js":2274,"./ne":8235,"./ne.js":8235,"./nl":2572,"./nl-be":3784,"./nl-be.js":3784,"./nl.js":2572,"./nn":4566,"./nn.js":4566,"./oc-lnc":9330,"./oc-lnc.js":9330,"./pa-in":9849,"./pa-in.js":9849,"./pl":4418,"./pl.js":4418,"./pt":9834,"./pt-br":8303,"./pt-br.js":8303,"./pt.js":9834,"./ro":4457,"./ro.js":4457,"./ru":2271,"./ru.js":2271,"./sd":1221,"./sd.js":1221,"./se":3478,"./se.js":3478,"./si":7538,"./si.js":7538,"./sk":5784,"./sk.js":5784,"./sl":6637,"./sl.js":6637,"./sq":6794,"./sq.js":6794,"./sr":5719,"./sr-cyrl":3322,"./sr-cyrl.js":3322,"./sr.js":5719,"./ss":6e3,"./ss.js":6e3,"./sv":1011,"./sv.js":1011,"./sw":748,"./sw.js":748,"./ta":1025,"./ta.js":1025,"./te":1885,"./te.js":1885,"./tet":8861,"./tet.js":8861,"./tg":6571,"./tg.js":6571,"./th":5802,"./th.js":5802,"./tk":9527,"./tk.js":9527,"./tl-ph":9231,"./tl-ph.js":9231,"./tlh":1052,"./tlh.js":1052,"./tr":5096,"./tr.js":5096,"./tzl":9846,"./tzl.js":9846,"./tzm":1765,"./tzm-latn":7711,"./tzm-latn.js":7711,"./tzm.js":1765,"./ug-cn":8414,"./ug-cn.js":8414,"./uk":6618,"./uk.js":6618,"./ur":158,"./ur.js":158,"./uz":7609,"./uz-latn":2475,"./uz-latn.js":2475,"./uz.js":7609,"./vi":1135,"./vi.js":1135,"./x-pseudo":4051,"./x-pseudo.js":4051,"./yo":2218,"./yo.js":2218,"./zh-cn":2648,"./zh-cn.js":2648,"./zh-hk":1632,"./zh-hk.js":1632,"./zh-mo":1541,"./zh-mo.js":1541,"./zh-tw":304,"./zh-tw.js":304};function n(e){var a=r(e);return t(a)}function r(e){if(!t.o(s,e)){var a=new Error("Cannot find module '"+e+"'");throw a.code="MODULE_NOT_FOUND",a}return s[e]}n.keys=function(){return Object.keys(s)},n.resolve=r,e.exports=n,n.id=5358},5093(e,a,t){(e=t.nmd(e)).exports=function(){"use strict";var a,s;function n(){return a.apply(null,arguments)}function r(e){a=e}function d(e){return e instanceof Array||"[object Array]"===Object.prototype.toString.call(e)}function i(e){return null!=e&&"[object Object]"===Object.prototype.toString.call(e)}function _(e,a){return Object.prototype.hasOwnProperty.call(e,a)}function o(e){if(Object.getOwnPropertyNames)return 0===Object.getOwnPropertyNames(e).length;var a;for(a in e)if(_(e,a))return!1;return!0}function m(e){return void 0===e}function u(e){return"number"==typeof e||"[object Number]"===Object.prototype.toString.call(e)}function l(e){return e instanceof Date||"[object Date]"===Object.prototype.toString.call(e)}function M(e,a){var t,s=[],n=e.length;for(t=0;t>>0;for(a=0;a0)for(t=0;t=0?t?"+":"":"-")+Math.pow(10,Math.max(0,n)).toString().substr(1)+s}var F=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,z=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,N={},J={};function R(e,a,t,s){var n=s;"string"==typeof s&&(n=function(){return this[s]()}),e&&(J[e]=n),a&&(J[a[0]]=function(){return E(n.apply(this,arguments),a[1],a[2])}),t&&(J[t]=function(){return this.localeData().ordinal(n.apply(this,arguments),e)})}function C(e){return e.match(/\[[\s\S]/)?e.replace(/^\[|\]$/g,""):e.replace(/\\/g,"")}function I(e){var a,t,s=e.match(F);for(a=0,t=s.length;a=0&&z.test(e);)e=e.replace(z,s),z.lastIndex=0,t-=1;return e}var V={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"};function q(e){var a=this._longDateFormat[e],t=this._longDateFormat[e.toUpperCase()];return a||!t?a:(this._longDateFormat[e]=t.match(F).map((function(e){return"MMMM"===e||"MM"===e||"DD"===e||"dddd"===e?e.slice(1):e})).join(""),this._longDateFormat[e])}var B="Invalid date";function K(){return this._invalidDate}var Z="%d",$=/\d{1,2}/;function Q(e){return this._ordinal.replace("%d",e)}var X={future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"};function ee(e,a,t,s){var n=this._relativeTime[t];return j(n)?n(e,a,t,s):n.replace(/%d/i,e)}function ae(e,a){var t=this._relativeTime[e>0?"future":"past"];return j(t)?t(a):t.replace(/%s/i,a)}var te={D:"date",dates:"date",date:"date",d:"day",days:"day",day:"day",e:"weekday",weekdays:"weekday",weekday:"weekday",E:"isoWeekday",isoweekdays:"isoWeekday",isoweekday:"isoWeekday",DDD:"dayOfYear",dayofyears:"dayOfYear",dayofyear:"dayOfYear",h:"hour",hours:"hour",hour:"hour",ms:"millisecond",milliseconds:"millisecond",millisecond:"millisecond",m:"minute",minutes:"minute",minute:"minute",M:"month",months:"month",month:"month",Q:"quarter",quarters:"quarter",quarter:"quarter",s:"second",seconds:"second",second:"second",gg:"weekYear",weekyears:"weekYear",weekyear:"weekYear",GG:"isoWeekYear",isoweekyears:"isoWeekYear",isoweekyear:"isoWeekYear",w:"week",weeks:"week",week:"week",W:"isoWeek",isoweeks:"isoWeek",isoweek:"isoWeek",y:"year",years:"year",year:"year"};function se(e){return"string"==typeof e?te[e]||te[e.toLowerCase()]:void 0}function ne(e){var a,t,s={};for(t in e)_(e,t)&&(a=se(t))&&(s[a]=e[t]);return s}var re={date:9,day:11,weekday:11,isoWeekday:11,dayOfYear:4,hour:13,millisecond:16,minute:14,month:8,quarter:7,second:15,weekYear:1,isoWeekYear:1,week:5,isoWeek:5,year:1};function de(e){var a,t=[];for(a in e)_(e,a)&&t.push({unit:a,priority:re[a]});return t.sort((function(e,a){return e.priority-a.priority})),t}var ie,_e=/\d/,oe=/\d\d/,me=/\d{3}/,ue=/\d{4}/,le=/[+-]?\d{6}/,Me=/\d\d?/,he=/\d\d\d\d?/,ce=/\d\d\d\d\d\d?/,Le=/\d{1,3}/,Ye=/\d{1,4}/,ye=/[+-]?\d{1,6}/,fe=/\d+/,ke=/[+-]?\d+/,pe=/Z|[+-]\d\d:?\d\d/gi,De=/Z|[+-]\d\d(?::?\d\d)?/gi,Te=/[+-]?\d+(\.\d{1,3})?/,ge=/[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i,we=/^[1-9]\d?/,ve=/^([1-9]\d|\d)/;function be(e,a,t){ie[e]=j(a)?a:function(e,s){return e&&t?t:a}}function He(e,a){return _(ie,e)?ie[e](a._strict,a._locale):new RegExp(Se(e))}function Se(e){return je(e.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,(function(e,a,t,s,n){return a||t||s||n})))}function je(e){return e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function xe(e){return e<0?Math.ceil(e)||0:Math.floor(e)}function Pe(e){var a=+e,t=0;return 0!==a&&isFinite(a)&&(t=xe(a)),t}ie={};var Oe={};function We(e,a){var t,s,n=a;for("string"==typeof e&&(e=[e]),u(a)&&(n=function(e,t){t[a]=Pe(e)}),s=e.length,t=0;t68?1900:2e3)};var Be,Ke=$e("FullYear",!0);function Ze(){return Fe(this.year())}function $e(e,a){return function(t){return null!=t?(Xe(this,e,t),n.updateOffset(this,a),this):Qe(this,e)}}function Qe(e,a){if(!e.isValid())return NaN;var t=e._d,s=e._isUTC;switch(a){case"Milliseconds":return s?t.getUTCMilliseconds():t.getMilliseconds();case"Seconds":return s?t.getUTCSeconds():t.getSeconds();case"Minutes":return s?t.getUTCMinutes():t.getMinutes();case"Hours":return s?t.getUTCHours():t.getHours();case"Date":return s?t.getUTCDate():t.getDate();case"Day":return s?t.getUTCDay():t.getDay();case"Month":return s?t.getUTCMonth():t.getMonth();case"FullYear":return s?t.getUTCFullYear():t.getFullYear();default:return NaN}}function Xe(e,a,t){var s,n,r,d,i;if(e.isValid()&&!isNaN(t)){switch(s=e._d,n=e._isUTC,a){case"Milliseconds":return void(n?s.setUTCMilliseconds(t):s.setMilliseconds(t));case"Seconds":return void(n?s.setUTCSeconds(t):s.setSeconds(t));case"Minutes":return void(n?s.setUTCMinutes(t):s.setMinutes(t));case"Hours":return void(n?s.setUTCHours(t):s.setHours(t));case"Date":return void(n?s.setUTCDate(t):s.setDate(t));case"FullYear":break;default:return}r=t,d=e.month(),i=29!==(i=e.date())||1!==d||Fe(r)?i:28,n?s.setUTCFullYear(r,d,i):s.setFullYear(r,d,i)}}function ea(e){return j(this[e=se(e)])?this[e]():this}function aa(e,a){if("object"==typeof e){var t,s=de(e=ne(e)),n=s.length;for(t=0;t=0?(i=new Date(e+400,a,t,s,n,r,d),isFinite(i.getFullYear())&&i.setFullYear(e)):i=new Date(e,a,t,s,n,r,d),i}function ka(e){var a,t;return e<100&&e>=0?((t=Array.prototype.slice.call(arguments))[0]=e+400,a=new Date(Date.UTC.apply(null,t)),isFinite(a.getUTCFullYear())&&a.setUTCFullYear(e)):a=new Date(Date.UTC.apply(null,arguments)),a}function pa(e,a,t){var s=7+a-t;return-(7+ka(e,0,s).getUTCDay()-a)%7+s-1}function Da(e,a,t,s,n){var r,d,i=1+7*(a-1)+(7+t-s)%7+pa(e,s,n);return i<=0?d=qe(r=e-1)+i:i>qe(e)?(r=e+1,d=i-qe(e)):(r=e,d=i),{year:r,dayOfYear:d}}function Ta(e,a,t){var s,n,r=pa(e.year(),a,t),d=Math.floor((e.dayOfYear()-r-1)/7)+1;return d<1?s=d+ga(n=e.year()-1,a,t):d>ga(e.year(),a,t)?(s=d-ga(e.year(),a,t),n=e.year()+1):(n=e.year(),s=d),{week:s,year:n}}function ga(e,a,t){var s=pa(e,a,t),n=pa(e+1,a,t);return(qe(e)-s+n)/7}function wa(e){return Ta(e,this._week.dow,this._week.doy).week}R("w",["ww",2],"wo","week"),R("W",["WW",2],"Wo","isoWeek"),be("w",Me,we),be("ww",Me,oe),be("W",Me,we),be("WW",Me,oe),Ae(["w","ww","W","WW"],(function(e,a,t,s){a[s.substr(0,1)]=Pe(e)}));var va={dow:0,doy:6};function ba(){return this._week.dow}function Ha(){return this._week.doy}function Sa(e){var a=this.localeData().week(this);return null==e?a:this.add(7*(e-a),"d")}function ja(e){var a=Ta(this,1,4).week;return null==e?a:this.add(7*(e-a),"d")}function xa(e,a){return"string"!=typeof e?e:isNaN(e)?"number"==typeof(e=a.weekdaysParse(e))?e:null:parseInt(e,10)}function Pa(e,a){return"string"==typeof e?a.weekdaysParse(e)%7||7:isNaN(e)?null:e}function Oa(e,a){return e.slice(a,7).concat(e.slice(0,a))}R("d",0,"do","day"),R("dd",0,0,(function(e){return this.localeData().weekdaysMin(this,e)})),R("ddd",0,0,(function(e){return this.localeData().weekdaysShort(this,e)})),R("dddd",0,0,(function(e){return this.localeData().weekdays(this,e)})),R("e",0,0,"weekday"),R("E",0,0,"isoWeekday"),be("d",Me),be("e",Me),be("E",Me),be("dd",(function(e,a){return a.weekdaysMinRegex(e)})),be("ddd",(function(e,a){return a.weekdaysShortRegex(e)})),be("dddd",(function(e,a){return a.weekdaysRegex(e)})),Ae(["dd","ddd","dddd"],(function(e,a,t,s){var n=t._locale.weekdaysParse(e,s,t._strict);null!=n?a.d=n:Y(t).invalidWeekday=e})),Ae(["d","e","E"],(function(e,a,t,s){a[s]=Pe(e)}));var Wa="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Aa="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Ea="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),Fa=ge,za=ge,Na=ge;function Ja(e,a){var t=d(this._weekdays)?this._weekdays:this._weekdays[e&&!0!==e&&this._weekdays.isFormat.test(a)?"format":"standalone"];return!0===e?Oa(t,this._week.dow):e?t[e.day()]:t}function Ra(e){return!0===e?Oa(this._weekdaysShort,this._week.dow):e?this._weekdaysShort[e.day()]:this._weekdaysShort}function Ca(e){return!0===e?Oa(this._weekdaysMin,this._week.dow):e?this._weekdaysMin[e.day()]:this._weekdaysMin}function Ia(e,a,t){var s,n,r,d=e.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],s=0;s<7;++s)r=c([2e3,1]).day(s),this._minWeekdaysParse[s]=this.weekdaysMin(r,"").toLocaleLowerCase(),this._shortWeekdaysParse[s]=this.weekdaysShort(r,"").toLocaleLowerCase(),this._weekdaysParse[s]=this.weekdays(r,"").toLocaleLowerCase();return t?"dddd"===a?-1!==(n=Be.call(this._weekdaysParse,d))?n:null:"ddd"===a?-1!==(n=Be.call(this._shortWeekdaysParse,d))?n:null:-1!==(n=Be.call(this._minWeekdaysParse,d))?n:null:"dddd"===a?-1!==(n=Be.call(this._weekdaysParse,d))||-1!==(n=Be.call(this._shortWeekdaysParse,d))||-1!==(n=Be.call(this._minWeekdaysParse,d))?n:null:"ddd"===a?-1!==(n=Be.call(this._shortWeekdaysParse,d))||-1!==(n=Be.call(this._weekdaysParse,d))||-1!==(n=Be.call(this._minWeekdaysParse,d))?n:null:-1!==(n=Be.call(this._minWeekdaysParse,d))||-1!==(n=Be.call(this._weekdaysParse,d))||-1!==(n=Be.call(this._shortWeekdaysParse,d))?n:null}function Ua(e,a,t){var s,n,r;if(this._weekdaysParseExact)return Ia.call(this,e,a,t);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),s=0;s<7;s++){if(n=c([2e3,1]).day(s),t&&!this._fullWeekdaysParse[s]&&(this._fullWeekdaysParse[s]=new RegExp("^"+this.weekdays(n,"").replace(".","\\.?")+"$","i"),this._shortWeekdaysParse[s]=new RegExp("^"+this.weekdaysShort(n,"").replace(".","\\.?")+"$","i"),this._minWeekdaysParse[s]=new RegExp("^"+this.weekdaysMin(n,"").replace(".","\\.?")+"$","i")),this._weekdaysParse[s]||(r="^"+this.weekdays(n,"")+"|^"+this.weekdaysShort(n,"")+"|^"+this.weekdaysMin(n,""),this._weekdaysParse[s]=new RegExp(r.replace(".",""),"i")),t&&"dddd"===a&&this._fullWeekdaysParse[s].test(e))return s;if(t&&"ddd"===a&&this._shortWeekdaysParse[s].test(e))return s;if(t&&"dd"===a&&this._minWeekdaysParse[s].test(e))return s;if(!t&&this._weekdaysParse[s].test(e))return s}}function Ga(e){if(!this.isValid())return null!=e?this:NaN;var a=Qe(this,"Day");return null!=e?(e=xa(e,this.localeData()),this.add(e-a,"d")):a}function Va(e){if(!this.isValid())return null!=e?this:NaN;var a=(this.day()+7-this.localeData()._week.dow)%7;return null==e?a:this.add(e-a,"d")}function qa(e){if(!this.isValid())return null!=e?this:NaN;if(null!=e){var a=Pa(e,this.localeData());return this.day(this.day()%7?a:a-7)}return this.day()||7}function Ba(e){return this._weekdaysParseExact?(_(this,"_weekdaysRegex")||$a.call(this),e?this._weekdaysStrictRegex:this._weekdaysRegex):(_(this,"_weekdaysRegex")||(this._weekdaysRegex=Fa),this._weekdaysStrictRegex&&e?this._weekdaysStrictRegex:this._weekdaysRegex)}function Ka(e){return this._weekdaysParseExact?(_(this,"_weekdaysRegex")||$a.call(this),e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(_(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=za),this._weekdaysShortStrictRegex&&e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function Za(e){return this._weekdaysParseExact?(_(this,"_weekdaysRegex")||$a.call(this),e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(_(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=Na),this._weekdaysMinStrictRegex&&e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function $a(){function e(e,a){return a.length-e.length}var a,t,s,n,r,d=[],i=[],_=[],o=[];for(a=0;a<7;a++)t=c([2e3,1]).day(a),s=je(this.weekdaysMin(t,"")),n=je(this.weekdaysShort(t,"")),r=je(this.weekdays(t,"")),d.push(s),i.push(n),_.push(r),o.push(s),o.push(n),o.push(r);d.sort(e),i.sort(e),_.sort(e),o.sort(e),this._weekdaysRegex=new RegExp("^("+o.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+_.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+i.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+d.join("|")+")","i")}function Qa(){return this.hours()%12||12}function Xa(){return this.hours()||24}function et(e,a){R(e,0,0,(function(){return this.localeData().meridiem(this.hours(),this.minutes(),a)}))}function at(e,a){return a._meridiemParse}function tt(e){return"p"===(e+"").toLowerCase().charAt(0)}R("H",["HH",2],0,"hour"),R("h",["hh",2],0,Qa),R("k",["kk",2],0,Xa),R("hmm",0,0,(function(){return""+Qa.apply(this)+E(this.minutes(),2)})),R("hmmss",0,0,(function(){return""+Qa.apply(this)+E(this.minutes(),2)+E(this.seconds(),2)})),R("Hmm",0,0,(function(){return""+this.hours()+E(this.minutes(),2)})),R("Hmmss",0,0,(function(){return""+this.hours()+E(this.minutes(),2)+E(this.seconds(),2)})),et("a",!0),et("A",!1),be("a",at),be("A",at),be("H",Me,ve),be("h",Me,we),be("k",Me,we),be("HH",Me,oe),be("hh",Me,oe),be("kk",Me,oe),be("hmm",he),be("hmmss",ce),be("Hmm",he),be("Hmmss",ce),We(["H","HH"],Re),We(["k","kk"],(function(e,a,t){var s=Pe(e);a[Re]=24===s?0:s})),We(["a","A"],(function(e,a,t){t._isPm=t._locale.isPM(e),t._meridiem=e})),We(["h","hh"],(function(e,a,t){a[Re]=Pe(e),Y(t).bigHour=!0})),We("hmm",(function(e,a,t){var s=e.length-2;a[Re]=Pe(e.substr(0,s)),a[Ce]=Pe(e.substr(s)),Y(t).bigHour=!0})),We("hmmss",(function(e,a,t){var s=e.length-4,n=e.length-2;a[Re]=Pe(e.substr(0,s)),a[Ce]=Pe(e.substr(s,2)),a[Ie]=Pe(e.substr(n)),Y(t).bigHour=!0})),We("Hmm",(function(e,a,t){var s=e.length-2;a[Re]=Pe(e.substr(0,s)),a[Ce]=Pe(e.substr(s))})),We("Hmmss",(function(e,a,t){var s=e.length-4,n=e.length-2;a[Re]=Pe(e.substr(0,s)),a[Ce]=Pe(e.substr(s,2)),a[Ie]=Pe(e.substr(n))}));var st=/[ap]\.?m?\.?/i,nt=$e("Hours",!0);function rt(e,a,t){return e>11?t?"pm":"PM":t?"am":"AM"}var dt,it={calendar:W,longDateFormat:V,invalidDate:B,ordinal:Z,dayOfMonthOrdinalParse:$,relativeTime:X,months:na,monthsShort:ra,week:va,weekdays:Wa,weekdaysMin:Ea,weekdaysShort:Aa,meridiemParse:st},_t={},ot={};function mt(e,a){var t,s=Math.min(e.length,a.length);for(t=0;t0;){if(s=ht(n.slice(0,a).join("-")))return s;if(t&&t.length>=a&&mt(n,t)>=a-1)break;a--}r++}return dt}function Mt(e){return!(!e||!e.match("^[^/\\\\]*$"))}function ht(a){var s=null;if(void 0===_t[a]&&e&&e.exports&&Mt(a))try{s=dt._abbr,t(5358)("./"+a),ct(s)}catch(e){_t[a]=null}return _t[a]}function ct(e,a){var t;return e&&((t=m(a)?yt(e):Lt(e,a))?dt=t:"undefined"!=typeof console&&console.warn&&console.warn("Locale "+e+" not found. Did you forget to load it?")),dt._abbr}function Lt(e,a){if(null!==a){var t,s=it;if(a.abbr=e,null!=_t[e])S("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),s=_t[e]._config;else if(null!=a.parentLocale)if(null!=_t[a.parentLocale])s=_t[a.parentLocale]._config;else{if(null==(t=ht(a.parentLocale)))return ot[a.parentLocale]||(ot[a.parentLocale]=[]),ot[a.parentLocale].push({name:e,config:a}),null;s=t._config}return _t[e]=new O(P(s,a)),ot[e]&&ot[e].forEach((function(e){Lt(e.name,e.config)})),ct(e),_t[e]}return delete _t[e],null}function Yt(e,a){if(null!=a){var t,s,n=it;null!=_t[e]&&null!=_t[e].parentLocale?_t[e].set(P(_t[e]._config,a)):(null!=(s=ht(e))&&(n=s._config),a=P(n,a),null==s&&(a.abbr=e),(t=new O(a)).parentLocale=_t[e],_t[e]=t),ct(e)}else null!=_t[e]&&(null!=_t[e].parentLocale?(_t[e]=_t[e].parentLocale,e===ct()&&ct(e)):null!=_t[e]&&delete _t[e]);return _t[e]}function yt(e){var a;if(e&&e._locale&&e._locale._abbr&&(e=e._locale._abbr),!e)return dt;if(!d(e)){if(a=ht(e))return a;e=[e]}return lt(e)}function ft(){return b(_t)}function kt(e){var a,t=e._a;return t&&-2===Y(e).overflow&&(a=t[Ne]<0||t[Ne]>11?Ne:t[Je]<1||t[Je]>sa(t[ze],t[Ne])?Je:t[Re]<0||t[Re]>24||24===t[Re]&&(0!==t[Ce]||0!==t[Ie]||0!==t[Ue])?Re:t[Ce]<0||t[Ce]>59?Ce:t[Ie]<0||t[Ie]>59?Ie:t[Ue]<0||t[Ue]>999?Ue:-1,Y(e)._overflowDayOfYear&&(aJe)&&(a=Je),Y(e)._overflowWeeks&&-1===a&&(a=Ge),Y(e)._overflowWeekday&&-1===a&&(a=Ve),Y(e).overflow=a),e}var pt=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Dt=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Tt=/Z|[+-]\d\d(?::?\d\d)?/,gt=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/],["YYYYMM",/\d{6}/,!1],["YYYY",/\d{4}/,!1]],wt=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],vt=/^\/?Date\((-?\d+)/i,bt=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/,Ht={UT:0,GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};function St(e){var a,t,s,n,r,d,i=e._i,_=pt.exec(i)||Dt.exec(i),o=gt.length,m=wt.length;if(_){for(Y(e).iso=!0,a=0,t=o;aqe(r)||0===e._dayOfYear)&&(Y(e)._overflowDayOfYear=!0),t=ka(r,0,e._dayOfYear),e._a[Ne]=t.getUTCMonth(),e._a[Je]=t.getUTCDate()),a=0;a<3&&null==e._a[a];++a)e._a[a]=d[a]=s[a];for(;a<7;a++)e._a[a]=d[a]=null==e._a[a]?2===a?1:0:e._a[a];24===e._a[Re]&&0===e._a[Ce]&&0===e._a[Ie]&&0===e._a[Ue]&&(e._nextDay=!0,e._a[Re]=0),e._d=(e._useUTC?ka:fa).apply(null,d),n=e._useUTC?e._d.getUTCDay():e._d.getDay(),null!=e._tzm&&e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),e._nextDay&&(e._a[Re]=24),e._w&&void 0!==e._w.d&&e._w.d!==n&&(Y(e).weekdayMismatch=!0)}}function Jt(e){var a,t,s,n,r,d,i,_,o;null!=(a=e._w).GG||null!=a.W||null!=a.E?(r=1,d=4,t=Ft(a.GG,e._a[ze],Ta(Kt(),1,4).year),s=Ft(a.W,1),((n=Ft(a.E,1))<1||n>7)&&(_=!0)):(r=e._locale._week.dow,d=e._locale._week.doy,o=Ta(Kt(),r,d),t=Ft(a.gg,e._a[ze],o.year),s=Ft(a.w,o.week),null!=a.d?((n=a.d)<0||n>6)&&(_=!0):null!=a.e?(n=a.e+r,(a.e<0||a.e>6)&&(_=!0)):n=r),s<1||s>ga(t,r,d)?Y(e)._overflowWeeks=!0:null!=_?Y(e)._overflowWeekday=!0:(i=Da(t,s,n,r,d),e._a[ze]=i.year,e._dayOfYear=i.dayOfYear)}function Rt(e){if(e._f!==n.ISO_8601)if(e._f!==n.RFC_2822){e._a=[],Y(e).empty=!0;var a,t,s,r,d,i,_,o=""+e._i,m=o.length,u=0;for(_=(s=G(e._f,e._locale).match(F)||[]).length,a=0;a<_;a++)r=s[a],(t=(o.match(He(r,e))||[])[0])&&((d=o.substr(0,o.indexOf(t))).length>0&&Y(e).unusedInput.push(d),o=o.slice(o.indexOf(t)+t.length),u+=t.length),J[r]?(t?Y(e).empty=!1:Y(e).unusedTokens.push(r),Ee(r,t,e)):e._strict&&!t&&Y(e).unusedTokens.push(r);Y(e).charsLeftOver=m-u,o.length>0&&Y(e).unusedInput.push(o),e._a[Re]<=12&&!0===Y(e).bigHour&&e._a[Re]>0&&(Y(e).bigHour=void 0),Y(e).parsedDateParts=e._a.slice(0),Y(e).meridiem=e._meridiem,e._a[Re]=Ct(e._locale,e._a[Re],e._meridiem),null!==(i=Y(e).era)&&(e._a[ze]=e._locale.erasConvertYear(i,e._a[ze])),Nt(e),kt(e)}else At(e);else St(e)}function Ct(e,a,t){var s;return null==t?a:null!=e.meridiemHour?e.meridiemHour(a,t):null!=e.isPM?((s=e.isPM(t))&&a<12&&(a+=12),s||12!==a||(a=0),a):a}function It(e){var a,t,s,n,r,d,i=!1,_=e._f.length;if(0===_)return Y(e).invalidFormat=!0,void(e._d=new Date(NaN));for(n=0;n<_;n++)r=0,d=!1,a=D({},e),null!=e._useUTC&&(a._useUTC=e._useUTC),a._f=e._f[n],Rt(a),y(a)&&(d=!0),r+=Y(a).charsLeftOver,r+=10*Y(a).unusedTokens.length,Y(a).score=r,i?rthis?this:e:f()}));function Qt(e,a){var t,s;if(1===a.length&&d(a[0])&&(a=a[0]),!a.length)return Kt();for(t=a[0],s=1;sthis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Ds(){if(!m(this._isDSTShifted))return this._isDSTShifted;var e,a={};return D(a,this),(a=Vt(a))._a?(e=a._isUTC?c(a._a):Kt(a._a),this._isDSTShifted=this.isValid()&&os(a._a,e.toArray())>0):this._isDSTShifted=!1,this._isDSTShifted}function Ts(){return!!this.isValid()&&!this._isUTC}function gs(){return!!this.isValid()&&this._isUTC}function ws(){return!!this.isValid()&&this._isUTC&&0===this._offset}n.updateOffset=function(){};var vs=/^(-|\+)?(?:(\d*)[. ])?(\d+):(\d+)(?::(\d+)(\.\d*)?)?$/,bs=/^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;function Hs(e,a){var t,s,n,r=e,d=null;return is(e)?r={ms:e._milliseconds,d:e._days,M:e._months}:u(e)||!isNaN(+e)?(r={},a?r[a]=+e:r.milliseconds=+e):(d=vs.exec(e))?(t="-"===d[1]?-1:1,r={y:0,d:Pe(d[Je])*t,h:Pe(d[Re])*t,m:Pe(d[Ce])*t,s:Pe(d[Ie])*t,ms:Pe(_s(1e3*d[Ue]))*t}):(d=bs.exec(e))?(t="-"===d[1]?-1:1,r={y:Ss(d[2],t),M:Ss(d[3],t),w:Ss(d[4],t),d:Ss(d[5],t),h:Ss(d[6],t),m:Ss(d[7],t),s:Ss(d[8],t)}):null==r?r={}:"object"==typeof r&&("from"in r||"to"in r)&&(n=xs(Kt(r.from),Kt(r.to)),(r={}).ms=n.milliseconds,r.M=n.months),s=new ds(r),is(e)&&_(e,"_locale")&&(s._locale=e._locale),is(e)&&_(e,"_isValid")&&(s._isValid=e._isValid),s}function Ss(e,a){var t=e&&parseFloat(e.replace(",","."));return(isNaN(t)?0:t)*a}function js(e,a){var t={};return t.months=a.month()-e.month()+12*(a.year()-e.year()),e.clone().add(t.months,"M").isAfter(a)&&--t.months,t.milliseconds=+a-+e.clone().add(t.months,"M"),t}function xs(e,a){var t;return e.isValid()&&a.isValid()?(a=Ms(a,e),e.isBefore(a)?t=js(e,a):((t=js(a,e)).milliseconds=-t.milliseconds,t.months=-t.months),t):{milliseconds:0,months:0}}function Ps(e,a){return function(t,s){var n;return null===s||isNaN(+s)||(S(a,"moment()."+a+"(period, number) is deprecated. Please use moment()."+a+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),n=t,t=s,s=n),Os(this,Hs(t,s),e),this}}function Os(e,a,t,s){var r=a._milliseconds,d=_s(a._days),i=_s(a._months);e.isValid()&&(s=s??!0,i&&Ma(e,Qe(e,"Month")+i*t),d&&Xe(e,"Date",Qe(e,"Date")+d*t),r&&e._d.setTime(e._d.valueOf()+r*t),s&&n.updateOffset(e,d||i))}Hs.fn=ds.prototype,Hs.invalid=rs;var Ws=Ps(1,"add"),As=Ps(-1,"subtract");function Es(e){return"string"==typeof e||e instanceof String}function Fs(e){return g(e)||l(e)||Es(e)||u(e)||Ns(e)||zs(e)||null==e}function zs(e){var a,t,s=i(e)&&!o(e),n=!1,r=["years","year","y","months","month","M","days","day","d","dates","date","D","hours","hour","h","minutes","minute","m","seconds","second","s","milliseconds","millisecond","ms"],d=r.length;for(a=0;at.valueOf():t.valueOf()9999?U(t,a?"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYYYY-MM-DD[T]HH:mm:ss.SSSZ"):j(Date.prototype.toISOString)?a?this.toDate().toISOString():new Date(this.valueOf()+60*this.utcOffset()*1e3).toISOString().replace("Z",U(t,"Z")):U(t,a?"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYY-MM-DD[T]HH:mm:ss.SSSZ")}function en(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var e,a,t,s,n="moment",r="";return this.isLocal()||(n=0===this.utcOffset()?"moment.utc":"moment.parseZone",r="Z"),e="["+n+'("]',a=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY",t="-MM-DD[T]HH:mm:ss.SSS",s=r+'[")]',this.format(e+a+t+s)}function an(e){e||(e=this.isUtc()?n.defaultFormatUtc:n.defaultFormat);var a=U(this,e);return this.localeData().postformat(a)}function tn(e,a){return this.isValid()&&(g(e)&&e.isValid()||Kt(e).isValid())?Hs({to:this,from:e}).locale(this.locale()).humanize(!a):this.localeData().invalidDate()}function sn(e){return this.from(Kt(),e)}function nn(e,a){return this.isValid()&&(g(e)&&e.isValid()||Kt(e).isValid())?Hs({from:this,to:e}).locale(this.locale()).humanize(!a):this.localeData().invalidDate()}function rn(e){return this.to(Kt(),e)}function dn(e){var a;return void 0===e?this._locale._abbr:(null!=(a=yt(e))&&(this._locale=a),this)}n.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",n.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var _n=v("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",(function(e){return void 0===e?this.localeData():this.locale(e)}));function on(){return this._locale}var mn=1e3,un=60*mn,ln=60*un,Mn=3506328*ln;function hn(e,a){return(e%a+a)%a}function cn(e,a,t){return e<100&&e>=0?new Date(e+400,a,t)-Mn:new Date(e,a,t).valueOf()}function Ln(e,a,t){return e<100&&e>=0?Date.UTC(e+400,a,t)-Mn:Date.UTC(e,a,t)}function Yn(e){var a,t;if(void 0===(e=se(e))||"millisecond"===e||!this.isValid())return this;switch(t=this._isUTC?Ln:cn,e){case"year":a=t(this.year(),0,1);break;case"quarter":a=t(this.year(),this.month()-this.month()%3,1);break;case"month":a=t(this.year(),this.month(),1);break;case"week":a=t(this.year(),this.month(),this.date()-this.weekday());break;case"isoWeek":a=t(this.year(),this.month(),this.date()-(this.isoWeekday()-1));break;case"day":case"date":a=t(this.year(),this.month(),this.date());break;case"hour":a=this._d.valueOf(),a-=hn(a+(this._isUTC?0:this.utcOffset()*un),ln);break;case"minute":a=this._d.valueOf(),a-=hn(a,un);break;case"second":a=this._d.valueOf(),a-=hn(a,mn)}return this._d.setTime(a),n.updateOffset(this,!0),this}function yn(e){var a,t;if(void 0===(e=se(e))||"millisecond"===e||!this.isValid())return this;switch(t=this._isUTC?Ln:cn,e){case"year":a=t(this.year()+1,0,1)-1;break;case"quarter":a=t(this.year(),this.month()-this.month()%3+3,1)-1;break;case"month":a=t(this.year(),this.month()+1,1)-1;break;case"week":a=t(this.year(),this.month(),this.date()-this.weekday()+7)-1;break;case"isoWeek":a=t(this.year(),this.month(),this.date()-(this.isoWeekday()-1)+7)-1;break;case"day":case"date":a=t(this.year(),this.month(),this.date()+1)-1;break;case"hour":a=this._d.valueOf(),a+=ln-hn(a+(this._isUTC?0:this.utcOffset()*un),ln)-1;break;case"minute":a=this._d.valueOf(),a+=un-hn(a,un)-1;break;case"second":a=this._d.valueOf(),a+=mn-hn(a,mn)-1}return this._d.setTime(a),n.updateOffset(this,!0),this}function fn(){return this._d.valueOf()-6e4*(this._offset||0)}function kn(){return Math.floor(this.valueOf()/1e3)}function pn(){return new Date(this.valueOf())}function Dn(){var e=this;return[e.year(),e.month(),e.date(),e.hour(),e.minute(),e.second(),e.millisecond()]}function Tn(){var e=this;return{years:e.year(),months:e.month(),date:e.date(),hours:e.hours(),minutes:e.minutes(),seconds:e.seconds(),milliseconds:e.milliseconds()}}function gn(){return this.isValid()?this.toISOString():null}function wn(){return y(this)}function vn(){return h({},Y(this))}function bn(){return Y(this).overflow}function Hn(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}}function Sn(e,a){var t,s,r,d=this._eras||yt("en")._eras;for(t=0,s=d.length;t=0)return _[s]}function xn(e,a){var t=e.since<=e.until?1:-1;return void 0===a?n(e.since).year():n(e.since).year()+(a-e.offset)*t}function Pn(){var e,a,t,s=this.localeData().eras();for(e=0,a=s.length;e(r=ga(e,s,n))&&(a=r),Qn.call(this,e,a,t,s,n))}function Qn(e,a,t,s,n){var r=Da(e,a,t,s,n),d=ka(r.year,0,r.dayOfYear);return this.year(d.getUTCFullYear()),this.month(d.getUTCMonth()),this.date(d.getUTCDate()),this}function Xn(e){return null==e?Math.ceil((this.month()+1)/3):this.month(3*(e-1)+this.month()%3)}R("N",0,0,"eraAbbr"),R("NN",0,0,"eraAbbr"),R("NNN",0,0,"eraAbbr"),R("NNNN",0,0,"eraName"),R("NNNNN",0,0,"eraNarrow"),R("y",["y",1],"yo","eraYear"),R("y",["yy",2],0,"eraYear"),R("y",["yyy",3],0,"eraYear"),R("y",["yyyy",4],0,"eraYear"),be("N",Nn),be("NN",Nn),be("NNN",Nn),be("NNNN",Jn),be("NNNNN",Rn),We(["N","NN","NNN","NNNN","NNNNN"],(function(e,a,t,s){var n=t._locale.erasParse(e,s,t._strict);n?Y(t).era=n:Y(t).invalidEra=e})),be("y",fe),be("yy",fe),be("yyy",fe),be("yyyy",fe),be("yo",Cn),We(["y","yy","yyy","yyyy"],ze),We(["yo"],(function(e,a,t,s){var n;t._locale._eraYearOrdinalRegex&&(n=e.match(t._locale._eraYearOrdinalRegex)),t._locale.eraYearOrdinalParse?a[ze]=t._locale.eraYearOrdinalParse(e,n):a[ze]=parseInt(e,10)})),R(0,["gg",2],0,(function(){return this.weekYear()%100})),R(0,["GG",2],0,(function(){return this.isoWeekYear()%100})),Un("gggg","weekYear"),Un("ggggg","weekYear"),Un("GGGG","isoWeekYear"),Un("GGGGG","isoWeekYear"),be("G",ke),be("g",ke),be("GG",Me,oe),be("gg",Me,oe),be("GGGG",Ye,ue),be("gggg",Ye,ue),be("GGGGG",ye,le),be("ggggg",ye,le),Ae(["gggg","ggggg","GGGG","GGGGG"],(function(e,a,t,s){a[s.substr(0,2)]=Pe(e)})),Ae(["gg","GG"],(function(e,a,t,s){a[s]=n.parseTwoDigitYear(e)})),R("Q",0,"Qo","quarter"),be("Q",_e),We("Q",(function(e,a){a[Ne]=3*(Pe(e)-1)})),R("D",["DD",2],"Do","date"),be("D",Me,we),be("DD",Me,oe),be("Do",(function(e,a){return e?a._dayOfMonthOrdinalParse||a._ordinalParse:a._dayOfMonthOrdinalParseLenient})),We(["D","DD"],Je),We("Do",(function(e,a){a[Je]=Pe(e.match(Me)[0])}));var er=$e("Date",!0);function ar(e){var a=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==e?a:this.add(e-a,"d")}R("DDD",["DDDD",3],"DDDo","dayOfYear"),be("DDD",Le),be("DDDD",me),We(["DDD","DDDD"],(function(e,a,t){t._dayOfYear=Pe(e)})),R("m",["mm",2],0,"minute"),be("m",Me,ve),be("mm",Me,oe),We(["m","mm"],Ce);var tr=$e("Minutes",!1);R("s",["ss",2],0,"second"),be("s",Me,ve),be("ss",Me,oe),We(["s","ss"],Ie);var sr,nr,rr=$e("Seconds",!1);for(R("S",0,0,(function(){return~~(this.millisecond()/100)})),R(0,["SS",2],0,(function(){return~~(this.millisecond()/10)})),R(0,["SSS",3],0,"millisecond"),R(0,["SSSS",4],0,(function(){return 10*this.millisecond()})),R(0,["SSSSS",5],0,(function(){return 100*this.millisecond()})),R(0,["SSSSSS",6],0,(function(){return 1e3*this.millisecond()})),R(0,["SSSSSSS",7],0,(function(){return 1e4*this.millisecond()})),R(0,["SSSSSSSS",8],0,(function(){return 1e5*this.millisecond()})),R(0,["SSSSSSSSS",9],0,(function(){return 1e6*this.millisecond()})),be("S",Le,_e),be("SS",Le,oe),be("SSS",Le,me),sr="SSSS";sr.length<=9;sr+="S")be(sr,fe);function dr(e,a){a[Ue]=Pe(1e3*("0."+e))}for(sr="S";sr.length<=9;sr+="S")We(sr,dr);function ir(){return this._isUTC?"UTC":""}function _r(){return this._isUTC?"Coordinated Universal Time":""}nr=$e("Milliseconds",!1),R("z",0,0,"zoneAbbr"),R("zz",0,0,"zoneName");var or=T.prototype;function mr(e){return Kt(1e3*e)}function ur(){return Kt.apply(null,arguments).parseZone()}function lr(e){return e}or.add=Ws,or.calendar=Cs,or.clone=Is,or.diff=Zs,or.endOf=yn,or.format=an,or.from=tn,or.fromNow=sn,or.to=nn,or.toNow=rn,or.get=ea,or.invalidAt=bn,or.isAfter=Us,or.isBefore=Gs,or.isBetween=Vs,or.isSame=qs,or.isSameOrAfter=Bs,or.isSameOrBefore=Ks,or.isValid=wn,or.lang=_n,or.locale=dn,or.localeData=on,or.max=$t,or.min=Zt,or.parsingFlags=vn,or.set=aa,or.startOf=Yn,or.subtract=As,or.toArray=Dn,or.toObject=Tn,or.toDate=pn,or.toISOString=Xs,or.inspect=en,"undefined"!=typeof Symbol&&null!=Symbol.for&&(or[Symbol.for("nodejs.util.inspect.custom")]=function(){return"Moment<"+this.format()+">"}),or.toJSON=gn,or.toString=Qs,or.unix=kn,or.valueOf=fn,or.creationData=Hn,or.eraName=Pn,or.eraNarrow=On,or.eraAbbr=Wn,or.eraYear=An,or.year=Ke,or.isLeapYear=Ze,or.weekYear=Gn,or.isoWeekYear=Vn,or.quarter=or.quarters=Xn,or.month=ha,or.daysInMonth=ca,or.week=or.weeks=Sa,or.isoWeek=or.isoWeeks=ja,or.weeksInYear=Kn,or.weeksInWeekYear=Zn,or.isoWeeksInYear=qn,or.isoWeeksInISOWeekYear=Bn,or.date=er,or.day=or.days=Ga,or.weekday=Va,or.isoWeekday=qa,or.dayOfYear=ar,or.hour=or.hours=nt,or.minute=or.minutes=tr,or.second=or.seconds=rr,or.millisecond=or.milliseconds=nr,or.utcOffset=cs,or.utc=Ys,or.local=ys,or.parseZone=fs,or.hasAlignedHourOffset=ks,or.isDST=ps,or.isLocal=Ts,or.isUtcOffset=gs,or.isUtc=ws,or.isUTC=ws,or.zoneAbbr=ir,or.zoneName=_r,or.dates=v("dates accessor is deprecated. Use date instead.",er),or.months=v("months accessor is deprecated. Use month instead",ha),or.years=v("years accessor is deprecated. Use year instead",Ke),or.zone=v("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",Ls),or.isDSTShifted=v("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",Ds);var Mr=O.prototype;function hr(e,a,t,s){var n=yt(),r=c().set(s,a);return n[t](r,e)}function cr(e,a,t){if(u(e)&&(a=e,e=void 0),e=e||"",null!=a)return hr(e,a,t,"month");var s,n=[];for(s=0;s<12;s++)n[s]=hr(e,s,t,"month");return n}function Lr(e,a,t,s){"boolean"==typeof e?(u(a)&&(t=a,a=void 0),a=a||""):(t=a=e,e=!1,u(a)&&(t=a,a=void 0),a=a||"");var n,r=yt(),d=e?r._week.dow:0,i=[];if(null!=t)return hr(a,(t+d)%7,s,"day");for(n=0;n<7;n++)i[n]=hr(a,(n+d)%7,s,"day");return i}function Yr(e,a){return cr(e,a,"months")}function yr(e,a){return cr(e,a,"monthsShort")}function fr(e,a,t){return Lr(e,a,t,"weekdays")}function kr(e,a,t){return Lr(e,a,t,"weekdaysShort")}function pr(e,a,t){return Lr(e,a,t,"weekdaysMin")}Mr.calendar=A,Mr.longDateFormat=q,Mr.invalidDate=K,Mr.ordinal=Q,Mr.preparse=lr,Mr.postformat=lr,Mr.relativeTime=ee,Mr.pastFuture=ae,Mr.set=x,Mr.eras=Sn,Mr.erasParse=jn,Mr.erasConvertYear=xn,Mr.erasAbbrRegex=Fn,Mr.erasNameRegex=En,Mr.erasNarrowRegex=zn,Mr.months=oa,Mr.monthsShort=ma,Mr.monthsParse=la,Mr.monthsRegex=Ya,Mr.monthsShortRegex=La,Mr.week=wa,Mr.firstDayOfYear=Ha,Mr.firstDayOfWeek=ba,Mr.weekdays=Ja,Mr.weekdaysMin=Ca,Mr.weekdaysShort=Ra,Mr.weekdaysParse=Ua,Mr.weekdaysRegex=Ba,Mr.weekdaysShortRegex=Ka,Mr.weekdaysMinRegex=Za,Mr.isPM=tt,Mr.meridiem=rt,ct("en",{eras:[{since:"0001-01-01",until:1/0,offset:1,name:"Anno Domini",narrow:"AD",abbr:"AD"},{since:"0000-12-31",until:-1/0,offset:1,name:"Before Christ",narrow:"BC",abbr:"BC"}],dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(e){var a=e%10;return e+(1===Pe(e%100/10)?"th":1===a?"st":2===a?"nd":3===a?"rd":"th")}}),n.lang=v("moment.lang is deprecated. Use moment.locale instead.",ct),n.langData=v("moment.langData is deprecated. Use moment.localeData instead.",yt);var Dr=Math.abs;function Tr(){var e=this._data;return this._milliseconds=Dr(this._milliseconds),this._days=Dr(this._days),this._months=Dr(this._months),e.milliseconds=Dr(e.milliseconds),e.seconds=Dr(e.seconds),e.minutes=Dr(e.minutes),e.hours=Dr(e.hours),e.months=Dr(e.months),e.years=Dr(e.years),this}function gr(e,a,t,s){var n=Hs(a,t);return e._milliseconds+=s*n._milliseconds,e._days+=s*n._days,e._months+=s*n._months,e._bubble()}function wr(e,a){return gr(this,e,a,1)}function vr(e,a){return gr(this,e,a,-1)}function br(e){return e<0?Math.floor(e):Math.ceil(e)}function Hr(){var e,a,t,s,n,r=this._milliseconds,d=this._days,i=this._months,_=this._data;return r>=0&&d>=0&&i>=0||r<=0&&d<=0&&i<=0||(r+=864e5*br(jr(i)+d),d=0,i=0),_.milliseconds=r%1e3,e=xe(r/1e3),_.seconds=e%60,a=xe(e/60),_.minutes=a%60,t=xe(a/60),_.hours=t%24,d+=xe(t/24),i+=n=xe(Sr(d)),d-=br(jr(n)),s=xe(i/12),i%=12,_.days=d,_.months=i,_.years=s,this}function Sr(e){return 4800*e/146097}function jr(e){return 146097*e/4800}function xr(e){if(!this.isValid())return NaN;var a,t,s=this._milliseconds;if("month"===(e=se(e))||"quarter"===e||"year"===e)switch(a=this._days+s/864e5,t=this._months+Sr(a),e){case"month":return t;case"quarter":return t/3;case"year":return t/12}else switch(a=this._days+Math.round(jr(this._months)),e){case"week":return a/7+s/6048e5;case"day":return a+s/864e5;case"hour":return 24*a+s/36e5;case"minute":return 1440*a+s/6e4;case"second":return 86400*a+s/1e3;case"millisecond":return Math.floor(864e5*a)+s;default:throw new Error("Unknown unit "+e)}}function Pr(e){return function(){return this.as(e)}}var Or=Pr("ms"),Wr=Pr("s"),Ar=Pr("m"),Er=Pr("h"),Fr=Pr("d"),zr=Pr("w"),Nr=Pr("M"),Jr=Pr("Q"),Rr=Pr("y"),Cr=Or;function Ir(){return Hs(this)}function Ur(e){return e=se(e),this.isValid()?this[e+"s"]():NaN}function Gr(e){return function(){return this.isValid()?this._data[e]:NaN}}var Vr=Gr("milliseconds"),qr=Gr("seconds"),Br=Gr("minutes"),Kr=Gr("hours"),Zr=Gr("days"),$r=Gr("months"),Qr=Gr("years");function Xr(){return xe(this.days()/7)}var ed=Math.round,ad={ss:44,s:45,m:45,h:22,d:26,w:null,M:11};function td(e,a,t,s,n){return n.relativeTime(a||1,!!t,e,s)}function sd(e,a,t,s){var n=Hs(e).abs(),r=ed(n.as("s")),d=ed(n.as("m")),i=ed(n.as("h")),_=ed(n.as("d")),o=ed(n.as("M")),m=ed(n.as("w")),u=ed(n.as("y")),l=r<=t.ss&&["s",r]||r0,l[4]=s,td.apply(null,l)}function nd(e){return void 0===e?ed:"function"==typeof e&&(ed=e,!0)}function rd(e,a){return void 0!==ad[e]&&(void 0===a?ad[e]:(ad[e]=a,"s"===e&&(ad.ss=a-1),!0))}function dd(e,a){if(!this.isValid())return this.localeData().invalidDate();var t,s,n=!1,r=ad;return"object"==typeof e&&(a=e,e=!1),"boolean"==typeof e&&(n=e),"object"==typeof a&&(r=Object.assign({},ad,a),null!=a.s&&null==a.ss&&(r.ss=a.s-1)),s=sd(this,!n,r,t=this.localeData()),n&&(s=t.pastFuture(+this,s)),t.postformat(s)}var id=Math.abs;function _d(e){return(e>0)-(e<0)||+e}function od(){if(!this.isValid())return this.localeData().invalidDate();var e,a,t,s,n,r,d,i,_=id(this._milliseconds)/1e3,o=id(this._days),m=id(this._months),u=this.asSeconds();return u?(e=xe(_/60),a=xe(e/60),_%=60,e%=60,t=xe(m/12),m%=12,s=_?_.toFixed(3).replace(/\.?0+$/,""):"",n=u<0?"-":"",r=_d(this._months)!==_d(u)?"-":"",d=_d(this._days)!==_d(u)?"-":"",i=_d(this._milliseconds)!==_d(u)?"-":"",n+"P"+(t?r+t+"Y":"")+(m?r+m+"M":"")+(o?d+o+"D":"")+(a||e||_?"T":"")+(a?i+a+"H":"")+(e?i+e+"M":"")+(_?i+s+"S":"")):"P0D"}var md=ds.prototype;return md.isValid=ns,md.abs=Tr,md.add=wr,md.subtract=vr,md.as=xr,md.asMilliseconds=Or,md.asSeconds=Wr,md.asMinutes=Ar,md.asHours=Er,md.asDays=Fr,md.asWeeks=zr,md.asMonths=Nr,md.asQuarters=Jr,md.asYears=Rr,md.valueOf=Cr,md._bubble=Hr,md.clone=Ir,md.get=Ur,md.milliseconds=Vr,md.seconds=qr,md.minutes=Br,md.hours=Kr,md.days=Zr,md.weeks=Xr,md.months=$r,md.years=Qr,md.humanize=dd,md.toISOString=od,md.toString=od,md.toJSON=od,md.locale=dn,md.localeData=on,md.toIsoString=v("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",od),md.lang=_n,R("X",0,0,"unix"),R("x",0,0,"valueOf"),be("x",ke),be("X",Te),We("X",(function(e,a,t){t._d=new Date(1e3*parseFloat(e))})),We("x",(function(e,a,t){t._d=new Date(Pe(e))})), //! moment.js -n.version="2.30.1",r(Kt),n.fn=or,n.min=Xt,n.max=es,n.now=as,n.utc=c,n.unix=ur,n.months=Yr,n.isDate=l,n.locale=ct,n.invalid=f,n.duration=Hs,n.isMoment=g,n.weekdays=fr,n.parseZone=mr,n.localeData=yt,n.isDuration=ds,n.monthsShort=yr,n.weekdaysMin=pr,n.defineLocale=Lt,n.updateLocale=Yt,n.locales=ft,n.weekdaysShort=kr,n.normalizeUnits=se,n.relativeTimeRounding=ni,n.relativeTimeThreshold=ri,n.calendarFormat=Rs,n.prototype=or,n.HTML5_FMT={DATETIME_LOCAL:"YYYY-MM-DDTHH:mm",DATETIME_LOCAL_SECONDS:"YYYY-MM-DDTHH:mm:ss",DATETIME_LOCAL_MS:"YYYY-MM-DDTHH:mm:ss.SSS",DATE:"YYYY-MM-DD",TIME:"HH:mm",TIME_SECONDS:"HH:mm:ss",TIME_MS:"HH:mm:ss.SSS",WEEK:"GGGG-[W]WW",MONTH:"YYYY-MM"},n}()},5946:(e,a,t)=>{e.exports=t(5093)}},a={};function t(s){var n=a[s];if(void 0!==n)return n.exports;var r=a[s]={id:s,loaded:!1,exports:{}};return e[s].call(r.exports,r,r.exports,t),r.loaded=!0,r.exports}return t.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),t.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),t(5946)})())); \ No newline at end of file +n.version="2.30.1",r(Kt),n.fn=or,n.min=Xt,n.max=es,n.now=as,n.utc=c,n.unix=mr,n.months=Yr,n.isDate=l,n.locale=ct,n.invalid=f,n.duration=Hs,n.isMoment=g,n.weekdays=fr,n.parseZone=ur,n.localeData=yt,n.isDuration=is,n.monthsShort=yr,n.weekdaysMin=pr,n.defineLocale=Lt,n.updateLocale=Yt,n.locales=ft,n.weekdaysShort=kr,n.normalizeUnits=se,n.relativeTimeRounding=nd,n.relativeTimeThreshold=rd,n.calendarFormat=Rs,n.prototype=or,n.HTML5_FMT={DATETIME_LOCAL:"YYYY-MM-DDTHH:mm",DATETIME_LOCAL_SECONDS:"YYYY-MM-DDTHH:mm:ss",DATETIME_LOCAL_MS:"YYYY-MM-DDTHH:mm:ss.SSS",DATE:"YYYY-MM-DD",TIME:"HH:mm",TIME_SECONDS:"HH:mm:ss",TIME_MS:"HH:mm:ss.SSS",WEEK:"GGGG-[W]WW",MONTH:"YYYY-MM"},n}()},5946(e,a,t){e.exports=t(5093)}},a={};function t(s){var n=a[s];if(void 0!==n)return n.exports;var r=a[s]={id:s,loaded:!1,exports:{}};return e[s].call(r.exports,r,r.exports,t),r.loaded=!0,r.exports}return t.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),t.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),t(5946)})())); \ No newline at end of file diff --git a/src/modules/Elsa.Expressions.JavaScript.Libraries/ClientLib/package-lock.json b/src/modules/Elsa.Expressions.JavaScript.Libraries/ClientLib/package-lock.json index 71fe669cc..b67190b2a 100644 --- a/src/modules/Elsa.Expressions.JavaScript.Libraries/ClientLib/package-lock.json +++ b/src/modules/Elsa.Expressions.JavaScript.Libraries/ClientLib/package-lock.json @@ -84,16 +84,18 @@ } }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { "version": "22.7.4", @@ -105,148 +107,163 @@ } }, "node_modules/@webassemblyjs/ast": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", - "dev": true + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", - "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "dev": true, + "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", - "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", - "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", - "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", - "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", - "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, @@ -298,19 +315,22 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -318,44 +338,84 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-attributes": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, "peerDependencies": { - "acorn": "^8" + "acorn": "^8.14.0" } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, + "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { "type": "github", "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, "peerDependencies": { - "ajv": "^6.9.1" + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.33", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz", + "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/browserslist": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", - "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "dev": true, "funding": [ { @@ -371,11 +431,13 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001663", - "electron-to-chromium": "^1.5.28", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" @@ -391,9 +453,9 @@ "dev": true }, "node_modules/caniuse-lite": { - "version": "1.0.30001667", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz", - "integrity": "sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==", + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", "dev": true, "funding": [ { @@ -408,7 +470,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/chrome-trace-event": { "version": "1.0.4", @@ -446,10 +509,11 @@ "dev": true }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -460,19 +524,21 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.32", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.32.tgz", - "integrity": "sha512-M+7ph0VGBQqqpTT2YrabjNKSQ2fEl9PVx6AK3N558gDH9NO8O6XN9SXXFWRo9u9PbEg/bWq+tjXQr+eXmxubCw==", - "dev": true + "version": "1.5.364", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.364.tgz", + "integrity": "sha512-G/dYE3+AYhyHwzTwg8UbnXf7zqMERYh7l2jJ3QujhFsH8agSYwtnGAR2aZ7f0AakIKJXd5En/Hre4igIUrdlYw==", + "dev": true, + "license": "ISC" }, "node_modules/enhanced-resolve": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "version": "5.22.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.1.tgz", + "integrity": "sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "tapable": "^2.3.3" }, "engines": { "node": ">=10.13.0" @@ -491,16 +557,18 @@ } }, "node_modules/es-module-lexer": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", - "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "dev": true, + "license": "MIT" }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -561,13 +629,25 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "node_modules/fast-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" }, "node_modules/fastest-levenshtein": { "version": "1.0.16", @@ -613,13 +693,15 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/has-flag": { "version": "4.0.0", @@ -726,17 +808,12 @@ "node": ">= 10.13.0" } }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" }, "node_modules/kind-of": { "version": "6.0.3", @@ -748,12 +825,17 @@ } }, "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz", + "integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/locate-path": { @@ -769,10 +851,11 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" }, "node_modules/merge-stream": { "version": "2.0.0", @@ -781,22 +864,11 @@ "dev": true }, "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -817,10 +889,14 @@ "dev": true }, "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true + "version": "2.0.46", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz", + "integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/p-limit": { "version": "2.3.0", @@ -883,10 +959,11 @@ "dev": true }, "node_modules/picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" }, "node_modules/pkg-dir": { "version": "4.2.0", @@ -900,24 +977,6 @@ "node": ">=8" } }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/rechoir": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", @@ -930,6 +989,16 @@ "node": ">= 10.13.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -968,35 +1037,17 @@ "node": ">=8" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "dev": true, + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" }, "engines": { "node": ">= 10.13.0" @@ -1006,15 +1057,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -1095,12 +1137,17 @@ } }, "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/terser": { @@ -1122,16 +1169,16 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.1.tgz", + "integrity": "sha512-201R5j+sJpK8nFWwKVyNfZot8FaJbLZDq5evriVzbV1wDtSXDjRUDRfJzHpAaxFDMEhsZL1QkeqM61wgsS3KaQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.20", + "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" + "schema-utils": "^4.3.0", + "terser": "^5.31.1" }, "engines": { "node": ">= 10.13.0" @@ -1144,12 +1191,39 @@ "webpack": "^5.1.0" }, "peerDependenciesMeta": { + "@minify-html/node": { + "optional": true + }, "@swc/core": { "optional": true }, + "@swc/css": { + "optional": true + }, + "@swc/html": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "cssnano": { + "optional": true + }, + "csso": { + "optional": true + }, "esbuild": { "optional": true }, + "html-minifier-terser": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "postcss": { + "optional": true + }, "uglify-js": { "optional": true } @@ -1162,9 +1236,9 @@ "dev": true }, "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -1180,9 +1254,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "escalade": "^3.2.0", - "picocolors": "^1.1.0" + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -1191,20 +1266,12 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, "node_modules/watchpack": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", - "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", "dev": true, + "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -1214,34 +1281,35 @@ } }, "node_modules/webpack": { - "version": "5.95.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.95.0.tgz", - "integrity": "sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==", + "version": "5.107.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.107.2.tgz", + "integrity": "sha512-v7RhXaJbpMlV0D7hC7lb2EbnxkoeUqf9qhKr6lozx3Q48pmFrqqNRmZFUEGmi7pSwm6fCQ2H1IjvCkHqdpVdjQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/estree": "^1.0.5", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.7.1", - "acorn-import-attributes": "^1.9.5", - "browserslist": "^4.21.10", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.16.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", - "es-module-lexer": "^1.2.1", + "enhanced-resolve": "^5.22.0", + "es-module-lexer": "^2.1.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", + "loader-runner": "^4.3.2", + "mime-db": "^1.54.0", "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.5.0", + "watchpack": "^2.5.1", + "webpack-sources": "^3.5.0" }, "bin": { "webpack": "bin/webpack.js" @@ -1328,10 +1396,11 @@ } }, "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.0.tgz", + "integrity": "sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.13.0" } @@ -1415,9 +1484,9 @@ } }, "@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "dev": true }, "@types/json-schema": { @@ -1436,148 +1505,148 @@ } }, "@webassemblyjs/ast": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "dev": true, "requires": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", "dev": true }, "@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", "dev": true }, "@webassemblyjs/helper-buffer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", "dev": true }, "@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "dev": true, "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", "@xtuc/long": "4.2.2" } }, "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", "dev": true }, "@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", - "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" } }, "@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "dev": true, "requires": { "@xtuc/ieee754": "^1.2.0" } }, "@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "dev": true, "requires": { "@xtuc/long": "4.2.2" } }, "@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", "dev": true }, "@webassemblyjs/wasm-edit": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", - "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" } }, "@webassemblyjs/wasm-gen": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", - "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "@webassemblyjs/wasm-opt": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", - "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" } }, "@webassemblyjs/wasm-parser": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", - "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "@webassemblyjs/wast-printer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", - "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, @@ -1615,47 +1684,65 @@ "dev": true }, "acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true }, - "acorn-import-attributes": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", "dev": true, "requires": {} }, "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "requires": { + "ajv": "^8.0.0" } }, "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} - }, - "browserslist": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", - "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001663", - "electron-to-chromium": "^1.5.28", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" + "fast-deep-equal": "^3.1.3" + } + }, + "baseline-browser-mapping": { + "version": "2.10.33", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz", + "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==", + "dev": true + }, + "browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "requires": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" } }, "buffer-from": { @@ -1665,9 +1752,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001667", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz", - "integrity": "sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==", + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", "dev": true }, "chrome-trace-event": { @@ -1700,9 +1787,9 @@ "dev": true }, "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "requires": { "path-key": "^3.1.0", @@ -1711,19 +1798,19 @@ } }, "electron-to-chromium": { - "version": "1.5.32", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.32.tgz", - "integrity": "sha512-M+7ph0VGBQqqpTT2YrabjNKSQ2fEl9PVx6AK3N558gDH9NO8O6XN9SXXFWRo9u9PbEg/bWq+tjXQr+eXmxubCw==", + "version": "1.5.364", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.364.tgz", + "integrity": "sha512-G/dYE3+AYhyHwzTwg8UbnXf7zqMERYh7l2jJ3QujhFsH8agSYwtnGAR2aZ7f0AakIKJXd5En/Hre4igIUrdlYw==", "dev": true }, "enhanced-resolve": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "version": "5.22.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.1.tgz", + "integrity": "sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww==", "dev": true, "requires": { "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "tapable": "^2.3.3" } }, "envinfo": { @@ -1733,9 +1820,9 @@ "dev": true }, "es-module-lexer": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", - "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", "dev": true }, "escalade": { @@ -1789,10 +1876,10 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "fast-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "dev": true }, "fastest-levenshtein": { @@ -1907,16 +1994,10 @@ "supports-color": "^8.0.0" } }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, "kind-of": { @@ -1926,9 +2007,9 @@ "dev": true }, "loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz", + "integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==", "dev": true }, "locate-path": { @@ -1941,9 +2022,9 @@ } }, "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "dev": true }, "merge-stream": { @@ -1953,20 +2034,11 @@ "dev": true }, "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "requires": { - "mime-db": "1.52.0" - } - }, "moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -1980,9 +2052,9 @@ "dev": true }, "node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "version": "2.0.46", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz", + "integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==", "dev": true }, "p-limit": { @@ -2028,9 +2100,9 @@ "dev": true }, "picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true }, "pkg-dir": { @@ -2042,21 +2114,6 @@ "find-up": "^4.0.0" } }, - "punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, "rechoir": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", @@ -2066,6 +2123,12 @@ "resolve": "^1.20.0" } }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, "resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -2092,30 +2155,16 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, "schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "dev": true, "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - }, - "serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" } }, "shallow-clone": { @@ -2174,9 +2223,9 @@ "dev": true }, "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "dev": true }, "terser": { @@ -2192,16 +2241,15 @@ } }, "terser-webpack-plugin": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.1.tgz", + "integrity": "sha512-201R5j+sJpK8nFWwKVyNfZot8FaJbLZDq5evriVzbV1wDtSXDjRUDRfJzHpAaxFDMEhsZL1QkeqM61wgsS3KaQ==", "dev": true, "requires": { - "@jridgewell/trace-mapping": "^0.3.20", + "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" + "schema-utils": "^4.3.0", + "terser": "^5.31.1" } }, "undici-types": { @@ -2211,28 +2259,19 @@ "dev": true }, "update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "requires": { "escalade": "^3.2.0", - "picocolors": "^1.1.0" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" + "picocolors": "^1.1.1" } }, "watchpack": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", - "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", "dev": true, "requires": { "glob-to-regexp": "^0.4.1", @@ -2240,34 +2279,34 @@ } }, "webpack": { - "version": "5.95.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.95.0.tgz", - "integrity": "sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==", + "version": "5.107.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.107.2.tgz", + "integrity": "sha512-v7RhXaJbpMlV0D7hC7lb2EbnxkoeUqf9qhKr6lozx3Q48pmFrqqNRmZFUEGmi7pSwm6fCQ2H1IjvCkHqdpVdjQ==", "dev": true, "requires": { - "@types/estree": "^1.0.5", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.7.1", - "acorn-import-attributes": "^1.9.5", - "browserslist": "^4.21.10", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.16.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", - "es-module-lexer": "^1.2.1", + "enhanced-resolve": "^5.22.0", + "es-module-lexer": "^2.1.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", + "loader-runner": "^4.3.2", + "mime-db": "^1.54.0", "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.5.0", + "watchpack": "^2.5.1", + "webpack-sources": "^3.5.0" } }, "webpack-cli": { @@ -2311,9 +2350,9 @@ } }, "webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.0.tgz", + "integrity": "sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==", "dev": true }, "which": { diff --git a/src/modules/Elsa.Expressions.JavaScript/Features/JavaScriptFeature.cs b/src/modules/Elsa.Expressions.JavaScript/Features/JavaScriptFeature.cs index b41b8bec2..23c0a8281 100644 --- a/src/modules/Elsa.Expressions.JavaScript/Features/JavaScriptFeature.cs +++ b/src/modules/Elsa.Expressions.JavaScript/Features/JavaScriptFeature.cs @@ -16,7 +16,9 @@ using Elsa.Expressions.JavaScript.Services; using Elsa.Expressions.JavaScript.TypeDefinitions.Contracts; using Elsa.Expressions.JavaScript.TypeDefinitions.Services; using Elsa.Workflows; +using Elsa.Workflows.Options; using Microsoft.Extensions.DependencyInjection; +using Elsa.Common.Serialization; namespace Elsa.Expressions.JavaScript.Features; @@ -61,6 +63,7 @@ public class JavaScriptFeature : FeatureBase { Services.Configure(JintOptions); Services.Configure(JavaScriptExceptionTypeAliasRegistrar.Register); + Services.Configure(JavaScriptExceptionTypeAliasRegistrar.Register); // JavaScript services. Services @@ -74,7 +77,7 @@ public class JavaScriptFeature : FeatureBase .AddScoped() .AddScoped() .AddScoped() - .AddSingleton() + .AddSingleton() .AddFunctionDefinitionProvider() .AddFunctionDefinitionProvider() .AddFunctionDefinitionProvider() diff --git a/src/modules/Elsa.Expressions.JavaScript/JavaScriptExceptionTypeAliasRegistrar.cs b/src/modules/Elsa.Expressions.JavaScript/JavaScriptExceptionTypeAliasRegistrar.cs index dea8c76a7..7ad876ba6 100644 --- a/src/modules/Elsa.Expressions.JavaScript/JavaScriptExceptionTypeAliasRegistrar.cs +++ b/src/modules/Elsa.Expressions.JavaScript/JavaScriptExceptionTypeAliasRegistrar.cs @@ -1,8 +1,10 @@ using System.Reflection; using Acornima; using Elsa.Expressions.Options; +using Elsa.Workflows.Options; using Jint; using Jint.Runtime; +using Elsa.Common.Serialization; namespace Elsa.Expressions.JavaScript; @@ -18,4 +20,15 @@ internal static class JavaScriptExceptionTypeAliasRegistrar if (wrapperExceptionType != null) options.RegisterTypeAlias(wrapperExceptionType, "Jint.JavaScriptErrorWrapperException"); } + + public static void Register(SerializationTypeOptions options) + { + options.RegisterTypeAlias(typeof(ScriptPreparationException), nameof(ScriptPreparationException)); + options.RegisterTypeAlias(typeof(JavaScriptException), nameof(JavaScriptException)); + options.RegisterTypeAlias(typeof(SyntaxErrorException), nameof(SyntaxErrorException)); + + var wrapperExceptionType = typeof(JavaScriptException).GetNestedType("JavaScriptErrorWrapperException", BindingFlags.Public | BindingFlags.NonPublic); + if (wrapperExceptionType != null) + options.RegisterTypeAlias(wrapperExceptionType, "Jint.JavaScriptErrorWrapperException"); + } } diff --git a/src/modules/Elsa.Expressions.JavaScript/ShellFeatures/JavaScriptFeature.cs b/src/modules/Elsa.Expressions.JavaScript/ShellFeatures/JavaScriptFeature.cs index 1b5f26760..27edd192c 100644 --- a/src/modules/Elsa.Expressions.JavaScript/ShellFeatures/JavaScriptFeature.cs +++ b/src/modules/Elsa.Expressions.JavaScript/ShellFeatures/JavaScriptFeature.cs @@ -12,8 +12,10 @@ using Elsa.Expressions.Options; using Elsa.Extensions; using Elsa.PackageManifest.Generator.Hints; using Elsa.Workflows; +using Elsa.Workflows.Options; using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; +using Elsa.Common.Serialization; namespace Elsa.Expressions.JavaScript.ShellFeatures; @@ -106,6 +108,7 @@ public class JavaScriptFeature : IShellFeature options.DisableVariableCopying = DisableVariableCopying; }); services.Configure(JavaScriptExceptionTypeAliasRegistrar.Register); + services.Configure(JavaScriptExceptionTypeAliasRegistrar.Register); // JavaScript services. services @@ -117,7 +120,7 @@ public class JavaScriptFeature : IShellFeature .AddScoped() .AddScoped() .AddScoped() - .AddSingleton() + .AddSingleton() .AddFunctionDefinitionProvider() .AddFunctionDefinitionProvider() .AddFunctionDefinitionProvider() diff --git a/src/modules/Elsa.Expressions/Extensions/TypeExtensions.cs b/src/modules/Elsa.Expressions/Extensions/TypeExtensions.cs index 09b5990a4..b88e4e1ad 100644 --- a/src/modules/Elsa.Expressions/Extensions/TypeExtensions.cs +++ b/src/modules/Elsa.Expressions/Extensions/TypeExtensions.cs @@ -1,4 +1,3 @@ -using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using System.Text; using Elsa.Expressions.Models; @@ -11,18 +10,6 @@ namespace Elsa.Extensions; /// public static class TypeExtensions { - private static readonly ConcurrentDictionary SimpleAssemblyQualifiedTypeNameCache = new(); - - /// - /// Gets the assembly-qualified name of the type, without any version info etc. - /// E.g. "System.String, System.Private.CoreLib" - /// - public static string GetSimpleAssemblyQualifiedName(this Type type) - { - if (type is null) throw new ArgumentNullException(nameof(type)); - return SimpleAssemblyQualifiedTypeNameCache.GetOrAdd(type, GetSimplifiedName); - } - /// /// Returns the default value for the specified type. /// @@ -113,24 +100,4 @@ public static class TypeExtensions return sb.ToString(); } - private static string GetSimplifiedName(Type type) - { - var assemblyName = type.Assembly.GetName().Name; - - if (type.IsGenericType) - { - var genericTypeName = type.GetGenericTypeDefinition().FullName!; - var backtickIndex = genericTypeName.IndexOf('`'); - var typeNameWithoutArity = genericTypeName[..backtickIndex]; - var arity = genericTypeName[backtickIndex..]; - - var genericArguments = type.GetGenericArguments(); - var simplifiedGenericArguments = genericArguments.Select(GetSimplifiedName); - - return $"{typeNameWithoutArity}{arity}[[{string.Join("],[", simplifiedGenericArguments)}]], {assemblyName}"; - } - - var typeName = type.FullName; - return $"{typeName}, {assemblyName}"; - } -} \ No newline at end of file +} diff --git a/src/modules/Elsa.Expressions/Options/ExpressionOptions.cs b/src/modules/Elsa.Expressions/Options/ExpressionOptions.cs index 5e448a8a2..866344e0b 100644 --- a/src/modules/Elsa.Expressions/Options/ExpressionOptions.cs +++ b/src/modules/Elsa.Expressions/Options/ExpressionOptions.cs @@ -51,7 +51,7 @@ public class ExpressionOptions /// Gets the type alias dictionary. /// public IDictionary AliasTypeDictionary { get; set; } - + /// /// Registers a well-known type alias. /// diff --git a/src/modules/Elsa.Http/Features/HttpFeature.cs b/src/modules/Elsa.Http/Features/HttpFeature.cs index 441789ee4..6e406665a 100644 --- a/src/modules/Elsa.Http/Features/HttpFeature.cs +++ b/src/modules/Elsa.Http/Features/HttpFeature.cs @@ -1,5 +1,4 @@ using System.Net; -using Elsa.Expressions.Options; using Elsa.Extensions; using Elsa.Features.Abstractions; using Elsa.Features.Attributes; @@ -21,12 +20,14 @@ using Elsa.Http.UIHints; using Elsa.Resilience.Extensions; using Elsa.Resilience.Features; using Elsa.Workflows; +using Elsa.Workflows.Options; using FluentStorage; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; +using Elsa.Common.Serialization; namespace Elsa.Http.Features; @@ -247,22 +248,22 @@ public class HttpFeature(IModule module) : FeatureBase(module) foreach (var httpWorkflowInstanceIdSelectorType in HttpWorkflowInstanceIdSelectorTypes) Services.AddScoped(typeof(IHttpWorkflowInstanceIdSelector), httpWorkflowInstanceIdSelectorType); - Services.Configure(options => + Services.Configure(options => { - options.AddTypeAlias("HttpRequest"); - options.AddTypeAlias("HttpResponse"); - options.AddTypeAlias("HttpResponseMessage"); - options.AddTypeAlias("HttpHeaders"); - options.AddTypeAlias("RouteData"); - options.AddTypeAlias("FormFile"); - options.AddTypeAlias("FormFile[]"); - options.AddTypeAlias("HttpFile"); - options.AddTypeAlias("HttpFile[]"); - options.AddTypeAlias("Downloadable"); - options.AddTypeAlias("Downloadable[]"); - options.AddTypeAlias(); - options.AddTypeAlias(); - options.AddTypeAlias(); + options.RegisterTypeAlias(typeof(HttpRequest), "HttpRequest"); + options.RegisterTypeAlias(typeof(HttpResponse), "HttpResponse"); + options.RegisterTypeAlias(typeof(HttpResponseMessage), "HttpResponseMessage"); + options.RegisterTypeAlias(typeof(HttpHeaders), "HttpHeaders"); + options.RegisterTypeAlias(typeof(HttpRouteData), "RouteData"); + options.RegisterTypeAlias(typeof(IFormFile), "FormFile"); + options.RegisterTypeAlias(typeof(IFormFile[]), "FormFile[]"); + options.RegisterTypeAlias(typeof(HttpFile), "HttpFile"); + options.RegisterTypeAlias(typeof(HttpFile[]), "HttpFile[]"); + options.RegisterTypeAlias(typeof(Downloadable), "Downloadable"); + options.RegisterTypeAlias(typeof(Downloadable[]), "Downloadable[]"); + options.RegisterTypeAlias(typeof(HttpStatusCode), nameof(HttpStatusCode)); + options.RegisterTypeAlias(typeof(HttpRequestException), nameof(HttpRequestException)); + options.RegisterTypeAlias(typeof(HttpEndpointBookmarkPayload), nameof(HttpEndpointBookmarkPayload)); }); } } diff --git a/src/modules/Elsa.Http/ShellFeatures/HttpFeature.cs b/src/modules/Elsa.Http/ShellFeatures/HttpFeature.cs index 956460357..7f333e191 100644 --- a/src/modules/Elsa.Http/ShellFeatures/HttpFeature.cs +++ b/src/modules/Elsa.Http/ShellFeatures/HttpFeature.cs @@ -1,7 +1,6 @@ using System.Net; using CShells.AspNetCore.Features; using CShells.Features; -using Elsa.Expressions.Options; using Elsa.Extensions; using Elsa.Http.Bookmarks; using Elsa.Http.ContentWriters; @@ -20,6 +19,7 @@ using Elsa.Http.UIHints; using Elsa.Resilience.Extensions; using Elsa.Workflows; using Elsa.Workflows.Management.Extensions; +using Elsa.Workflows.Options; using FluentStorage; using JetBrains.Annotations; using Microsoft.AspNetCore.Builder; @@ -28,6 +28,7 @@ using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; +using Elsa.Common.Serialization; namespace Elsa.Http.ShellFeatures; @@ -218,22 +219,22 @@ public class HttpFeature : IMiddlewareShellFeature foreach (var httpWorkflowInstanceIdSelectorType in HttpWorkflowInstanceIdSelectorTypes) services.AddScoped(typeof(IHttpWorkflowInstanceIdSelector), httpWorkflowInstanceIdSelectorType); - services.Configure(options => + services.Configure(options => { - options.AddTypeAlias("HttpRequest"); - options.AddTypeAlias("HttpResponse"); - options.AddTypeAlias("HttpResponseMessage"); - options.AddTypeAlias("HttpHeaders"); - options.AddTypeAlias("RouteData"); - options.AddTypeAlias("FormFile"); - options.AddTypeAlias("FormFile[]"); - options.AddTypeAlias("HttpFile"); - options.AddTypeAlias("HttpFile[]"); - options.AddTypeAlias("Downloadable"); - options.AddTypeAlias("Downloadable[]"); - options.AddTypeAlias(); - options.AddTypeAlias(); - options.AddTypeAlias(); + options.RegisterTypeAlias(typeof(HttpRequest), "HttpRequest"); + options.RegisterTypeAlias(typeof(HttpResponse), "HttpResponse"); + options.RegisterTypeAlias(typeof(HttpResponseMessage), "HttpResponseMessage"); + options.RegisterTypeAlias(typeof(HttpHeaders), "HttpHeaders"); + options.RegisterTypeAlias(typeof(HttpRouteData), "RouteData"); + options.RegisterTypeAlias(typeof(IFormFile), "FormFile"); + options.RegisterTypeAlias(typeof(IFormFile[]), "FormFile[]"); + options.RegisterTypeAlias(typeof(HttpFile), "HttpFile"); + options.RegisterTypeAlias(typeof(HttpFile[]), "HttpFile[]"); + options.RegisterTypeAlias(typeof(Downloadable), "Downloadable"); + options.RegisterTypeAlias(typeof(Downloadable[]), "Downloadable[]"); + options.RegisterTypeAlias(typeof(HttpStatusCode), nameof(HttpStatusCode)); + options.RegisterTypeAlias(typeof(HttpRequestException), nameof(HttpRequestException)); + options.RegisterTypeAlias(typeof(HttpEndpointBookmarkPayload), nameof(HttpEndpointBookmarkPayload)); }); } diff --git a/src/modules/Elsa.Persistence.EFCore/Modules/Management/WorkflowDefinitionPersistenceFeature.cs b/src/modules/Elsa.Persistence.EFCore/Modules/Management/WorkflowDefinitionPersistenceFeature.cs index 104a90694..b13b41a41 100644 --- a/src/modules/Elsa.Persistence.EFCore/Modules/Management/WorkflowDefinitionPersistenceFeature.cs +++ b/src/modules/Elsa.Persistence.EFCore/Modules/Management/WorkflowDefinitionPersistenceFeature.cs @@ -3,6 +3,7 @@ using Elsa.Features.Attributes; using Elsa.Features.Services; using Elsa.Workflows.Management.Entities; using Elsa.Workflows.Management.Features; +using Elsa.Workflows.Options; using Microsoft.Extensions.DependencyInjection; namespace Elsa.Persistence.EFCore.Modules.Management; @@ -27,7 +28,6 @@ public class EFCoreWorkflowDefinitionPersistenceFeature(IModule module) : Persis public override void Apply() { base.Apply(); - Services.Configure(options => options.RegisterTypeAlias(EFCoreWorkflowDefinitionStore.WorkflowDefinitionStateType, "EFCoreWorkflowDefinitionState")); AddEntityStore(); } } diff --git a/src/modules/Elsa.Persistence.EFCore/Modules/Management/WorkflowDefinitionStore.cs b/src/modules/Elsa.Persistence.EFCore/Modules/Management/WorkflowDefinitionStore.cs index 451792359..e805caeaa 100644 --- a/src/modules/Elsa.Persistence.EFCore/Modules/Management/WorkflowDefinitionStore.cs +++ b/src/modules/Elsa.Persistence.EFCore/Modules/Management/WorkflowDefinitionStore.cs @@ -22,8 +22,6 @@ namespace Elsa.Persistence.EFCore.Modules.Management; public class EFCoreWorkflowDefinitionStore(EntityStore store, IPayloadSerializer payloadSerializer, ILogger logger) : IWorkflowDefinitionStore { - internal static Type WorkflowDefinitionStateType => typeof(WorkflowDefinitionState); - /// public async Task FindAsync(WorkflowDefinitionFilter filter, CancellationToken cancellationToken = default) { @@ -269,4 +267,4 @@ public class EFCoreWorkflowDefinitionStore(EntityStore Outcomes { get; set; } = new List(); public IDictionary CustomProperties { get; set; } = new Dictionary(); } -} +} \ No newline at end of file diff --git a/src/modules/Elsa.Resilience/Features/ResilienceFeature.cs b/src/modules/Elsa.Resilience/Features/ResilienceFeature.cs index 5cc8f6d3e..887ff7de5 100644 --- a/src/modules/Elsa.Resilience/Features/ResilienceFeature.cs +++ b/src/modules/Elsa.Resilience/Features/ResilienceFeature.cs @@ -10,8 +10,10 @@ using Elsa.Resilience.Recorders; using Elsa.Resilience.Serialization; using Elsa.Resilience.StrategySources; using Elsa.Workflows; +using Elsa.Workflows.Options; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Elsa.Common.Serialization; namespace Elsa.Resilience.Features; @@ -66,6 +68,11 @@ public class ResilienceFeature(IModule module) : FeatureBase(module) { options.AddTypeAlias>("RetryAttemptRecordList"); }); + + Services.Configure(options => + { + options.RegisterTypeAlias(typeof(List), "RetryAttemptRecordList"); + }); } public override void Apply() diff --git a/src/modules/Elsa.Resilience/ShellFeatures/ResilienceFeature.cs b/src/modules/Elsa.Resilience/ShellFeatures/ResilienceFeature.cs index 4e57ce778..dedacd3c5 100644 --- a/src/modules/Elsa.Resilience/ShellFeatures/ResilienceFeature.cs +++ b/src/modules/Elsa.Resilience/ShellFeatures/ResilienceFeature.cs @@ -10,8 +10,10 @@ using Elsa.Resilience.Recorders; using Elsa.Resilience.Serialization; using Elsa.Resilience.StrategySources; using Elsa.Workflows; +using Elsa.Workflows.Options; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Elsa.Common.Serialization; namespace Elsa.Resilience.ShellFeatures; @@ -26,6 +28,11 @@ public class ResilienceFeature : IFastEndpointsShellFeature { options.AddTypeAlias>("RetryAttemptRecordList"); }); + + services.Configure(options => + { + options.RegisterTypeAlias(typeof(List), "RetryAttemptRecordList"); + }); services.AddOptions(); services.AddOptions(); diff --git a/src/modules/Elsa.Scheduling/Features/SchedulingFeature.cs b/src/modules/Elsa.Scheduling/Features/SchedulingFeature.cs index 7bac060de..20efd0a61 100644 --- a/src/modules/Elsa.Scheduling/Features/SchedulingFeature.cs +++ b/src/modules/Elsa.Scheduling/Features/SchedulingFeature.cs @@ -1,6 +1,5 @@ using Elsa.Common.Features; using Elsa.Common.Multitenancy; -using Elsa.Expressions.Options; using Elsa.Extensions; using Elsa.Features.Abstractions; using Elsa.Features.Attributes; @@ -11,7 +10,9 @@ using Elsa.Scheduling.Services; using Elsa.Scheduling.StartupTasks; using Elsa.Scheduling.TriggerPayloadValidators; using Elsa.Workflows.Management.Features; +using Elsa.Workflows.Options; using Microsoft.Extensions.DependencyInjection; +using Elsa.Common.Serialization; namespace Elsa.Scheduling.Features; @@ -58,14 +59,14 @@ public class SchedulingFeature : FeatureBase // Graceful shutdown: register scheduled-trigger ingress for diagnostic visibility (FR-006). .AddSingleton(); - Services.Configure(options => + Services.Configure(options => { - options.AddTypeAlias(); - options.AddTypeAlias(); - options.AddTypeAlias(); - options.AddTypeAlias(); - options.AddTypeAlias(); - options.AddTypeAlias(); + options.RegisterTypeAlias(typeof(CronBookmarkPayload), nameof(CronBookmarkPayload)); + options.RegisterTypeAlias(typeof(CronTriggerPayload), nameof(CronTriggerPayload)); + options.RegisterTypeAlias(typeof(DelayPayload), nameof(DelayPayload)); + options.RegisterTypeAlias(typeof(StartAtPayload), nameof(StartAtPayload)); + options.RegisterTypeAlias(typeof(TimerBookmarkPayload), nameof(TimerBookmarkPayload)); + options.RegisterTypeAlias(typeof(TimerTriggerPayload), nameof(TimerTriggerPayload)); }); Module.Configure(management => management.AddActivitiesFrom()); diff --git a/src/modules/Elsa.Scheduling/ShellFeatures/SchedulingFeature.cs b/src/modules/Elsa.Scheduling/ShellFeatures/SchedulingFeature.cs index 0c960b2cc..79eb86831 100644 --- a/src/modules/Elsa.Scheduling/ShellFeatures/SchedulingFeature.cs +++ b/src/modules/Elsa.Scheduling/ShellFeatures/SchedulingFeature.cs @@ -2,6 +2,7 @@ using CShells.Features; using Elsa.Common.Multitenancy; using Elsa.Common.ShellFeatures; using Elsa.Extensions; +using Elsa.Workflows.Options; using Elsa.Scheduling.Bookmarks; using Elsa.Scheduling.Handlers; using Elsa.Scheduling.Services; @@ -10,6 +11,7 @@ using Elsa.Scheduling.TriggerPayloadValidators; using Elsa.Workflows.Management.Extensions; using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; +using Elsa.Common.Serialization; namespace Elsa.Scheduling.ShellFeatures; @@ -49,5 +51,15 @@ public class SchedulingFeature : IShellFeature .AddHandlersFrom() .AddTriggerPayloadValidator() .AddActivitiesFrom(); + + services.Configure(options => + { + options.AddTypeAlias(); + options.AddTypeAlias(); + options.AddTypeAlias(); + options.AddTypeAlias(); + options.AddTypeAlias(); + options.AddTypeAlias(); + }); } } diff --git a/src/modules/Elsa.Workflows.Api/AssemblyInfo.cs b/src/modules/Elsa.Workflows.Api/AssemblyInfo.cs index 2c63c1354..e6bd2a3d1 100644 --- a/src/modules/Elsa.Workflows.Api/AssemblyInfo.cs +++ b/src/modules/Elsa.Workflows.Api/AssemblyInfo.cs @@ -1,3 +1,4 @@ using System.Runtime.CompilerServices; -[assembly: InternalsVisibleTo("Elsa.Workflows.IntegrationTests")] \ No newline at end of file +[assembly: InternalsVisibleTo("Elsa.Workflows.IntegrationTests")] +[assembly: InternalsVisibleTo("Elsa.Workflows.Api.UnitTests")] diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/ActivityExecutions/Get/Endpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/ActivityExecutions/Get/Endpoint.cs index 829720b25..819d95a64 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/ActivityExecutions/Get/Endpoint.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/ActivityExecutions/Get/Endpoint.cs @@ -15,14 +15,22 @@ internal class Endpoint(IActivityExecutionStore store) : ElsaEndpointWithoutRequ /// public override void Configure() { - Get("/activity-executions/{id}"); + Get("/activity-executions/{id}", "/activity-executions/{*id}", "/activity-executions/by-id"); ConfigurePermissions("read:activity-execution"); } /// public override async Task HandleAsync(CancellationToken cancellationToken) { - var id = Route("id"); + var id = Query("id", false) ?? Route("id", false); + + if (string.IsNullOrWhiteSpace(id)) + { + AddError("The activity execution ID is required."); + await Send.ErrorsAsync(cancellation: cancellationToken); + return; + } + var filter = new ActivityExecutionRecordFilter { Id = id @@ -38,4 +46,4 @@ internal class Endpoint(IActivityExecutionStore store) : ElsaEndpointWithoutRequ await Send.OkAsync(record, cancellationToken); } -} \ No newline at end of file +} diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/IncidentStrategies/List/Endpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/IncidentStrategies/List/Endpoint.cs index cafa9453d..95c87902b 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/IncidentStrategies/List/Endpoint.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/IncidentStrategies/List/Endpoint.cs @@ -2,16 +2,17 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Reflection; using Elsa.Abstractions; -using Elsa.Extensions; using Elsa.Models; +using Elsa.Workflows; using Humanizer; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Api.Endpoints.IncidentStrategies.List; /// /// Returns list of available implementations. /// -internal class List(IEnumerable strategies) : ElsaEndpointWithoutRequest> +internal class List(IEnumerable strategies, ISerializationTypeRegistry workflowJsonTypeRegistry) : ElsaEndpointWithoutRequest> { public override void Configure() { @@ -21,15 +22,15 @@ internal class List(IEnumerable strategies) : ElsaEndpointWit public override Task> ExecuteAsync(CancellationToken cancellationToken) { - var descriptors = strategies.Select(IncidentStrategyDescriptor.FromStrategy).OrderBy(x => x.DisplayName).ToList(); - var response =new ListResponse(descriptors); + var descriptors = strategies.Select(x => IncidentStrategyDescriptor.FromStrategy(x, workflowJsonTypeRegistry)).OrderBy(x => x.DisplayName).ToList(); + var response = new ListResponse(descriptors); return Task.FromResult(response); } } internal record IncidentStrategyDescriptor(string DisplayName, string Description, string TypeName) { - public static IncidentStrategyDescriptor FromStrategy(IIncidentStrategy strategy) + public static IncidentStrategyDescriptor FromStrategy(IIncidentStrategy strategy, ISerializationTypeRegistry workflowJsonTypeRegistry) { var type = strategy.GetType(); var displayNameAttribute = type.GetCustomAttribute(); @@ -38,6 +39,7 @@ internal record IncidentStrategyDescriptor(string DisplayName, string Descriptio var displayName = displayNameAttribute?.DisplayName ?? displayAttribute?.Name ?? type.Name.Replace("Strategy", "").Humanize(); var description = descriptionAttribute?.Description ?? displayAttribute?.Description ?? ""; - return new IncidentStrategyDescriptor(displayName, description, type.GetSimpleAssemblyQualifiedName()); + var typeName = workflowJsonTypeRegistry.TryGetAlias(type, out var alias) ? alias : type.FullName!; + return new IncidentStrategyDescriptor(displayName, description, typeName); } -} \ No newline at end of file +} diff --git a/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Serialization/FlowchartJsonConverter.cs b/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Serialization/FlowchartJsonConverter.cs index b65421cd1..afa42aaf6 100644 --- a/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Serialization/FlowchartJsonConverter.cs +++ b/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Serialization/FlowchartJsonConverter.cs @@ -1,12 +1,12 @@ using System.Text.Json; using System.Text.Json.Serialization; -using Elsa.Expressions.Contracts; using Elsa.Extensions; using Elsa.Workflows.Activities.Flowchart.Models; using Elsa.Workflows.Memory; using Elsa.Workflows.Serialization.Converters; using JetBrains.Annotations; using Microsoft.Extensions.Logging; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Activities.Flowchart.Serialization; @@ -14,7 +14,7 @@ namespace Elsa.Workflows.Activities.Flowchart.Serialization; /// A JSON converter for . /// [UsedImplicitly] -public class FlowchartJsonConverter(IIdentityGenerator identityGenerator, IWellKnownTypeRegistry wellKnownTypeRegistry, ILoggerFactory loggerFactory) : JsonConverter +public class FlowchartJsonConverter(IIdentityGenerator identityGenerator, ISerializationTypeRegistry workflowJsonTypeRegistry, ILoggerFactory loggerFactory) : JsonConverter { private const string AllActivitiesKey = "allActivities"; private const string AllConnectionsKey = "allConnections"; @@ -47,7 +47,7 @@ public class FlowchartJsonConverter(IIdentityGenerator identityGenerator, IWellK var variables = variablesElement.ValueKind != JsonValueKind.Undefined ? variablesElement.Deserialize>(options) ?? new List() : new List(); var polymorphicOptions = options.Clone(); - polymorphicOptions.Converters.Add(new PolymorphicDictionaryConverter(options, wellKnownTypeRegistry)); + polymorphicOptions.Converters.Add(new PolymorphicDictionaryConverter(options, workflowJsonTypeRegistry)); var metadataElement = doc.RootElement.TryGetProperty("metadata", out var metadataEl) ? metadataEl : default; var metadata = metadataElement.ValueKind != JsonValueKind.Undefined ? metadataElement.Deserialize>(polymorphicOptions) ?? new Dictionary() : new Dictionary(); @@ -105,7 +105,7 @@ public class FlowchartJsonConverter(IIdentityGenerator identityGenerator, IWellK var flowchartSerializerOptions = new JsonSerializerOptions(options); flowchartSerializerOptions.Converters.Add(new ConnectionJsonConverter(activityDictionary, loggerFactory)); - flowchartSerializerOptions.Converters.Add(new PolymorphicDictionaryConverter(options, wellKnownTypeRegistry)); + flowchartSerializerOptions.Converters.Add(new PolymorphicDictionaryConverter(options, workflowJsonTypeRegistry)); JsonSerializer.Serialize(writer, model, flowchartSerializerOptions); } @@ -218,4 +218,4 @@ public class FlowchartJsonConverter(IIdentityGenerator identityGenerator, IWellK // drop any half‑baked entries return raw.Where(c => c != null && c.Source.Activity != null! && c.Target.Activity != null!).Cast().ToList(); } -} \ No newline at end of file +} diff --git a/src/modules/Elsa.Workflows.Core/Features/FlowchartFeature.cs b/src/modules/Elsa.Workflows.Core/Features/FlowchartFeature.cs index ab3a000a2..8fb59634d 100644 --- a/src/modules/Elsa.Workflows.Core/Features/FlowchartFeature.cs +++ b/src/modules/Elsa.Workflows.Core/Features/FlowchartFeature.cs @@ -4,7 +4,9 @@ using Elsa.Features.Services; using Elsa.Workflows.Activities.Flowchart.Models; using Elsa.Workflows.Activities.Flowchart.Options; using Elsa.Workflows.Activities.Flowchart.Serialization; +using Elsa.Workflows.Options; using Microsoft.Extensions.DependencyInjection; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Features; @@ -33,10 +35,7 @@ public class FlowchartFeature : FeatureBase if (FlowchartOptionsConfigurator != null) Services.Configure(FlowchartOptionsConfigurator); - } - public override void Configure() - { - Module.AddTypeAlias("FlowScope"); + Services.Configure(options => options.AddTypeAlias("FlowScope")); } -} \ No newline at end of file +} diff --git a/src/modules/Elsa.Workflows.Core/Features/WorkflowsFeature.cs b/src/modules/Elsa.Workflows.Core/Features/WorkflowsFeature.cs index 4822214f9..89c17f04c 100644 --- a/src/modules/Elsa.Workflows.Core/Features/WorkflowsFeature.cs +++ b/src/modules/Elsa.Workflows.Core/Features/WorkflowsFeature.cs @@ -2,7 +2,6 @@ using Elsa.Common; using Elsa.Common.Features; using Elsa.Common.Serialization; using Elsa.Expressions.Features; -using Elsa.Expressions.Options; using Elsa.Extensions; using Elsa.Features.Abstractions; using Elsa.Features.Attributes; @@ -17,6 +16,7 @@ using Elsa.Workflows.LogPersistence; using Elsa.Workflows.LogPersistence.Strategies; using Elsa.Workflows.Middleware.Activities; using Elsa.Workflows.Middleware.Workflows; +using Elsa.Workflows.Options; using Elsa.Workflows.Pipelines.ActivityExecution; using Elsa.Workflows.Pipelines.WorkflowExecution; using Elsa.Workflows.PortResolvers; @@ -91,7 +91,12 @@ public class WorkflowsFeature : FeatureBase /// /// A delegate to configure the . /// - public Action ActivityExecutionPipeline { get; set; } = builder => builder.UseDefaultActivityInvoker(); + public Action ActivityExecutionPipeline { get; set; } = builder => builder + .UseLogging() + .UseExceptionHandling() + .UseExecutionLogging() + .UseNotifications() + .UseDefaultActivityInvoker(); /// /// Fluent method to set . @@ -164,34 +169,30 @@ public class WorkflowsFeature : FeatureBase private void AddElsaCore(IServiceCollection services) { - services.Configure(options => + services.Configure(options => { - options.RegisterTypeAlias(typeof(ExceptionState), nameof(ExceptionState)); - options.RegisterTypeAlias(typeof(FaultException), nameof(FaultException)); - options.RegisterTypeAlias(typeof(VariablesDictionary), nameof(VariablesDictionary)); - options.RegisterTypeAlias(typeof(Token), nameof(Token)); - options.RegisterTypeAlias(typeof(FlowJoinMode), "Elsa.Workflows.Core.Activities.Flowchart.Models.FlowJoinMode, Elsa.Workflows.Core"); - options.RegisterTypeAlias(typeof(FlowJoinMode), typeof(FlowJoinMode).GetSimpleAssemblyQualifiedName()); - options.RegisterTypeAlias(typeof(FlowJoinMode), nameof(FlowJoinMode)); - options.RegisterTypeAlias(typeof(WorkflowStorageDriver), typeof(WorkflowStorageDriver).GetSimpleAssemblyQualifiedName()); - options.RegisterTypeAlias(typeof(WorkflowStorageDriver), nameof(WorkflowStorageDriver)); - options.RegisterTypeAlias(typeof(WorkflowInstanceStorageDriver), typeof(WorkflowInstanceStorageDriver).GetSimpleAssemblyQualifiedName()); - options.RegisterTypeAlias(typeof(WorkflowInstanceStorageDriver), nameof(WorkflowInstanceStorageDriver)); - options.RegisterTypeAlias(typeof(MemoryStorageDriver), typeof(MemoryStorageDriver).GetSimpleAssemblyQualifiedName()); - options.RegisterTypeAlias(typeof(MemoryStorageDriver), nameof(MemoryStorageDriver)); - options.RegisterTypeAlias(typeof(FaultStrategy), typeof(FaultStrategy).GetSimpleAssemblyQualifiedName()); - options.RegisterTypeAlias(typeof(FaultStrategy), nameof(FaultStrategy)); - options.RegisterTypeAlias(typeof(Exception), nameof(Exception)); - options.RegisterTypeAlias(typeof(ArgumentException), nameof(ArgumentException)); - options.RegisterTypeAlias(typeof(ArgumentNullException), nameof(ArgumentNullException)); - options.RegisterTypeAlias(typeof(InvalidOperationException), nameof(InvalidOperationException)); - options.RegisterTypeAlias(typeof(NullReferenceException), nameof(NullReferenceException)); - options.RegisterTypeAlias(typeof(OperationCanceledException), nameof(OperationCanceledException)); - options.RegisterTypeAlias(typeof(TaskCanceledException), nameof(TaskCanceledException)); - options.RegisterTypeAlias(typeof(TimeoutException), nameof(TimeoutException)); - options.RegisterTypeAlias(typeof(NotSupportedException), nameof(NotSupportedException)); - options.RegisterTypeAlias(typeof(JObject), nameof(JObject)); - options.RegisterTypeAlias(typeof(JArray), nameof(JArray)); + options.AddTypeAlias(nameof(ExceptionState)); + options.AddTypeAlias(nameof(FaultException)); + options.AddTypeAlias(nameof(VariablesDictionary)); + options.AddTypeAlias(nameof(Token)); + options.RegisterLegacyTypeName(typeof(FlowJoinMode), "Elsa.Workflows.Core.Activities.Flowchart.Models.FlowJoinMode, Elsa.Workflows.Core"); + options.AddTypeAliasWithLegacyName(nameof(FlowJoinMode)); + options.AddTypeAliasWithLegacyName(nameof(WorkflowStorageDriver)); + options.AddTypeAliasWithLegacyName(nameof(WorkflowInstanceStorageDriver)); + options.AddTypeAliasWithLegacyName(nameof(MemoryStorageDriver)); + options.AddTypeAliasWithLegacyName(nameof(FaultStrategy)); + options.AddTypeAliasWithLegacyName(nameof(ContinueWithIncidentsStrategy)); + options.AddTypeAlias(nameof(Exception)); + options.AddTypeAlias(nameof(ArgumentException)); + options.AddTypeAlias(nameof(ArgumentNullException)); + options.AddTypeAlias(nameof(InvalidOperationException)); + options.AddTypeAlias(nameof(NullReferenceException)); + options.AddTypeAlias(nameof(OperationCanceledException)); + options.AddTypeAlias(nameof(TaskCanceledException)); + options.AddTypeAlias(nameof(TimeoutException)); + options.AddTypeAlias(nameof(NotSupportedException)); + options.AddTypeAlias(nameof(JObject)); + options.AddTypeAlias(nameof(JArray)); }); services @@ -264,6 +265,7 @@ public class WorkflowsFeature : FeatureBase .AddStorageDriver() // Serialization. + .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Converters/ExcludeFromHashConverter.cs b/src/modules/Elsa.Workflows.Core/Serialization/Converters/ExcludeFromHashConverter.cs index b425eb865..4c84b5de9 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/Converters/ExcludeFromHashConverter.cs +++ b/src/modules/Elsa.Workflows.Core/Serialization/Converters/ExcludeFromHashConverter.cs @@ -35,7 +35,9 @@ public class ExcludeFromHashConverter : JsonConverter var propertyValue = property.GetValue(value); if (ShouldIgnoreProperty(metadata.JsonIgnoreCondition, property.PropertyType, propertyValue)) + { continue; + } writer.WritePropertyName(property.Name); JsonSerializer.Serialize(writer, propertyValue, newOptions); diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Converters/OutputJsonConverter.cs b/src/modules/Elsa.Workflows.Core/Serialization/Converters/OutputJsonConverter.cs index ecefa40b6..af9f90393 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/Converters/OutputJsonConverter.cs +++ b/src/modules/Elsa.Workflows.Core/Serialization/Converters/OutputJsonConverter.cs @@ -1,9 +1,9 @@ using System.Text.Json; using System.Text.Json.Serialization; -using Elsa.Expressions.Contracts; -using Elsa.Expressions.Extensions; +using Elsa.Extensions; using Elsa.Workflows.Memory; using Elsa.Workflows.Models; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Serialization.Converters; @@ -12,12 +12,12 @@ namespace Elsa.Workflows.Serialization.Converters; /// public class OutputJsonConverter : JsonConverter?> { - private readonly IWellKnownTypeRegistry _wellKnownTypeRegistry; + private readonly ISerializationTypeRegistry _workflowJsonTypeRegistry; /// - public OutputJsonConverter(IWellKnownTypeRegistry wellKnownTypeRegistry) + public OutputJsonConverter(ISerializationTypeRegistry workflowJsonTypeRegistry) { - _wellKnownTypeRegistry = wellKnownTypeRegistry; + _workflowJsonTypeRegistry = workflowJsonTypeRegistry; } /// @@ -50,7 +50,9 @@ public class OutputJsonConverter : JsonConverter?> public override void Write(Utf8JsonWriter writer, Output? value, JsonSerializerOptions options) { var valueType = typeof(T); - var valueTypeAlias = _wellKnownTypeRegistry.GetAliasOrDefault(valueType); + var valueTypeAlias = SerializationTypeResolver.TryGetAlias(_workflowJsonTypeRegistry, valueType, out var alias) + ? alias + : valueType.GetSimpleAssemblyQualifiedName(); var model = new { @@ -63,4 +65,4 @@ public class OutputJsonConverter : JsonConverter?> JsonSerializer.Serialize(writer, model, options); } -} \ No newline at end of file +} diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicDictionaryConverter.cs b/src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicDictionaryConverter.cs index 3e0060aa8..347392765 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicDictionaryConverter.cs +++ b/src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicDictionaryConverter.cs @@ -1,6 +1,6 @@ using System.Text.Json; using System.Text.Json.Serialization; -using Elsa.Expressions.Contracts; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Serialization.Converters; @@ -12,9 +12,9 @@ public class PolymorphicDictionaryConverter : JsonConverter _objectConverter; /// - public PolymorphicDictionaryConverter(JsonSerializerOptions options, IWellKnownTypeRegistry wellKnownTypeRegistry) + public PolymorphicDictionaryConverter(JsonSerializerOptions options, ISerializationTypeRegistry workflowJsonTypeRegistry) { - var factory = (JsonConverterFactory)(options.Converters.FirstOrDefault(x => x is PolymorphicObjectConverterFactory) ?? new PolymorphicObjectConverterFactory(wellKnownTypeRegistry)); + var factory = (JsonConverterFactory)(options.Converters.FirstOrDefault(x => x is PolymorphicObjectConverterFactory) ?? new PolymorphicObjectConverterFactory(workflowJsonTypeRegistry)); _objectConverter = (JsonConverter)factory.CreateConverter(typeof(object), options)!; } @@ -53,4 +53,4 @@ public class PolymorphicDictionaryConverter : JsonConverter private const string IdPropertyName = "$id"; private const string RefPropertyName = "$ref"; private const string ValuesPropertyName = "$values"; - private readonly IWellKnownTypeRegistry _wellKnownTypeRegistry; + private readonly ISerializationTypeRegistry _workflowJsonTypeRegistry; /// /// Initializes a new instance of the class. /// - public PolymorphicObjectConverter(IWellKnownTypeRegistry wellKnownTypeRegistry) + public PolymorphicObjectConverter(ISerializationTypeRegistry workflowJsonTypeRegistry) { - _wellKnownTypeRegistry = wellKnownTypeRegistry; + _workflowJsonTypeRegistry = workflowJsonTypeRegistry; } /// @@ -39,7 +37,7 @@ public class PolymorphicObjectConverter : JsonConverter /// public PolymorphicObjectConverter() { - _wellKnownTypeRegistry = WellKnownTypeRegistry.CreateDefault(); + _workflowJsonTypeRegistry = SerializationTypeRegistry.CreateDefault(); } /// @@ -350,12 +348,12 @@ public class PolymorphicObjectConverter : JsonConverter } // If we found the _type property, attempt to resolve the type. - return typeName != null ? WorkflowJsonTypeResolver.ResolveType(_wellKnownTypeRegistry, typeName) : default; + return typeName != null ? SerializationTypeResolver.ResolveType(_workflowJsonTypeRegistry, typeName) : default; } private void WriteTypeMetadata(Utf8JsonWriter writer, Type type) { - if (!WorkflowJsonTypeResolver.TryGetAlias(_wellKnownTypeRegistry, type, out var typeAlias)) + if (!SerializationTypeResolver.TryGetAlias(_workflowJsonTypeRegistry, type, out var typeAlias)) return; writer.WritePropertyName(TypePropertyName); @@ -370,7 +368,7 @@ public class PolymorphicObjectConverter : JsonConverter if (!targetType.IsInterface && !targetType.IsAbstract) return targetType; - if (WorkflowJsonTypeResolver.TryGetInstantiableCollectionType(targetType, out var instantiableCollectionType)) + if (SerializationTypeResolver.TryGetInstantiableCollectionType(targetType, out var instantiableCollectionType)) return instantiableCollectionType; throw new JsonException($"Workflow JSON type alias resolved to non-instantiable type '{targetType}'."); diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicObjectConverterFactory.cs b/src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicObjectConverterFactory.cs index 9bf659435..0b7b73b69 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicObjectConverterFactory.cs +++ b/src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicObjectConverterFactory.cs @@ -1,8 +1,7 @@ using System.Dynamic; using System.Text.Json; using System.Text.Json.Serialization; -using Elsa.Expressions.Contracts; -using Elsa.Expressions.Services; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Serialization.Converters; @@ -11,14 +10,14 @@ namespace Elsa.Workflows.Serialization.Converters; /// public class PolymorphicObjectConverterFactory : JsonConverterFactory { - private readonly IWellKnownTypeRegistry _wellKnownTypeRegistry; + private readonly ISerializationTypeRegistry _workflowJsonTypeRegistry; /// /// A JSON converter factory that creates instances. /// - public PolymorphicObjectConverterFactory(IWellKnownTypeRegistry wellKnownTypeRegistry) + public PolymorphicObjectConverterFactory(ISerializationTypeRegistry workflowJsonTypeRegistry) { - _wellKnownTypeRegistry = wellKnownTypeRegistry; + _workflowJsonTypeRegistry = workflowJsonTypeRegistry; } /// @@ -26,7 +25,7 @@ public class PolymorphicObjectConverterFactory : JsonConverterFactory /// public PolymorphicObjectConverterFactory() { - _wellKnownTypeRegistry = WellKnownTypeRegistry.CreateDefault(); + _workflowJsonTypeRegistry = SerializationTypeRegistry.CreateDefault(); } /// @@ -49,8 +48,8 @@ public class PolymorphicObjectConverterFactory : JsonConverterFactory public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) { if (typeof(IDictionary).IsAssignableFrom(typeToConvert)) - return new PolymorphicDictionaryConverter(options, _wellKnownTypeRegistry); + return new PolymorphicDictionaryConverter(options, _workflowJsonTypeRegistry); - return new PolymorphicObjectConverter(_wellKnownTypeRegistry); + return new PolymorphicObjectConverter(_workflowJsonTypeRegistry); } } diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Converters/TypeJsonConverter.cs b/src/modules/Elsa.Workflows.Core/Serialization/Converters/TypeJsonConverter.cs index c74191e41..cf2c03385 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/Converters/TypeJsonConverter.cs +++ b/src/modules/Elsa.Workflows.Core/Serialization/Converters/TypeJsonConverter.cs @@ -1,9 +1,8 @@ using System.Text.Json; using System.Text.Json.Serialization; -using Elsa.Expressions.Contracts; using Elsa.Extensions; -using Elsa.Workflows.Serialization.Helpers; using JetBrains.Annotations; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Serialization.Converters; @@ -18,12 +17,18 @@ public class TypeJsonConverter : JsonConverter /// Prefix for unregistered type metadata that is not used for CLR type loading during deserialization. /// private const string UnregisteredTypeAliasPrefix = "UnregisteredClrType:"; - private readonly IWellKnownTypeRegistry _wellKnownTypeRegistry; + private readonly ISerializationTypeRegistry _workflowJsonTypeRegistry; /// - public TypeJsonConverter(IWellKnownTypeRegistry wellKnownTypeRegistry) + public TypeJsonConverter(ISerializationTypeRegistry workflowJsonTypeRegistry) { - _wellKnownTypeRegistry = wellKnownTypeRegistry; + _workflowJsonTypeRegistry = workflowJsonTypeRegistry; + } + + /// + public TypeJsonConverter() + { + _workflowJsonTypeRegistry = SerializationTypeRegistry.CreateDefault(); } /// @@ -39,13 +44,13 @@ public class TypeJsonConverter : JsonConverter if (typeAlias?.StartsWith(UnregisteredTypeAliasPrefix, StringComparison.Ordinal) == true) return typeof(Exception); - return WorkflowJsonTypeResolver.ResolveType(_wellKnownTypeRegistry, typeAlias); + return SerializationTypeResolver.ResolveType(_workflowJsonTypeRegistry, typeAlias); } /// public override void Write(Utf8JsonWriter writer, Type value, JsonSerializerOptions options) { - if (!WorkflowJsonTypeResolver.TryGetAlias(_wellKnownTypeRegistry, value, out var typeAlias)) + if (!SerializationTypeResolver.TryGetAlias(_workflowJsonTypeRegistry, value, out var typeAlias)) typeAlias = $"{UnregisteredTypeAliasPrefix}{value.GetSimpleAssemblyQualifiedName()}"; writer.WriteStringValue(typeAlias); diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Converters/VariableConverter.cs b/src/modules/Elsa.Workflows.Core/Serialization/Converters/VariableConverter.cs index 6dcc60b4e..18184d4da 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/Converters/VariableConverter.cs +++ b/src/modules/Elsa.Workflows.Core/Serialization/Converters/VariableConverter.cs @@ -1,9 +1,9 @@ using System.Text.Json; using System.Text.Json.Serialization; -using Elsa.Expressions.Contracts; using Elsa.Workflows.Memory; using Elsa.Workflows.Models; using Microsoft.Extensions.Logging; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Serialization.Converters; @@ -17,9 +17,9 @@ public class VariableConverter : JsonConverter /// // ReSharper disable once ContextualLoggerProblem - public VariableConverter(IWellKnownTypeRegistry wellKnownTypeRegistry, ILogger logger) + public VariableConverter(ISerializationTypeRegistry workflowJsonTypeRegistry, ILogger logger) { - _mapper = new VariableMapper(wellKnownTypeRegistry, logger); + _mapper = new VariableMapper(workflowJsonTypeRegistry, logger); } /// @@ -49,4 +49,4 @@ public class VariableConverter : JsonConverter _options = newOptions; return newOptions; } -} \ No newline at end of file +} diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Converters/VariableConverterFactory.cs b/src/modules/Elsa.Workflows.Core/Serialization/Converters/VariableConverterFactory.cs index 293ce4e35..f7aaab283 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/Converters/VariableConverterFactory.cs +++ b/src/modules/Elsa.Workflows.Core/Serialization/Converters/VariableConverterFactory.cs @@ -1,8 +1,8 @@ using System.Text.Json; using System.Text.Json.Serialization; -using Elsa.Expressions.Contracts; using Elsa.Workflows.Memory; using Microsoft.Extensions.Logging; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Serialization.Converters; @@ -11,14 +11,14 @@ namespace Elsa.Workflows.Serialization.Converters; /// public class VariableConverterFactory : JsonConverterFactory { - private readonly IWellKnownTypeRegistry _wellKnownTypeRegistry; + private readonly ISerializationTypeRegistry _workflowJsonTypeRegistry; private readonly ILoggerFactory _loggerFactory; /// // ReSharper disable once ContextualLoggerProblem - public VariableConverterFactory(IWellKnownTypeRegistry wellKnownTypeRegistry, ILoggerFactory loggerFactory) + public VariableConverterFactory(ISerializationTypeRegistry workflowJsonTypeRegistry, ILoggerFactory loggerFactory) { - _wellKnownTypeRegistry = wellKnownTypeRegistry; + _workflowJsonTypeRegistry = workflowJsonTypeRegistry; _loggerFactory = loggerFactory; } @@ -26,5 +26,5 @@ public class VariableConverterFactory : JsonConverterFactory public override bool CanConvert(Type typeToConvert) => typeof(Variable).IsAssignableFrom(typeToConvert); /// - public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) => new VariableConverter(_wellKnownTypeRegistry, _loggerFactory.CreateLogger()); -} \ No newline at end of file + public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) => new VariableConverter(_workflowJsonTypeRegistry, _loggerFactory.CreateLogger()); +} diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Serializers/BookmarkPayloadSerializer.cs b/src/modules/Elsa.Workflows.Core/Serialization/Serializers/BookmarkPayloadSerializer.cs index 9dab96949..a2a79b631 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/Serializers/BookmarkPayloadSerializer.cs +++ b/src/modules/Elsa.Workflows.Core/Serialization/Serializers/BookmarkPayloadSerializer.cs @@ -1,6 +1,6 @@ using System.Text.Json; -using Elsa.Expressions.Contracts; using Elsa.Workflows.Serialization.Converters; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Serialization.Serializers; @@ -12,7 +12,7 @@ public class BookmarkPayloadSerializer : IBookmarkPayloadSerializer /// /// Initializes a new instance of the class. /// - public BookmarkPayloadSerializer(IWellKnownTypeRegistry wellKnownTypeRegistry) + public BookmarkPayloadSerializer(ISerializationTypeRegistry workflowJsonTypeRegistry) { _settings = new JsonSerializerOptions { @@ -21,7 +21,7 @@ public class BookmarkPayloadSerializer : IBookmarkPayloadSerializer PropertyNameCaseInsensitive = true, }; - _settings.Converters.Add(new TypeJsonConverter(wellKnownTypeRegistry)); + _settings.Converters.Add(new TypeJsonConverter(workflowJsonTypeRegistry)); _settings.Converters.Add(new FuncExpressionValueConverter()); } diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Serializers/JsonWorkflowStateSerializer.cs b/src/modules/Elsa.Workflows.Core/Serialization/Serializers/JsonWorkflowStateSerializer.cs index faf4215b8..93f8a807d 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/Serializers/JsonWorkflowStateSerializer.cs +++ b/src/modules/Elsa.Workflows.Core/Serialization/Serializers/JsonWorkflowStateSerializer.cs @@ -1,7 +1,6 @@ using System.Diagnostics.CodeAnalysis; using System.Text.Json; using Elsa.Common.Serialization; -using Elsa.Expressions.Contracts; using Elsa.Workflows.Serialization.Converters; using Elsa.Workflows.Serialization.ReferenceHandlers; using Elsa.Workflows.State; @@ -14,16 +13,16 @@ namespace Elsa.Workflows.Serialization.Serializers; /// public class JsonWorkflowStateSerializer : ConfigurableSerializer, IWorkflowStateSerializer { - private readonly IWellKnownTypeRegistry _wellKnownTypeRegistry; + private readonly ISerializationTypeRegistry _workflowJsonTypeRegistry; private readonly ILoggerFactory _loggerFactory; /// /// Initializes a new instance of the class. /// - public JsonWorkflowStateSerializer(IServiceProvider serviceProvider, IWellKnownTypeRegistry wellKnownTypeRegistry, ILoggerFactory loggerFactory) + public JsonWorkflowStateSerializer(IServiceProvider serviceProvider, ISerializationTypeRegistry workflowJsonTypeRegistry, ILoggerFactory loggerFactory) : base(serviceProvider) { - _wellKnownTypeRegistry = wellKnownTypeRegistry; + _workflowJsonTypeRegistry = workflowJsonTypeRegistry; _loggerFactory = loggerFactory; } @@ -135,9 +134,9 @@ public class JsonWorkflowStateSerializer : ConfigurableSerializer, IWorkflowStat /// protected override void AddConverters(JsonSerializerOptions options) { - options.Converters.Add(new TypeJsonConverter(_wellKnownTypeRegistry)); - options.Converters.Add(new PolymorphicObjectConverterFactory(_wellKnownTypeRegistry)); - options.Converters.Add(new VariableConverterFactory(_wellKnownTypeRegistry, _loggerFactory)); + options.Converters.Add(new TypeJsonConverter(_workflowJsonTypeRegistry)); + options.Converters.Add(new PolymorphicObjectConverterFactory(_workflowJsonTypeRegistry)); + options.Converters.Add(new VariableConverterFactory(_workflowJsonTypeRegistry, _loggerFactory)); options.Converters.Add(new FuncExpressionValueConverter()); } } diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Serializers/SafeSerializer.cs b/src/modules/Elsa.Workflows.Core/Serialization/Serializers/SafeSerializer.cs index 281e24b13..c2fadbd2a 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/Serializers/SafeSerializer.cs +++ b/src/modules/Elsa.Workflows.Core/Serialization/Serializers/SafeSerializer.cs @@ -3,7 +3,6 @@ using System.Text.Json; using System.Text.Json.Serialization; using Elsa.Common.Serialization; using Elsa.Expressions.Contracts; -using Elsa.Expressions.Services; using Elsa.Workflows.Serialization.Converters; using Microsoft.Extensions.DependencyInjection; @@ -72,10 +71,10 @@ public class SafeSerializer : ConfigurableSerializer, ISafeSerializer protected override void AddConverters(JsonSerializerOptions options) { var expressionDescriptorRegistry = ServiceProvider.GetRequiredService(); - var wellKnownTypeRegistry = ServiceProvider.GetRequiredService(); + var workflowJsonTypeRegistry = ServiceProvider.GetRequiredService(); options.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)); - options.Converters.Add(new TypeJsonConverter(wellKnownTypeRegistry)); + options.Converters.Add(new TypeJsonConverter(workflowJsonTypeRegistry)); options.Converters.Add(new SafeValueConverterFactory()); options.Converters.Add(new ExpressionJsonConverterFactory(expressionDescriptorRegistry)); options.Converters.Add(new FuncExpressionValueConverter()); diff --git a/src/modules/Elsa.Workflows.Core/Services/Hasher.cs b/src/modules/Elsa.Workflows.Core/Services/Hasher.cs index 808a8684b..be018cd7d 100644 --- a/src/modules/Elsa.Workflows.Core/Services/Hasher.cs +++ b/src/modules/Elsa.Workflows.Core/Services/Hasher.cs @@ -2,8 +2,8 @@ using System.Security.Cryptography; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; -using Elsa.Expressions.Contracts; using Elsa.Workflows.Serialization.Converters; +using Elsa.Common.Serialization; namespace Elsa.Workflows; @@ -12,7 +12,7 @@ public class Hasher : IHasher { private readonly JsonSerializerOptions _serializerOptions; - public Hasher(IWellKnownTypeRegistry wellKnownTypeRegistry) + public Hasher(ISerializationTypeRegistry workflowJsonTypeRegistry) { _serializerOptions = new JsonSerializerOptions { @@ -21,7 +21,7 @@ public class Hasher : IHasher DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }; - _serializerOptions.Converters.Add(new TypeJsonConverter(wellKnownTypeRegistry)); + _serializerOptions.Converters.Add(new TypeJsonConverter(workflowJsonTypeRegistry)); _serializerOptions.Converters.Add(new ExcludeFromHashConverterFactory()); } @@ -50,4 +50,4 @@ public class Hasher : IHasher return JsonSerializer.Serialize(payload, payload.GetType(), _serializerOptions); } -} \ No newline at end of file +} diff --git a/src/modules/Elsa.Workflows.Core/Services/VariableMapper.cs b/src/modules/Elsa.Workflows.Core/Services/VariableMapper.cs index 91c19fd03..430c746f1 100644 --- a/src/modules/Elsa.Workflows.Core/Services/VariableMapper.cs +++ b/src/modules/Elsa.Workflows.Core/Services/VariableMapper.cs @@ -1,13 +1,11 @@ -using Elsa.Expressions.Contracts; -using Elsa.Expressions.Extensions; using Elsa.Expressions.Helpers; -using Elsa.Expressions.Services; using Elsa.Extensions; using Elsa.Workflows.Memory; using Elsa.Workflows.Models; -using Elsa.Workflows.Serialization.Helpers; +using Elsa.Workflows.Services; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Elsa.Common.Serialization; namespace Elsa.Workflows; @@ -17,21 +15,21 @@ namespace Elsa.Workflows; public class VariableMapper { private readonly ILogger _logger; - private readonly IWellKnownTypeRegistry _wellKnownTypeRegistry; + private readonly ISerializationTypeRegistry _workflowJsonTypeRegistry; /// /// Initializes a new instance of the class. /// - /// The well-known type registry. + /// The serialization type registry. /// The logger. - public VariableMapper(IWellKnownTypeRegistry wellKnownTypeRegistry, ILogger logger) + public VariableMapper(ISerializationTypeRegistry workflowJsonTypeRegistry, ILogger logger) { - _wellKnownTypeRegistry = wellKnownTypeRegistry; + _workflowJsonTypeRegistry = workflowJsonTypeRegistry; _logger = logger; } /// - public VariableMapper() : this(new WellKnownTypeRegistry(), NullLogger.Instance) + public VariableMapper() : this(SerializationTypeRegistry.CreateDefault(), NullLogger.Instance) { } @@ -67,19 +65,27 @@ public class VariableMapper var variableType = source.GetType(); var value = source.Value; var valueType = variableType.IsConstructedGenericType ? variableType.GetGenericArguments().FirstOrDefault() ?? typeof(object) : typeof(object); - var valueTypeAlias = _wellKnownTypeRegistry.GetAliasOrDefault(valueType); - var storageDriverTypeName = source.StorageDriverType?.GetSimpleAssemblyQualifiedName(); + var valueTypeAlias = SerializationTypeResolver.TryGetAlias(_workflowJsonTypeRegistry, valueType, out var alias) ? alias : valueType.GetSimpleAssemblyQualifiedName(); + var storageDriverTypeName = GetTypeName(source.StorageDriverType); var serializedValue = value.Format(); return new(source.Id, source.Name, valueTypeAlias, serializedValue, storageDriverTypeName); } + private string? GetTypeName(Type? type) + { + if (type == null) + return null; + + return SerializationTypeResolver.TryGetAlias(_workflowJsonTypeRegistry, type, out var alias) ? alias : type.GetSimpleAssemblyQualifiedName(); + } + private Type ResolveVariableType(string? typeAlias) { if (string.IsNullOrWhiteSpace(typeAlias)) return typeof(object); - if (WorkflowJsonTypeResolver.TryResolveType(_wellKnownTypeRegistry, typeAlias, out var type)) + if (SerializationTypeResolver.TryResolveType(_workflowJsonTypeRegistry, typeAlias, out var type)) return type; _logger.LogWarning("Failed to resolve variable type alias {VariableTypeName}", typeAlias); @@ -91,7 +97,7 @@ public class VariableMapper if (string.IsNullOrWhiteSpace(typeAlias)) return null; - if (WorkflowJsonTypeResolver.TryResolveType(_wellKnownTypeRegistry, typeAlias, out var type) && IsStorageDriverType(type)) + if (SerializationTypeResolver.TryResolveType(_workflowJsonTypeRegistry, typeAlias, out var type) && IsStorageDriverType(type)) return type; _logger.LogWarning("Failed to resolve storage driver type alias {StorageDriverTypeName}", typeAlias); diff --git a/src/modules/Elsa.Workflows.Core/ShellFeatures/FlowchartFeature.cs b/src/modules/Elsa.Workflows.Core/ShellFeatures/FlowchartFeature.cs index b7d9fdce3..6307b5ae8 100644 --- a/src/modules/Elsa.Workflows.Core/ShellFeatures/FlowchartFeature.cs +++ b/src/modules/Elsa.Workflows.Core/ShellFeatures/FlowchartFeature.cs @@ -1,9 +1,12 @@ using CShells.Features; using Elsa.Extensions; +using Elsa.Workflows.Activities.Flowchart.Models; using Elsa.Workflows.Activities.Flowchart.Options; using Elsa.Workflows.Activities.Flowchart.Serialization; +using Elsa.Workflows.Options; using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; +using Elsa.Common.Serialization; namespace Elsa.Workflows.ShellFeatures; @@ -30,6 +33,7 @@ public class FlowchartFeature : IShellFeature if (FlowchartOptionsConfigurator != null) services.Configure(FlowchartOptionsConfigurator); + + services.Configure(options => options.AddTypeAlias("FlowScope")); } } - diff --git a/src/modules/Elsa.Workflows.Core/ShellFeatures/WorkflowsFeature.cs b/src/modules/Elsa.Workflows.Core/ShellFeatures/WorkflowsFeature.cs index b3617a45a..a9c6a065e 100644 --- a/src/modules/Elsa.Workflows.Core/ShellFeatures/WorkflowsFeature.cs +++ b/src/modules/Elsa.Workflows.Core/ShellFeatures/WorkflowsFeature.cs @@ -5,15 +5,18 @@ using Elsa.Common.ShellFeatures; using Elsa.Expressions.ShellFeatures; using Elsa.Extensions; using Elsa.Workflows.ActivationValidators; +using Elsa.Workflows.Activities.Flowchart.Models; using Elsa.Workflows.Activities.Flowchart.Options; using Elsa.Workflows.Activities.Flowchart.Serialization; using Elsa.Workflows.Builders; using Elsa.Workflows.CommitStates; +using Elsa.Workflows.Exceptions; using Elsa.Workflows.IncidentStrategies; using Elsa.Workflows.LogPersistence; using Elsa.Workflows.LogPersistence.Strategies; using Elsa.Workflows.Middleware.Activities; using Elsa.Workflows.Middleware.Workflows; +using Elsa.Workflows.Options; using Elsa.Workflows.Pipelines.ActivityExecution; using Elsa.Workflows.Pipelines.WorkflowExecution; using Elsa.Workflows.PortResolvers; @@ -21,12 +24,14 @@ using Elsa.Workflows.Serialization.Configurators; using Elsa.Workflows.Serialization.Helpers; using Elsa.Workflows.Serialization.Serializers; using Elsa.Workflows.Services; +using Elsa.Workflows.State; using Elsa.Workflows.UIHints.CheckList; using Elsa.Workflows.UIHints.Dictionary; using Elsa.Workflows.UIHints.Dropdown; using Elsa.Workflows.UIHints.JsonEditor; using Elsa.Workflows.UIHints.RadioList; using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json.Linq; namespace Elsa.Workflows.ShellFeatures; @@ -54,7 +59,12 @@ public class WorkflowsFeature : IShellFeature /// /// A delegate to configure the . /// - public Action ActivityExecutionPipeline { get; set; } = builder => builder.UseDefaultActivityInvoker(); + public Action ActivityExecutionPipeline { get; set; } = builder => builder + .UseLogging() + .UseExceptionHandling() + .UseExecutionLogging() + .UseNotifications() + .UseDefaultActivityInvoker(); /// /// A factory that instantiates a concrete . @@ -78,6 +88,32 @@ public class WorkflowsFeature : IShellFeature public void ConfigureServices(IServiceCollection services) { + services.Configure(options => + { + options.AddTypeAlias(nameof(ExceptionState)); + options.AddTypeAlias(nameof(FaultException)); + options.AddTypeAlias(nameof(VariablesDictionary)); + options.AddTypeAlias(nameof(Token)); + options.RegisterLegacyTypeName(typeof(FlowJoinMode), "Elsa.Workflows.Core.Activities.Flowchart.Models.FlowJoinMode, Elsa.Workflows.Core"); + options.AddTypeAliasWithLegacyName(nameof(FlowJoinMode)); + options.AddTypeAliasWithLegacyName(nameof(WorkflowStorageDriver)); + options.AddTypeAliasWithLegacyName(nameof(WorkflowInstanceStorageDriver)); + options.AddTypeAliasWithLegacyName(nameof(MemoryStorageDriver)); + options.AddTypeAliasWithLegacyName(nameof(FaultStrategy)); + options.AddTypeAliasWithLegacyName(nameof(ContinueWithIncidentsStrategy)); + options.AddTypeAlias(nameof(Exception)); + options.AddTypeAlias(nameof(ArgumentException)); + options.AddTypeAlias(nameof(ArgumentNullException)); + options.AddTypeAlias(nameof(InvalidOperationException)); + options.AddTypeAlias(nameof(NullReferenceException)); + options.AddTypeAlias(nameof(OperationCanceledException)); + options.AddTypeAlias(nameof(TaskCanceledException)); + options.AddTypeAlias(nameof(TimeoutException)); + options.AddTypeAlias(nameof(NotSupportedException)); + options.AddTypeAlias(nameof(JObject)); + options.AddTypeAlias(nameof(JArray)); + }); + services // Core. .AddScoped() @@ -147,6 +183,7 @@ public class WorkflowsFeature : IShellFeature .AddStorageDriver() // Serialization. + .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() diff --git a/src/modules/Elsa.Workflows.Management/Extensions/ManagementServiceCollectionExtensions.cs b/src/modules/Elsa.Workflows.Management/Extensions/ManagementServiceCollectionExtensions.cs index 0eadcf65b..6b83d8e39 100644 --- a/src/modules/Elsa.Workflows.Management/Extensions/ManagementServiceCollectionExtensions.cs +++ b/src/modules/Elsa.Workflows.Management/Extensions/ManagementServiceCollectionExtensions.cs @@ -2,7 +2,9 @@ using System.Reflection; using Elsa.Expressions.Extensions; using Elsa.Workflows.Management.Models; using Elsa.Workflows.Management.Options; +using Elsa.Workflows.Options; using Microsoft.Extensions.DependencyInjection; +using Elsa.Common.Serialization; // ReSharper disable once CheckNamespace namespace Elsa.Workflows.Management.Extensions; @@ -98,8 +100,9 @@ public static class ManagementServiceCollectionExtensions /// public static IServiceCollection AddVariableTypeAndAlias(this IServiceCollection services, string alias, string category) { + services.Configure(options => options.RegisterTypeAlias(typeof(T), alias)); return services .AddVariableDescriptor(category) .AddTypeAlias(alias); } -} \ No newline at end of file +} diff --git a/src/modules/Elsa.Workflows.Management/Extensions/ModuleExtensions.cs b/src/modules/Elsa.Workflows.Management/Extensions/ModuleExtensions.cs index 55e72f630..36cc410ae 100644 --- a/src/modules/Elsa.Workflows.Management/Extensions/ModuleExtensions.cs +++ b/src/modules/Elsa.Workflows.Management/Extensions/ModuleExtensions.cs @@ -2,6 +2,9 @@ using Elsa.Features.Services; using Elsa.Workflows; using Elsa.Workflows.Activities; using Elsa.Workflows.Management.Features; +using Elsa.Workflows.Options; +using Microsoft.Extensions.DependencyInjection; +using Elsa.Common.Serialization; // ReSharper disable once CheckNamespace namespace Elsa.Extensions; @@ -72,6 +75,8 @@ public static class ModuleExtensions /// public static IModule AddVariableTypeAndAlias(this IModule module, string alias, string category) { + module.Services.Configure(options => options.RegisterTypeAlias(typeof(T), alias)); + return module .UseWorkflowManagement(management => management.AddVariableType(category)) .AddTypeAlias(alias); @@ -85,4 +90,4 @@ public static class ModuleExtensions feature.Module.Configure(configure); return feature; } -} \ No newline at end of file +} diff --git a/src/modules/Elsa.Workflows.Management/Extensions/WorkflowManagementFeatureExtensions.cs b/src/modules/Elsa.Workflows.Management/Extensions/WorkflowManagementFeatureExtensions.cs index 12d91f384..58ab08a73 100644 --- a/src/modules/Elsa.Workflows.Management/Extensions/WorkflowManagementFeatureExtensions.cs +++ b/src/modules/Elsa.Workflows.Management/Extensions/WorkflowManagementFeatureExtensions.cs @@ -1,6 +1,9 @@ using Elsa.Extensions; using Elsa.Workflows.Management.Features; +using Elsa.Workflows.Options; using JetBrains.Annotations; +using Microsoft.Extensions.DependencyInjection; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Management; @@ -16,6 +19,7 @@ public static class WorkflowManagementFeatureExtensions { management.AddVariableType(category); management.Module.AddTypeAlias(alias); + management.Module.Services.Configure(options => options.RegisterTypeAlias(typeof(T), alias)); return management; } -} \ No newline at end of file +} diff --git a/src/modules/Elsa.Workflows.Management/Features/WorkflowManagementFeature.cs b/src/modules/Elsa.Workflows.Management/Features/WorkflowManagementFeature.cs index 46608c0c7..0a26da083 100644 --- a/src/modules/Elsa.Workflows.Management/Features/WorkflowManagementFeature.cs +++ b/src/modules/Elsa.Workflows.Management/Features/WorkflowManagementFeature.cs @@ -27,10 +27,12 @@ using Elsa.Workflows.Management.Options; using Elsa.Workflows.Management.Providers; using Elsa.Workflows.Management.Services; using Elsa.Workflows.Management.Stores; +using Elsa.Workflows.Options; using Elsa.Workflows.Serialization.Serializers; using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Management.Features; @@ -314,6 +316,7 @@ public class WorkflowManagementFeature(IModule module) : FeatureBase(module) }); Services.Configure(options => options.RegisterTypeAlias(typeof(ClrWorkflowMaterializerContext), nameof(ClrWorkflowMaterializerContext))); + Services.Configure(options => options.RegisterTypeAlias(typeof(ClrWorkflowMaterializerContext), nameof(ClrWorkflowMaterializerContext))); Services.Configure(_ => { }); Services.Configure(_ => { }); } diff --git a/src/modules/Elsa.Workflows.Management/Mappers/VariableDefinitionMapper.cs b/src/modules/Elsa.Workflows.Management/Mappers/VariableDefinitionMapper.cs index cd0bc53b7..80568cc9b 100644 --- a/src/modules/Elsa.Workflows.Management/Mappers/VariableDefinitionMapper.cs +++ b/src/modules/Elsa.Workflows.Management/Mappers/VariableDefinitionMapper.cs @@ -1,26 +1,25 @@ -using Elsa.Expressions.Contracts; -using Elsa.Expressions.Extensions; using Elsa.Expressions.Helpers; using Elsa.Extensions; using Elsa.Workflows.Memory; using Elsa.Workflows.Models; +using Elsa.Workflows.Services; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Management.Mappers; /// /// Maps s to s and vice versa. /// -public class VariableDefinitionMapper(IWellKnownTypeRegistry wellKnownTypeRegistry, IServiceScopeFactory scopeFactory, ILogger logger) +public class VariableDefinitionMapper(ISerializationTypeRegistry workflowJsonTypeRegistry, IServiceScopeFactory scopeFactory, ILogger logger) { /// /// Maps a to a . /// public Variable? Map(VariableDefinition source) { - var aliasedType = wellKnownTypeRegistry.TryGetType(source.TypeName, out var aliasedTypeValue) ? aliasedTypeValue : null; - var type = aliasedType ?? Type.GetType(source.TypeName); + var type = SerializationTypeResolver.TryResolveType(workflowJsonTypeRegistry, source.TypeName, out var resolvedType) ? resolvedType : null; if (type == null) { @@ -28,7 +27,7 @@ public class VariableDefinitionMapper(IWellKnownTypeRegistry wellKnownTypeRegist return null; } - var valueType = aliasedType is { IsArray: true } ? source.IsArray ? aliasedType.MakeArrayType() : aliasedType : source.IsArray ? type.MakeArrayType() : type; + var valueType = type.IsArray ? source.IsArray ? type.MakeArrayType() : type : source.IsArray ? type.MakeArrayType() : type; var variableGenericType = typeof(Variable<>).MakeGenericType(valueType); var variable = (Variable)Activator.CreateInstance(variableGenericType)!; @@ -70,10 +69,14 @@ public class VariableDefinitionMapper(IWellKnownTypeRegistry wellKnownTypeRegist { var variableType = source.GetType(); var valueType = variableType.IsConstructedGenericType ? variableType.GetGenericArguments().FirstOrDefault() ?? typeof(object) : typeof(object); - var valueTypeAlias = wellKnownTypeRegistry.TryGetAlias(valueType, out var alias) ? alias : null; + var valueTypeAlias = SerializationTypeResolver.TryGetAlias(workflowJsonTypeRegistry, valueType, out var alias) ? alias : null; var value = source.Value; var serializedValue = value.Format(); - var storageDriverTypeName = source.StorageDriverType?.GetSimpleAssemblyQualifiedName(); + var storageDriverTypeName = source.StorageDriverType != null + ? SerializationTypeResolver.TryGetAlias(workflowJsonTypeRegistry, source.StorageDriverType, out var storageDriverAlias) + ? storageDriverAlias + : source.StorageDriverType.GetSimpleAssemblyQualifiedName() + : null; // Handles the case where an alias exists for an array or collection type. E.g. byte[] -> ByteArray. if (valueTypeAlias != null && (valueType.IsArray || valueType.IsCollectionType())) @@ -82,7 +85,9 @@ public class VariableDefinitionMapper(IWellKnownTypeRegistry wellKnownTypeRegist var isArray = valueType.IsArray; var isCollection = valueType.IsCollectionType(); var elementValueType = isArray ? valueType.GetElementType()! : isCollection ? valueType.GenericTypeArguments[0] : valueType; - var elementTypeAlias = wellKnownTypeRegistry.GetAliasOrDefault(elementValueType); + var elementTypeAlias = SerializationTypeResolver.TryGetAlias(workflowJsonTypeRegistry, elementValueType, out var elementAlias) + ? elementAlias + : elementValueType.GetSimpleAssemblyQualifiedName(); return new(source.Id, source.Name, elementTypeAlias, isArray, serializedValue, storageDriverTypeName); } @@ -97,9 +102,7 @@ public class VariableDefinitionMapper(IWellKnownTypeRegistry wellKnownTypeRegist if (string.IsNullOrEmpty(storageDriverTypeName)) return null; - var type = Type.GetType(storageDriverTypeName); - - if (type != null) + if (SerializationTypeResolver.TryResolveType(workflowJsonTypeRegistry, storageDriverTypeName, out var type) && typeof(IStorageDriver).IsAssignableFrom(type)) return type; // TODO: The following code handles backward compatibility with variable definitions referencing older .NET type namespaces. @@ -115,4 +118,4 @@ public class VariableDefinitionMapper(IWellKnownTypeRegistry wellKnownTypeRegist return null; } -} \ No newline at end of file +} diff --git a/src/modules/Elsa.Workflows.Management/ShellFeatures/WorkflowManagementFeature.cs b/src/modules/Elsa.Workflows.Management/ShellFeatures/WorkflowManagementFeature.cs index d34feb336..b16f21d03 100644 --- a/src/modules/Elsa.Workflows.Management/ShellFeatures/WorkflowManagementFeature.cs +++ b/src/modules/Elsa.Workflows.Management/ShellFeatures/WorkflowManagementFeature.cs @@ -7,6 +7,7 @@ using Elsa.Common.Features; using Elsa.Expressions.Contracts; using Elsa.Extensions; using Elsa.Features.Attributes; +using Elsa.Workflows.Options; using Elsa.Workflows.Features; using Elsa.Workflows.Management.Activities.WorkflowDefinitionActivity; using Elsa.Workflows.Management.Contracts; @@ -24,6 +25,7 @@ using Elsa.Workflows.Management.Stores; using Elsa.Workflows.Serialization.Serializers; using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Management.ShellFeatures; @@ -131,5 +133,7 @@ public class WorkflowManagementFeature : IShellFeature // Register the default variable descriptors declared on this feature. services.AddVariableDescriptors(VariableDescriptors); + + services.Configure(options => options.RegisterTypeAlias(typeof(ClrWorkflowMaterializerContext), nameof(ClrWorkflowMaterializerContext))); } -} \ No newline at end of file +} diff --git a/src/modules/Elsa.Workflows.Runtime/Comparers/WorkflowTriggerEqualityComparer.cs b/src/modules/Elsa.Workflows.Runtime/Comparers/WorkflowTriggerEqualityComparer.cs index 45498dd5e..dea87c00c 100644 --- a/src/modules/Elsa.Workflows.Runtime/Comparers/WorkflowTriggerEqualityComparer.cs +++ b/src/modules/Elsa.Workflows.Runtime/Comparers/WorkflowTriggerEqualityComparer.cs @@ -1,10 +1,10 @@ using System.Text.Json; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Metadata; -using Elsa.Expressions.Contracts; -using Elsa.Expressions.Services; using Elsa.Workflows.Runtime.Entities; using Elsa.Workflows.Serialization.Converters; +using Elsa.Workflows.Services; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Runtime.Comparers; @@ -18,14 +18,14 @@ public class WorkflowTriggerEqualityComparer : IEqualityComparer /// /// Initializes a new instance of the class. /// - public WorkflowTriggerEqualityComparer() : this(WellKnownTypeRegistry.CreateDefault()) + public WorkflowTriggerEqualityComparer() : this(SerializationTypeRegistry.CreateDefault()) { } /// /// Initializes a new instance of the class. /// - public WorkflowTriggerEqualityComparer(IWellKnownTypeRegistry wellKnownTypeRegistry) + public WorkflowTriggerEqualityComparer(ISerializationTypeRegistry workflowJsonTypeRegistry) { _settings = new() { @@ -44,8 +44,8 @@ public class WorkflowTriggerEqualityComparer : IEqualityComparer // polymorphic object properties serialize identically to their stored representation. _settings.Converters.Add(new JsonStringEnumConverter()); _settings.Converters.Add(JsonMetadataServices.TimeSpanConverter); - _settings.Converters.Add(new PolymorphicObjectConverterFactory(wellKnownTypeRegistry)); - _settings.Converters.Add(new TypeJsonConverter(wellKnownTypeRegistry)); + _settings.Converters.Add(new PolymorphicObjectConverterFactory(workflowJsonTypeRegistry)); + _settings.Converters.Add(new TypeJsonConverter(workflowJsonTypeRegistry)); } /// diff --git a/src/modules/Elsa.Workflows.Runtime/Discovery/WorkflowTypeScanner.cs b/src/modules/Elsa.Workflows.Runtime/Discovery/WorkflowTypeScanner.cs new file mode 100644 index 000000000..207a0d212 --- /dev/null +++ b/src/modules/Elsa.Workflows.Runtime/Discovery/WorkflowTypeScanner.cs @@ -0,0 +1,14 @@ +using System.Diagnostics.CodeAnalysis; +using System.Reflection; + +namespace Elsa.Workflows.Runtime.Discovery; + +internal static class WorkflowTypeScanner +{ + [RequiresUnreferencedCode("The assembly is required to be referenced.")] + public static IEnumerable GetWorkflowTypes(Assembly assembly) + { + return assembly.GetExportedTypes() + .Where(x => typeof(IWorkflow).IsAssignableFrom(x) && x is { IsAbstract: false, IsInterface: false, ContainsGenericParameters: false }); + } +} diff --git a/src/modules/Elsa.Workflows.Runtime/Extensions/DependencyInjectionExtensions.cs b/src/modules/Elsa.Workflows.Runtime/Extensions/DependencyInjectionExtensions.cs index 40ef0c3f1..b99773b31 100644 --- a/src/modules/Elsa.Workflows.Runtime/Extensions/DependencyInjectionExtensions.cs +++ b/src/modules/Elsa.Workflows.Runtime/Extensions/DependencyInjectionExtensions.cs @@ -1,9 +1,16 @@ +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using Elsa.Extensions; +using Elsa.Workflows; +using Elsa.Workflows.Options; using Elsa.Workflows.Runtime; using Elsa.Workflows.Runtime.Contracts; +using Elsa.Workflows.Runtime.Discovery; using Elsa.Workflows.Runtime.Options; using Elsa.Workflows.Runtime.Providers; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; +using Elsa.Common.Serialization; // ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection; @@ -51,4 +58,42 @@ public static class DependencyInjectionExtensions /// /// The type of the workflows provider to add. Must implement . public static IServiceCollection AddWorkflowsProvider(this IServiceCollection services) where T : class, IWorkflowsProvider => services.AddScoped(); -} \ No newline at end of file + + /// + /// Registers the specified code-first workflow type. + /// + public static IServiceCollection AddWorkflow(this IServiceCollection services) where T : IWorkflow => services.AddWorkflow(typeof(T)); + + /// + /// Registers the specified code-first workflow type. + /// + public static IServiceCollection AddWorkflow(this IServiceCollection services, Type workflowType) + { + AddWorkflowRegistration(services, workflowType); + return services; + } + + /// + /// Registers all code-first workflows contained in the assembly containing the specified marker type. + /// + [RequiresUnreferencedCode("The assembly is required to be referenced.")] + public static IServiceCollection AddWorkflowsFrom(this IServiceCollection services) => services.AddWorkflowsFrom(typeof(TMarker).Assembly); + + /// + /// Registers all code-first workflows in the specified assembly. + /// + [RequiresUnreferencedCode("The assembly is required to be referenced.")] + public static IServiceCollection AddWorkflowsFrom(this IServiceCollection services, Assembly assembly) + { + foreach (var workflowType in WorkflowTypeScanner.GetWorkflowTypes(assembly)) + AddWorkflowRegistration(services, workflowType); + + return services; + } + + private static void AddWorkflowRegistration(IServiceCollection services, Type workflowType) + { + services.PostConfigure(options => options.Workflows.Add(workflowType)); + services.Configure(options => options.AddSimpleAssemblyQualifiedTypeAlias(workflowType)); + } +} diff --git a/src/modules/Elsa.Workflows.Runtime/Extensions/WorkflowDictionaryExtensions.cs b/src/modules/Elsa.Workflows.Runtime/Extensions/WorkflowDictionaryExtensions.cs index 952c28da7..0967c0276 100644 --- a/src/modules/Elsa.Workflows.Runtime/Extensions/WorkflowDictionaryExtensions.cs +++ b/src/modules/Elsa.Workflows.Runtime/Extensions/WorkflowDictionaryExtensions.cs @@ -1,5 +1,4 @@ using Elsa.Workflows; -using Elsa.Workflows.Runtime.Helpers; using Microsoft.Extensions.DependencyInjection; // ReSharper disable once CheckNamespace @@ -23,7 +22,10 @@ public static class WorkflowDictionaryExtensions /// public static void Add(this IDictionary>> dictionary, Type workflowType) { - WorkflowTypeValidator.Validate(workflowType); + ValidateWorkflowType(workflowType); + + if (string.IsNullOrWhiteSpace(workflowType.FullName)) + throw new ArgumentException($"Workflow type '{workflowType.Name}' must have a full name.", nameof(workflowType)); var key = workflowType.GetSimpleAssemblyQualifiedName(); var legacyKey = workflowType.FullName; @@ -45,8 +47,16 @@ public static class WorkflowDictionaryExtensions if (!string.IsNullOrWhiteSpace(legacyKey) && legacyKey != key) dictionary[legacyKey] = factory!; - - if (dictionary is IWorkflowTypeRegistry workflowTypeRegistry) - workflowTypeRegistry.AddWorkflowType(workflowType); } + + private static void ValidateWorkflowType(Type workflowType) + { + if (!typeof(IWorkflow).IsAssignableFrom(workflowType)) + throw new ArgumentException($"Workflow type '{GetDisplayName(workflowType)}' must implement {nameof(IWorkflow)}.", nameof(workflowType)); + + if (workflowType.IsAbstract || workflowType.IsInterface || workflowType.ContainsGenericParameters) + throw new ArgumentException($"Workflow type '{GetDisplayName(workflowType)}' must be a concrete, closed type.", nameof(workflowType)); + } + + private static string GetDisplayName(Type type) => type.FullName ?? type.Name; } diff --git a/src/modules/Elsa.Workflows.Runtime/Features/WorkflowRuntimeFeature.cs b/src/modules/Elsa.Workflows.Runtime/Features/WorkflowRuntimeFeature.cs index 870c4148d..9d50fe713 100644 --- a/src/modules/Elsa.Workflows.Runtime/Features/WorkflowRuntimeFeature.cs +++ b/src/modules/Elsa.Workflows.Runtime/Features/WorkflowRuntimeFeature.cs @@ -4,7 +4,6 @@ using Elsa.Common; using Elsa.Common.DistributedHosting; using Elsa.Common.Features; using Elsa.Common.RecurringTasks; -using Elsa.Expressions.Options; using Elsa.Extensions; using Elsa.Features.Abstractions; using Elsa.Features.Attributes; @@ -14,11 +13,12 @@ using Elsa.Workflows.Features; using Elsa.Workflows.Management; using Elsa.Workflows.Management.Contracts; using Elsa.Workflows.Management.Services; +using Elsa.Workflows.Options; using Elsa.Workflows.Runtime.ActivationValidators; using Elsa.Workflows.Runtime.Bookmarks; +using Elsa.Workflows.Runtime.Discovery; using Elsa.Workflows.Runtime.Entities; using Elsa.Workflows.Runtime.Handlers; -using Elsa.Workflows.Runtime.Helpers; using Elsa.Workflows.Runtime.Models; using Elsa.Workflows.Runtime.Options; using Elsa.Workflows.Runtime.Providers; @@ -31,6 +31,7 @@ using Medallion.Threading.FileSystem; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Runtime.Features; @@ -46,7 +47,7 @@ public class WorkflowRuntimeFeature(IModule module) : FeatureBase(module) /// /// A list of workflow builders configured during application startup. /// - public IDictionary>> Workflows { get; set; } = new WorkflowFactoryDictionary(); + public IDictionary>> Workflows { get; set; } = new Dictionary>>(); private ISet WorkflowTypes { get; } = new HashSet(); /// @@ -202,7 +203,6 @@ public class WorkflowRuntimeFeature(IModule module) : FeatureBase(module) /// public WorkflowRuntimeFeature AddWorkflow(Type workflowType) { - WorkflowTypeValidator.Validate(workflowType); Workflows.Add(workflowType); WorkflowTypes.Add(workflowType); return this; @@ -214,11 +214,7 @@ public class WorkflowRuntimeFeature(IModule module) : FeatureBase(module) [RequiresUnreferencedCode("The assembly is required to be referenced.")] public WorkflowRuntimeFeature AddWorkflowsFrom(Assembly assembly) { - var workflowTypes = assembly.GetExportedTypes() - .Where(x => typeof(IWorkflow).IsAssignableFrom(x) && x is { IsAbstract: false, IsInterface: false, ContainsGenericParameters: false }) - .ToList(); - - foreach (var workflowType in workflowTypes) + foreach (var workflowType in WorkflowTypeScanner.GetWorkflowTypes(assembly)) AddWorkflow(workflowType); return this; @@ -275,7 +271,7 @@ public class WorkflowRuntimeFeature(IModule module) : FeatureBase(module) Services.Configure(WorkflowInboxCleanupOptions); Services.Configure(WorkflowDispatcherOptions); Services.Configure(BookmarkQueuePurgeOptions); - Services.Configure(RegisterWorkflowTypeAliases); + Services.Configure(RegisterWorkflowTypeAliases); Services.Configure(options => { options.Workflows = Workflows; }); Services.Configure(options => { @@ -448,12 +444,33 @@ public class WorkflowRuntimeFeature(IModule module) : FeatureBase(module) Services.TryAddScoped(); } - private void RegisterWorkflowTypeAliases(ExpressionOptions options) + private void RegisterWorkflowTypeAliases(SerializationTypeOptions options) { - var workflowTypes = Workflows is IWorkflowTypeRegistry workflowTypeRegistry - ? WorkflowTypes.Concat(workflowTypeRegistry.WorkflowTypes) - : WorkflowTypes; + WorkflowRuntimeTypeAliasRegistrar.Register(options, GetRegisteredWorkflowTypes()); + } - WorkflowRuntimeTypeAliasRegistrar.Register(options, workflowTypes); + private IEnumerable GetRegisteredWorkflowTypes() + { + return WorkflowTypes + .Concat(Workflows.Keys.Select(TryResolveWorkflowType).Where(type => type != null).Select(type => type!)) + .Distinct(); + } + + private static Type? TryResolveWorkflowType(string typeName) + { + Type? type; + + try + { + type = Type.GetType(typeName, false); + } + catch (Exception e) when (e is ArgumentException or FileLoadException or FileNotFoundException or TypeLoadException or BadImageFormatException) + { + return null; + } + + return type != null && typeof(IWorkflow).IsAssignableFrom(type) && type is { IsAbstract: false, IsInterface: false, ContainsGenericParameters: false } + ? type + : null; } } diff --git a/src/modules/Elsa.Workflows.Runtime/Helpers/IWorkflowTypeRegistry.cs b/src/modules/Elsa.Workflows.Runtime/Helpers/IWorkflowTypeRegistry.cs deleted file mode 100644 index 4b7b977f2..000000000 --- a/src/modules/Elsa.Workflows.Runtime/Helpers/IWorkflowTypeRegistry.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Elsa.Workflows.Runtime.Helpers; - -internal interface IWorkflowTypeRegistry -{ - IEnumerable WorkflowTypes { get; } - - void AddWorkflowType(Type workflowType); -} diff --git a/src/modules/Elsa.Workflows.Runtime/Helpers/WorkflowFactoryDictionary.cs b/src/modules/Elsa.Workflows.Runtime/Helpers/WorkflowFactoryDictionary.cs deleted file mode 100644 index 872f80423..000000000 --- a/src/modules/Elsa.Workflows.Runtime/Helpers/WorkflowFactoryDictionary.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Elsa.Workflows; - -namespace Elsa.Workflows.Runtime.Helpers; - -internal sealed class WorkflowFactoryDictionary : Dictionary>>, IWorkflowTypeRegistry -{ - private readonly ISet _workflowTypes = new HashSet(); - - public IEnumerable WorkflowTypes => _workflowTypes; - - public void AddWorkflowType(Type workflowType) - { - WorkflowTypeValidator.Validate(workflowType); - _workflowTypes.Add(workflowType); - } -} diff --git a/src/modules/Elsa.Workflows.Runtime/Helpers/WorkflowTypeValidator.cs b/src/modules/Elsa.Workflows.Runtime/Helpers/WorkflowTypeValidator.cs deleted file mode 100644 index 069aed8ab..000000000 --- a/src/modules/Elsa.Workflows.Runtime/Helpers/WorkflowTypeValidator.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Elsa.Workflows; - -namespace Elsa.Workflows.Runtime.Helpers; - -internal static class WorkflowTypeValidator -{ - public static void Validate(Type workflowType) - { - if (!typeof(IWorkflow).IsAssignableFrom(workflowType)) - throw new ArgumentException($"Workflow type '{GetDisplayName(workflowType)}' must implement {nameof(IWorkflow)}.", nameof(workflowType)); - - if (workflowType.IsAbstract || workflowType.IsInterface || workflowType.IsGenericTypeDefinition || workflowType.ContainsGenericParameters) - throw new ArgumentException($"Workflow type '{GetDisplayName(workflowType)}' must be a concrete, closed type.", nameof(workflowType)); - } - - private static string GetDisplayName(Type type) => type.FullName ?? type.Name; -} diff --git a/src/modules/Elsa.Workflows.Runtime/Services/TriggerIndexer.cs b/src/modules/Elsa.Workflows.Runtime/Services/TriggerIndexer.cs index c69353ac9..fa8c68c7a 100644 --- a/src/modules/Elsa.Workflows.Runtime/Services/TriggerIndexer.cs +++ b/src/modules/Elsa.Workflows.Runtime/Services/TriggerIndexer.cs @@ -15,6 +15,7 @@ using Medallion.Threading; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Open.Linq.AsyncExtensions; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Runtime; @@ -49,7 +50,7 @@ public class TriggerIndexer : ITriggerIndexer IServiceProvider serviceProvider, IStimulusHasher hasher, IDistributedLockProvider distributedLockProvider, - IWellKnownTypeRegistry wellKnownTypeRegistry, + ISerializationTypeRegistry workflowJsonTypeRegistry, IOptions lockingOptions, ILogger logger) { @@ -62,7 +63,7 @@ public class TriggerIndexer : ITriggerIndexer _serviceProvider = serviceProvider; _hasher = hasher; _distributedLockProvider = distributedLockProvider; - _triggerEqualityComparer = new WorkflowTriggerEqualityComparer(wellKnownTypeRegistry); + _triggerEqualityComparer = new WorkflowTriggerEqualityComparer(workflowJsonTypeRegistry); _lockingOptions = lockingOptions.Value; _logger = logger; _workflowDefinitionService = workflowDefinitionService; diff --git a/src/modules/Elsa.Workflows.Runtime/ShellFeatures/WorkflowRuntimeFeature.cs b/src/modules/Elsa.Workflows.Runtime/ShellFeatures/WorkflowRuntimeFeature.cs index c66a829f5..1ec183a7e 100644 --- a/src/modules/Elsa.Workflows.Runtime/ShellFeatures/WorkflowRuntimeFeature.cs +++ b/src/modules/Elsa.Workflows.Runtime/ShellFeatures/WorkflowRuntimeFeature.cs @@ -3,17 +3,17 @@ using System.Reflection; using CShells.Features; using Elsa.Common; using Elsa.Common.RecurringTasks; -using Elsa.Expressions.Options; using Elsa.Extensions; using Elsa.Mediator.Contracts; using Elsa.Workflows.CommitStates; using Elsa.Workflows.Management; using Elsa.Workflows.Management.Contracts; using Elsa.Workflows.Management.Services; +using Elsa.Workflows.Options; using Elsa.Workflows.Runtime.ActivationValidators; +using Elsa.Workflows.Runtime.Discovery; using Elsa.Workflows.Runtime.Entities; using Elsa.Workflows.Runtime.Handlers; -using Elsa.Workflows.Runtime.Helpers; using Elsa.Workflows.Runtime.Options; using Elsa.Workflows.Runtime.Providers; using Elsa.Workflows.Runtime.Services; @@ -25,6 +25,7 @@ using Medallion.Threading.FileSystem; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Runtime.ShellFeatures; @@ -42,7 +43,7 @@ public class WorkflowRuntimeFeature : IShellFeature /// /// A list of workflow builders configured during application startup. /// - public IDictionary>> Workflows { get; set; } = new WorkflowFactoryDictionary(); + public IDictionary>> Workflows { get; set; } = new Dictionary>>(); private ISet WorkflowTypes { get; } = new HashSet(); /// @@ -164,7 +165,6 @@ public class WorkflowRuntimeFeature : IShellFeature /// public WorkflowRuntimeFeature AddWorkflow(Type workflowType) { - WorkflowTypeValidator.Validate(workflowType); Workflows.Add(workflowType); WorkflowTypes.Add(workflowType); return this; @@ -176,11 +176,7 @@ public class WorkflowRuntimeFeature : IShellFeature [RequiresUnreferencedCode("The assembly is required to be referenced.")] public WorkflowRuntimeFeature AddWorkflowsFrom(Assembly assembly) { - var workflowTypes = assembly.GetExportedTypes() - .Where(x => typeof(IWorkflow).IsAssignableFrom(x) && x is { IsAbstract: false, IsInterface: false, ContainsGenericParameters: false }) - .ToList(); - - foreach (var workflowType in workflowTypes) + foreach (var workflowType in WorkflowTypeScanner.GetWorkflowTypes(assembly)) AddWorkflow(workflowType); return this; @@ -189,7 +185,7 @@ public class WorkflowRuntimeFeature : IShellFeature public void ConfigureServices(IServiceCollection services) { // Options. - services.Configure(RegisterWorkflowTypeAliases); + services.Configure(RegisterWorkflowTypeAliases); services.Configure(options => { options.Workflows = Workflows; }); services.Configure(options => { @@ -366,12 +362,33 @@ public class WorkflowRuntimeFeature : IShellFeature services.TryAddScoped(); } - private void RegisterWorkflowTypeAliases(ExpressionOptions options) + private void RegisterWorkflowTypeAliases(SerializationTypeOptions options) { - var workflowTypes = Workflows is IWorkflowTypeRegistry workflowTypeRegistry - ? WorkflowTypes.Concat(workflowTypeRegistry.WorkflowTypes) - : WorkflowTypes; + WorkflowRuntimeTypeAliasRegistrar.Register(options, GetRegisteredWorkflowTypes()); + } - WorkflowRuntimeTypeAliasRegistrar.Register(options, workflowTypes); + private IEnumerable GetRegisteredWorkflowTypes() + { + return WorkflowTypes + .Concat(Workflows.Keys.Select(TryResolveWorkflowType).Where(type => type != null).Select(type => type!)) + .Distinct(); + } + + private static Type? TryResolveWorkflowType(string typeName) + { + Type? type; + + try + { + type = Type.GetType(typeName, false); + } + catch (Exception e) when (e is ArgumentException or FileLoadException or FileNotFoundException or TypeLoadException or BadImageFormatException) + { + return null; + } + + return type != null && typeof(IWorkflow).IsAssignableFrom(type) && type is { IsAbstract: false, IsInterface: false, ContainsGenericParameters: false } + ? type + : null; } } diff --git a/src/modules/Elsa.Workflows.Runtime/WorkflowRuntimeTypeAliasRegistrar.cs b/src/modules/Elsa.Workflows.Runtime/WorkflowRuntimeTypeAliasRegistrar.cs index b3811a01e..31a52542d 100644 --- a/src/modules/Elsa.Workflows.Runtime/WorkflowRuntimeTypeAliasRegistrar.cs +++ b/src/modules/Elsa.Workflows.Runtime/WorkflowRuntimeTypeAliasRegistrar.cs @@ -1,28 +1,29 @@ -using Elsa.Expressions.Options; using Elsa.Extensions; using Elsa.Workflows; +using Elsa.Workflows.Options; using Elsa.Workflows.Runtime.Bookmarks; using Elsa.Workflows.Runtime.Stimuli; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Runtime; internal static class WorkflowRuntimeTypeAliasRegistrar { - public static void Register(ExpressionOptions options, IEnumerable workflowTypes) + public static void Register(SerializationTypeOptions options, IEnumerable workflowTypes) { - options.RegisterTypeAlias(typeof(EventBookmarkPayload), nameof(EventBookmarkPayload)); - options.RegisterTypeAlias(typeof(ExecuteWorkflowPayload), nameof(ExecuteWorkflowPayload)); - options.RegisterTypeAlias(typeof(RunTaskBookmarkPayload), nameof(RunTaskBookmarkPayload)); - options.RegisterTypeAlias(typeof(BookmarkTokenPayload), nameof(BookmarkTokenPayload)); - options.RegisterTypeAlias(typeof(EventTokenPayload), nameof(EventTokenPayload)); - options.RegisterTypeAlias(typeof(ExecuteWorkflowResult), nameof(ExecuteWorkflowResult)); - options.RegisterTypeAlias(typeof(WorkflowInterruptedPayload), nameof(WorkflowInterruptedPayload)); - options.RegisterTypeAlias(typeof(BackgroundActivityStimulus), nameof(BackgroundActivityStimulus)); - options.RegisterTypeAlias(typeof(BulkDispatchWorkflowsStimulus), nameof(BulkDispatchWorkflowsStimulus)); - options.RegisterTypeAlias(typeof(DispatchWorkflowStimulus), nameof(DispatchWorkflowStimulus)); - options.RegisterTypeAlias(typeof(EventStimulus), nameof(EventStimulus)); - options.RegisterTypeAlias(typeof(ExecuteWorkflowStimulus), nameof(ExecuteWorkflowStimulus)); - options.RegisterTypeAlias(typeof(RunTaskStimulus), nameof(RunTaskStimulus)); + options.AddTypeAlias(); + options.AddTypeAlias(); + options.AddTypeAlias(); + options.AddTypeAlias(); + options.AddTypeAlias(); + options.AddTypeAlias(); + options.AddTypeAlias(); + options.AddTypeAlias(); + options.AddTypeAlias(); + options.AddTypeAlias(); + options.AddTypeAlias(); + options.AddTypeAlias(); + options.AddTypeAlias(); foreach (var workflowType in workflowTypes.Where(IsConcreteWorkflowType).Distinct()) options.RegisterTypeAlias(workflowType, workflowType.GetSimpleAssemblyQualifiedName()); diff --git a/test/TlsSmoke/Directory.Build.props b/test/TlsSmoke/Directory.Build.props new file mode 100644 index 000000000..aa6d9a312 --- /dev/null +++ b/test/TlsSmoke/Directory.Build.props @@ -0,0 +1,5 @@ + + + + + diff --git a/test/TlsSmoke/Program.cs b/test/TlsSmoke/Program.cs new file mode 100644 index 000000000..e2b8d9a3b --- /dev/null +++ b/test/TlsSmoke/Program.cs @@ -0,0 +1,16 @@ +if (args.Length != 1 || !Uri.TryCreate(args[0], UriKind.Absolute, out var uri)) +{ + Console.Error.WriteLine("Usage: TlsSmoke "); + return 2; +} + +using var httpClient = new HttpClient +{ + Timeout = TimeSpan.FromSeconds(30) +}; + +using var response = await httpClient.GetAsync(uri); +response.EnsureSuccessStatusCode(); + +Console.WriteLine($"TLS request to {uri} returned {(int)response.StatusCode}."); +return 0; diff --git a/test/TlsSmoke/TlsSmoke.csproj b/test/TlsSmoke/TlsSmoke.csproj new file mode 100644 index 000000000..cd19a3563 --- /dev/null +++ b/test/TlsSmoke/TlsSmoke.csproj @@ -0,0 +1,10 @@ + + + + Exe + net10.0 + enable + enable + + + diff --git a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Composition/BulkDispatchWorkflows/BulkDispatchWorkflowsTests.cs b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Composition/BulkDispatchWorkflows/BulkDispatchWorkflowsTests.cs index 4ad856b7e..847bdebee 100644 --- a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Composition/BulkDispatchWorkflows/BulkDispatchWorkflowsTests.cs +++ b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Composition/BulkDispatchWorkflows/BulkDispatchWorkflowsTests.cs @@ -142,24 +142,25 @@ public class BulkDispatchWorkflowsTests : AppComponentTest return (T?)variables.FirstOrDefault(v => v.Variable.Name == variableName)?.Value; } - private async Task<(TestWorkflowExecutionResult Result, List CompletedChildWorkflows)> RunWorkflowAndWaitForChildWorkflowsAsync( + private async Task<(TestWorkflowExecutionResult Result, List CompletedChildWorkflows)> RunWorkflowAndWaitForChildWorkflowsAsync( string parentWorkflowDefinitionId, string childWorkflowDefinitionId, int expectedChildCount) { var result = await RunWorkflowAsync(parentWorkflowDefinitionId); - var completedChildWorkflows = await WaitForCompletedChildWorkflowInstancesAsync(result.WorkflowExecutionContext.Id, childWorkflowDefinitionId, expectedChildCount); + var completedChildWorkflows = await WaitForCompletedChildWorkflowsAsync(result.WorkflowExecutionContext.Id, childWorkflowDefinitionId, expectedChildCount); return (result, completedChildWorkflows); } - private async Task> WaitForCompletedChildWorkflowInstancesAsync(string parentWorkflowInstanceId, string childWorkflowDefinitionId, int expectedChildCount) + private async Task> WaitForCompletedChildWorkflowsAsync(string parentWorkflowInstanceId, string childWorkflowDefinitionId, int expectedChildCount) { + var workflowInstanceStore = Scope.ServiceProvider.GetRequiredService(); var timeoutAt = DateTimeOffset.UtcNow.AddSeconds(ChildWorkflowTimeoutSeconds); while (DateTimeOffset.UtcNow < timeoutAt) { - var completedChildWorkflows = await FindChildWorkflowInstancesAsync(parentWorkflowInstanceId, childWorkflowDefinitionId, WorkflowStatus.Finished); + var completedChildWorkflows = await FindChildWorkflowStatesAsync(workflowInstanceStore, parentWorkflowInstanceId, childWorkflowDefinitionId, WorkflowStatus.Finished); if (completedChildWorkflows.Count >= expectedChildCount) return completedChildWorkflows; @@ -167,12 +168,13 @@ public class BulkDispatchWorkflowsTests : AppComponentTest await Task.Delay(TimeSpan.FromMilliseconds(100)); } - var childWorkflows = await FindChildWorkflowInstancesAsync(parentWorkflowInstanceId, childWorkflowDefinitionId); + var childWorkflows = await FindChildWorkflowStatesAsync(workflowInstanceStore, parentWorkflowInstanceId, childWorkflowDefinitionId); var observedStates = string.Join(", ", childWorkflows.Select(x => $"{x.Id}:{x.Status}:{x.SubStatus}")); throw new TimeoutException($"Expected {expectedChildCount} completed child workflows with definition ID {childWorkflowDefinitionId}, but observed {childWorkflows.Count(x => x.Status == WorkflowStatus.Finished)}. Observed child workflow states: {observedStates}"); } - private async Task> FindChildWorkflowInstancesAsync( + private static async Task> FindChildWorkflowStatesAsync( + IWorkflowInstanceStore workflowInstanceStore, string parentWorkflowInstanceId, string childWorkflowDefinitionId, WorkflowStatus? workflowStatus = null) @@ -183,8 +185,8 @@ public class BulkDispatchWorkflowsTests : AppComponentTest ParentWorkflowInstanceIds = new[] { parentWorkflowInstanceId }, WorkflowStatus = workflowStatus }; - var instances = await _workflowInstanceStore.FindManyAsync(filter); - return instances.OrderBy(x => x.CreatedAt).ToList(); + var instances = await workflowInstanceStore.FindManyAsync(filter); + return instances.Select(x => x.WorkflowState).ToList(); } private async Task> WaitForChildWorkflowInstancesAsync( diff --git a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Primitives/Event/PublishEventTests.cs b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Primitives/Event/PublishEventTests.cs index 8b6b696c5..b1390b510 100644 --- a/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Primitives/Event/PublishEventTests.cs +++ b/test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/Primitives/Event/PublishEventTests.cs @@ -73,10 +73,9 @@ public class PublishEventTests : AppComponentTest Assert.NotNull(receivedPayload); // Verify the payload structure and content - var payloadJson = JsonSerializer.Serialize(receivedPayload); - using var payloadDocument = JsonDocument.Parse(payloadJson); - var statusProperty = Assert.Single(payloadDocument.RootElement.EnumerateObject(), x => string.Equals(x.Name, "Status", StringComparison.OrdinalIgnoreCase)); - Assert.Equal("Shipped", statusProperty.Value.GetString()); + using var payloadDocument = JsonDocument.Parse(JsonSerializer.Serialize(receivedPayload)); + Assert.True(payloadDocument.RootElement.TryGetProperty("Status", out var status), "Received payload should contain a Status property"); + Assert.Equal("Shipped", status.GetString()); } private async Task GetSingleWorkflowInstanceAsync(string definitionId, string correlationId, int timeoutMs = 5000) diff --git a/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsAuthorizationTests.cs b/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsAuthorizationTests.cs index 74969a8fd..d6bf4c1a4 100644 --- a/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsAuthorizationTests.cs +++ b/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsAuthorizationTests.cs @@ -1,15 +1,15 @@ using System.Reflection; using System.Security.Claims; -using System.Text.Json; -using ConsoleLogStreaming.Contracts; +using System.Text; +using ConsoleLogStreaming.Core.Models; using ConsoleLogStreaming.Core; -using ConsoleLogStreaming.SignalR; using Elsa.Diagnostics.ConsoleLogs.Contracts; using Elsa.Diagnostics.ConsoleLogs.Features; using Elsa.Diagnostics.ConsoleLogs.Permissions; using Elsa.Diagnostics.ConsoleLogs.RealTime; using Elsa.Diagnostics.ConsoleLogs.Services; using FastEndpoints; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging.Abstractions; @@ -60,18 +60,15 @@ public class ConsoleLogsAuthorizationTests { var endpointType = typeof(ConsoleLogsFeature).Assembly.GetType("Elsa.Diagnostics.ConsoleLogs.Endpoints.ConsoleLogs.Recent.Endpoint", throwOnError: true)!; var provider = new TestConsoleLogProvider(); - var endpoint = Activator.CreateInstance(endpointType, provider, new ConsoleLogStreamingApiMapper())!; - var (requestDtoType, _) = GetEndpointDtoTypes(endpointType); - var request = JsonSerializer.Deserialize( + var endpoint = Activator.CreateInstance(endpointType, provider)!; + SetJsonRequest(endpointType, endpoint, """ { "workflowInstanceId": "workflow-instance-a" } - """, - requestDtoType, - new JsonSerializerOptions { PropertyNameCaseInsensitive = true })!; + """); - var result = endpointType.GetMethod("ExecuteAsync")!.Invoke(endpoint, [request, CancellationToken.None]); + var result = endpointType.GetMethod("ExecuteAsync", [typeof(CancellationToken)])!.Invoke(endpoint, [CancellationToken.None]); await Assert.IsAssignableFrom(result); Assert.NotNull(provider.LastFilter); @@ -80,14 +77,59 @@ public class ConsoleLogsAuthorizationTests Assert.Equal("workflow-instance-a", workflowInstanceId); } + [Theory] + [InlineData("stdout", ConsoleStream.Stdout)] + [InlineData("stderr", ConsoleStream.Stderr)] + public async Task RecentEndpoint_MapsLowercaseStreamFilter(string stream, ConsoleStream expected) + { + var endpointType = typeof(ConsoleLogsFeature).Assembly.GetType("Elsa.Diagnostics.ConsoleLogs.Endpoints.ConsoleLogs.Recent.Endpoint", throwOnError: true)!; + var provider = new TestConsoleLogProvider(); + var endpoint = Activator.CreateInstance(endpointType, provider)!; + SetJsonRequest(endpointType, endpoint, + $$""" + { + "stream": "{{stream}}" + } + """); + + var result = endpointType.GetMethod("ExecuteAsync", [typeof(CancellationToken)])!.Invoke(endpoint, [CancellationToken.None]); + await Assert.IsAssignableFrom(result); + + Assert.NotNull(provider.LastFilter); + Assert.Equal(expected, provider.LastFilter.Stream); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData("all")] + public async Task RecentEndpoint_MapsAllStreamFilterToNull(string? stream) + { + var endpointType = typeof(ConsoleLogsFeature).Assembly.GetType("Elsa.Diagnostics.ConsoleLogs.Endpoints.ConsoleLogs.Recent.Endpoint", throwOnError: true)!; + var provider = new TestConsoleLogProvider(); + var endpoint = Activator.CreateInstance(endpointType, provider)!; + var streamJson = stream == null ? "null" : $"\"{stream}\""; + SetJsonRequest(endpointType, endpoint, + $$""" + { + "stream": {{streamJson}} + } + """); + + var result = endpointType.GetMethod("ExecuteAsync", [typeof(CancellationToken)])!.Invoke(endpoint, [CancellationToken.None]); + await Assert.IsAssignableFrom(result); + + Assert.NotNull(provider.LastFilter); + Assert.Null(provider.LastFilter.Stream); + } + [Fact] public async Task RecentEndpoint_MapsActivityFiltersToMetadataFilter() { var endpointType = typeof(ConsoleLogsFeature).Assembly.GetType("Elsa.Diagnostics.ConsoleLogs.Endpoints.ConsoleLogs.Recent.Endpoint", throwOnError: true)!; var provider = new TestConsoleLogProvider(); - var endpoint = Activator.CreateInstance(endpointType, provider, new ConsoleLogStreamingApiMapper())!; - var (requestDtoType, _) = GetEndpointDtoTypes(endpointType); - var request = JsonSerializer.Deserialize( + var endpoint = Activator.CreateInstance(endpointType, provider)!; + SetJsonRequest(endpointType, endpoint, """ { "workflowInstanceId": "workflow-instance-a", @@ -95,17 +137,30 @@ public class ConsoleLogsAuthorizationTests "activityId": "activity-a", "activityNodeId": "node-a" } - """, - requestDtoType, - new JsonSerializerOptions { PropertyNameCaseInsensitive = true })!; + """); - var result = endpointType.GetMethod("ExecuteAsync")!.Invoke(endpoint, [request, CancellationToken.None]); + var result = endpointType.GetMethod("ExecuteAsync", [typeof(CancellationToken)])!.Invoke(endpoint, [CancellationToken.None]); await Assert.IsAssignableFrom(result); Assert.NotNull(provider.LastFilter); AssertActivityMetadata(provider.LastFilter.Metadata); } + [Fact] + public async Task RecentEndpoint_WhenJsonRequestHasUnknownEmptyBody_UsesEmptyFilter() + { + var endpointType = typeof(ConsoleLogsFeature).Assembly.GetType("Elsa.Diagnostics.ConsoleLogs.Endpoints.ConsoleLogs.Recent.Endpoint", throwOnError: true)!; + var provider = new TestConsoleLogProvider(); + var endpoint = Activator.CreateInstance(endpointType, provider)!; + SetJsonRequest(endpointType, endpoint, "", includeContentLength: false); + + var result = endpointType.GetMethod("ExecuteAsync", [typeof(CancellationToken)])!.Invoke(endpoint, [CancellationToken.None]); + await Assert.IsAssignableFrom(result); + + Assert.NotNull(provider.LastFilter); + Assert.Empty(provider.LastFilter.Metadata); + } + [Fact] public async Task HubStream_MapsWorkflowInstanceIdToMetadataFilter() { @@ -167,13 +222,24 @@ public class ConsoleLogsAuthorizationTests Assert.Equal("node-a", metadata[ConsoleLogMetadataKeys.ActivityNodeId]); } + private static void SetJsonRequest(Type endpointType, object endpoint, string json, bool includeContentLength = true) + { + var bytes = Encoding.UTF8.GetBytes(json); + var context = new DefaultHttpContext(); + context.Request.Body = new MemoryStream(bytes); + if (includeContentLength) + context.Request.ContentLength = bytes.Length; + context.Request.ContentType = "application/json"; + + endpointType + .GetProperty("HttpContext", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)! + .SetValue(endpoint, context); + } + private static IReadOnlyCollection GetConfiguredPermissions(string endpointTypeName) { var endpointType = typeof(ConsoleLogsFeature).Assembly.GetType(endpointTypeName, throwOnError: true)!; - var mapper = new ConsoleLogStreamingApiMapper(); - var endpoint = endpointTypeName.EndsWith(".Recent.Endpoint", StringComparison.Ordinal) - ? Activator.CreateInstance(endpointType, new TestConsoleLogProvider(), mapper)! - : Activator.CreateInstance(endpointType, new TestConsoleLogProvider(), mapper)!; + var endpoint = Activator.CreateInstance(endpointType, new TestConsoleLogProvider())!; var (requestDtoType, responseDtoType) = GetEndpointDtoTypes(endpointType); var definition = new EndpointDefinition(endpointType, requestDtoType, responseDtoType); @@ -205,13 +271,13 @@ public class ConsoleLogsAuthorizationTests var genericTypeDefinition = type.GetGenericTypeDefinition(); var genericArguments = type.GetGenericArguments(); - if (genericTypeDefinition == typeof(Elsa.Abstractions.ElsaEndpoint<,>)) + if (genericTypeDefinition == typeof(Abstractions.ElsaEndpoint<,>)) return (genericArguments[0], genericArguments[1]); - if (genericTypeDefinition == typeof(Elsa.Abstractions.ElsaEndpoint<,,>)) + if (genericTypeDefinition == typeof(Abstractions.ElsaEndpoint<,,>)) return (genericArguments[0], genericArguments[1]); - if (genericTypeDefinition == typeof(Elsa.Abstractions.ElsaEndpointWithoutRequest<>)) + if (genericTypeDefinition == typeof(Abstractions.ElsaEndpointWithoutRequest<>)) return (typeof(EmptyRequest), genericArguments[0]); } @@ -225,13 +291,11 @@ public class ConsoleLogsAuthorizationTests private static ElsaConsoleLogsHub CreateHub(TestConsoleLogProvider provider, params string[] permissions) { - var sourceRegistry = new TestConsoleLogSourceRegistry(); - var mapper = new ConsoleLogStreamingApiMapper(); var hubContext = new TestHubContext(); - var subscriptionManager = new ElsaConsoleLogSubscriptionManager(provider, sourceRegistry, mapper, hubContext, NullLogger.Instance); - var authorizer = new ElsaConsoleLogStreamingHubAuthorizer(); + var subscriptionManager = new ElsaConsoleLogSubscriptionManager(provider, new TestConsoleLogSourceRegistry(), hubContext, NullLogger.Instance); + var authorizer = new ElsaConsoleLogStreamHubAuthorizer(); - return new ElsaConsoleLogsHub(provider, mapper, authorizer, subscriptionManager) + return new ElsaConsoleLogsHub(provider, authorizer, subscriptionManager) { Context = new TestHubCallerContext(CreateUser(permissions)) }; @@ -250,83 +314,58 @@ public class ConsoleLogsAuthorizationTests private class TestConsoleLogProvider : IConsoleLogProvider { - private readonly TaskCompletionSource _subscriptionFilterSet = new(TaskCreationOptions.RunContinuationsAsynchronously); + private readonly TaskCompletionSource _subscriptionFilterSet = new(TaskCreationOptions.RunContinuationsAsynchronously); - public ConsoleLogStreaming.Core.Models.ConsoleLogFilter? LastFilter { get; private set; } - public ConsoleLogStreaming.Core.Models.ConsoleLogFilter? LastSubscriptionFilter { get; private set; } + public ConsoleLogFilter? LastFilter { get; private set; } + public ConsoleLogFilter? LastSubscriptionFilter { get; private set; } - public Task WaitForSubscriptionFilterAsync() => + public Task WaitForSubscriptionFilterAsync() => _subscriptionFilterSet.Task.WaitAsync(TimeSpan.FromSeconds(5)); - public ValueTask PublishAsync(ConsoleLogStreaming.Core.Models.ConsoleLogLine line, CancellationToken cancellationToken = default) + public ValueTask PublishAsync(ConsoleLogLine line, CancellationToken cancellationToken = default) { return ValueTask.CompletedTask; } - public ValueTask GetRecentAsync(ConsoleLogStreaming.Core.Models.ConsoleLogFilter filter, CancellationToken cancellationToken = default) + public ValueTask GetRecentAsync(ConsoleLogFilter filter, CancellationToken cancellationToken = default) { LastFilter = filter; - return ValueTask.FromResult(new ConsoleLogStreaming.Core.Models.RecentConsoleLogsResult()); + return ValueTask.FromResult(new RecentConsoleLogsResult()); } - public IAsyncEnumerable SubscribeAsync( - ConsoleLogStreaming.Core.Models.ConsoleLogFilter filter, + public IAsyncEnumerable SubscribeAsync( + ConsoleLogFilter filter, CancellationToken cancellationToken = default) { LastSubscriptionFilter = filter; _subscriptionFilterSet.TrySetResult(filter); - return AsyncEnumerable.Empty(); + return AsyncEnumerable.Empty(); } - public ValueTask> ListSourcesAsync(CancellationToken cancellationToken = default) + public ValueTask> ListSourcesAsync(CancellationToken cancellationToken = default) { - return ValueTask.FromResult>([]); + return ValueTask.FromResult>([]); } } - private class TestConsoleLogSourceRegistry : IConsoleLogSourceRegistry + private class TestHubContext : IHubContext { - public event Action? SourceChanged - { - add { } - remove { } - } - - public ConsoleLogStreaming.Core.Models.ConsoleLogSource Current { get; } = new() - { - Id = "test", - DisplayName = "Test" - }; - - public ConsoleLogStreaming.Core.Models.ConsoleLogSource MarkSeen(ConsoleLogStreaming.Core.Models.ConsoleLogSource source, DateTimeOffset timestamp) - { - return source with { LastSeen = timestamp }; - } - - public IReadOnlyCollection List() - { - return [Current]; - } - } - - private class TestHubContext : IHubContext - { - public IHubClients Clients { get; } = new TestHubClients(); + public IHubClients Clients { get; } = new TestHubClients(); public IGroupManager Groups { get; } = new TestGroupManager(); } - private class TestHubClients : IHubClients + private class TestHubClients : IHubClients { - public IConsoleLogsClient All => throw new NotSupportedException(); - public IConsoleLogsClient AllExcept(IReadOnlyList excludedConnectionIds) => throw new NotSupportedException(); - public IConsoleLogsClient Client(string connectionId) => throw new NotSupportedException(); - public IConsoleLogsClient Clients(IReadOnlyList connectionIds) => throw new NotSupportedException(); - public IConsoleLogsClient Group(string groupName) => throw new NotSupportedException(); - public IConsoleLogsClient GroupExcept(string groupName, IReadOnlyList excludedConnectionIds) => throw new NotSupportedException(); - public IConsoleLogsClient Groups(IReadOnlyList groupNames) => throw new NotSupportedException(); - public IConsoleLogsClient User(string userId) => throw new NotSupportedException(); - public IConsoleLogsClient Users(IReadOnlyList userIds) => throw new NotSupportedException(); + public IElsaConsoleLogsClient All => throw new NotSupportedException(); + public IElsaConsoleLogsClient AllExcept(IReadOnlyList excludedConnectionIds) => throw new NotSupportedException(); + public IElsaConsoleLogsClient Client(string connectionId) => throw new NotSupportedException(); + public IElsaConsoleLogsClient Clients(IReadOnlyList connectionIds) => throw new NotSupportedException(); + public IElsaConsoleLogsClient Group(string groupName) => throw new NotSupportedException(); + public IElsaConsoleLogsClient GroupExcept(string groupName, IReadOnlyList excludedConnectionIds) => throw new NotSupportedException(); + public IElsaConsoleLogsClient Groups(IReadOnlyList groupNames) => throw new NotSupportedException(); + public IElsaConsoleLogsClient User(string userId) => throw new NotSupportedException(); + public IElsaConsoleLogsClient Users(IReadOnlyList userIds) => throw new NotSupportedException(); } private class TestGroupManager : IGroupManager diff --git a/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsHubSourceStatusTests.cs b/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsHubSourceStatusTests.cs index ca31b3050..7c09d8a9f 100644 --- a/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsHubSourceStatusTests.cs +++ b/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsHubSourceStatusTests.cs @@ -1,4 +1,9 @@ -using ConsoleLogStreaming.SignalR; +using ConsoleLogStreaming.Core; +using ConsoleLogStreaming.Core.Models; +using Elsa.Diagnostics.ConsoleLogs.Contracts; +using Elsa.Diagnostics.ConsoleLogs.RealTime; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging.Abstractions; namespace Elsa.Diagnostics.ConsoleLogs.IntegrationTests; @@ -7,6 +12,139 @@ public class ConsoleLogsHubSourceStatusTests [Fact] public void ClientContract_ExposesSourceChangeMethod() { - Assert.NotNull(typeof(IConsoleLogsClient).GetMethod(nameof(IConsoleLogsClient.ReceiveSourceChangedAsync))); + Assert.NotNull(typeof(IElsaConsoleLogsClient).GetMethod(nameof(IElsaConsoleLogsClient.ReceiveSourceChangedAsync))); + } + + [Fact] + public async Task PushedSubscription_ForwardsSourceChangeFromConsoleLines() + { + var source = new ConsoleLogSource { Id = "source-1", DisplayName = "Source 1" }; + var provider = new SingleLineProvider(new ConsoleLogLine { Text = "message", Source = source }); + var sourceRegistry = new TestConsoleLogSourceRegistry(); + var client = new TestConsoleLogsClient(); + var hubContext = new TestHubContext(client); + using var manager = new ElsaConsoleLogSubscriptionManager(provider, sourceRegistry, hubContext, NullLogger.Instance); + + await manager.SubscribeAsync("connection-1", new ElsaConsoleLogFilter(), CancellationToken.None); + + Assert.Same(source, await client.SourceChanged.Task.WaitAsync(TimeSpan.FromSeconds(5))); + } + + [Fact] + public async Task PushedSubscription_ForwardsSourceChangeFromRegistry() + { + var source = new ConsoleLogSource { Id = "source-1", DisplayName = "Source 1" }; + var provider = new IdleProvider(); + var sourceRegistry = new TestConsoleLogSourceRegistry(); + var client = new TestConsoleLogsClient(); + var hubContext = new TestHubContext(client); + using var manager = new ElsaConsoleLogSubscriptionManager(provider, sourceRegistry, hubContext, NullLogger.Instance); + + await manager.SubscribeAsync("connection-1", new ElsaConsoleLogFilter { SourceId = source.Id }, CancellationToken.None); + sourceRegistry.Raise(source); + + Assert.Same(source, await client.SourceChanged.Task.WaitAsync(TimeSpan.FromSeconds(5))); + } + + private sealed class SingleLineProvider(ConsoleLogLine line) : IConsoleLogProvider + { + public ValueTask PublishAsync(ConsoleLogLine line, CancellationToken cancellationToken = default) + { + return ValueTask.CompletedTask; + } + + public ValueTask GetRecentAsync(ConsoleLogFilter filter, CancellationToken cancellationToken = default) + { + return ValueTask.FromResult(new RecentConsoleLogsResult()); + } + + public async IAsyncEnumerable SubscribeAsync(ConsoleLogFilter filter, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default) + { + yield return ConsoleLogStreamingItem.FromLine(line); + await Task.Yield(); + } + + public ValueTask> ListSourcesAsync(CancellationToken cancellationToken = default) + { + return ValueTask.FromResult>([line.Source]); + } + } + + private sealed class IdleProvider : IConsoleLogProvider + { + public ValueTask PublishAsync(ConsoleLogLine line, CancellationToken cancellationToken = default) + { + return ValueTask.CompletedTask; + } + + public ValueTask GetRecentAsync(ConsoleLogFilter filter, CancellationToken cancellationToken = default) + { + return ValueTask.FromResult(new RecentConsoleLogsResult()); + } + + public async IAsyncEnumerable SubscribeAsync(ConsoleLogFilter filter, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default) + { + await Task.Delay(Timeout.InfiniteTimeSpan, cancellationToken); + yield break; + } + + public ValueTask> ListSourcesAsync(CancellationToken cancellationToken = default) + { + return ValueTask.FromResult>([]); + } + } + + private sealed class TestConsoleLogsClient : IElsaConsoleLogsClient + { + public TaskCompletionSource SourceChanged { get; } = new(TaskCreationOptions.RunContinuationsAsynchronously); + + public Task ReceiveConsoleLogLineAsync(ConsoleLogLine line, CancellationToken cancellationToken = default) + { + return Task.CompletedTask; + } + + public Task ReceiveDroppedLinesAsync(ConsoleLogDroppedSummary summary, CancellationToken cancellationToken = default) + { + return Task.CompletedTask; + } + + public Task ReceiveSourceChangedAsync(ConsoleLogSource source, CancellationToken cancellationToken = default) + { + SourceChanged.TrySetResult(source); + return Task.CompletedTask; + } + } + + private sealed class TestHubContext(IElsaConsoleLogsClient client) : IHubContext + { + public IHubClients Clients { get; } = new TestHubClients(client); + + public IGroupManager Groups { get; } = new TestGroupManager(); + } + + private sealed class TestHubClients(IElsaConsoleLogsClient client) : IHubClients + { + public IElsaConsoleLogsClient All => client; + public IElsaConsoleLogsClient AllExcept(IReadOnlyList excludedConnectionIds) => client; + public IElsaConsoleLogsClient Client(string connectionId) => client; + public IElsaConsoleLogsClient Clients(IReadOnlyList connectionIds) => client; + public IElsaConsoleLogsClient Group(string groupName) => client; + public IElsaConsoleLogsClient GroupExcept(string groupName, IReadOnlyList excludedConnectionIds) => client; + public IElsaConsoleLogsClient Groups(IReadOnlyList groupNames) => client; + public IElsaConsoleLogsClient User(string userId) => client; + public IElsaConsoleLogsClient Users(IReadOnlyList userIds) => client; + } + + private sealed class TestGroupManager : IGroupManager + { + public Task AddToGroupAsync(string connectionId, string groupName, CancellationToken cancellationToken = default) + { + return Task.CompletedTask; + } + + public Task RemoveFromGroupAsync(string connectionId, string groupName, CancellationToken cancellationToken = default) + { + return Task.CompletedTask; + } } } diff --git a/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsModuleTests.cs b/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsModuleTests.cs index 0dd1fc06f..40d05a073 100644 --- a/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsModuleTests.cs +++ b/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsModuleTests.cs @@ -25,5 +25,6 @@ public class ConsoleLogsModuleTests Assert.DoesNotContain("Elsa.Diagnostics.StructuredLogs", references); Assert.DoesNotContain("Elsa.Diagnostics.StructuredLogs.Persistence.Sqlite", references); + Assert.DoesNotContain("ConsoleLogStreaming.Persistence.Sqlite", references); } } diff --git a/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsRecentEndpointTests.cs b/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsRecentEndpointTests.cs index ac94f5456..7b226a5df 100644 --- a/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsRecentEndpointTests.cs +++ b/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsRecentEndpointTests.cs @@ -5,7 +5,7 @@ public class ConsoleLogsRecentEndpointTests [Fact] public void RecentEndpoint_ExistsInConsoleLogsAssembly() { - var endpointType = typeof(Elsa.Diagnostics.ConsoleLogs.Features.ConsoleLogsFeature) + var endpointType = typeof(Features.ConsoleLogsFeature) .Assembly .GetType("Elsa.Diagnostics.ConsoleLogs.Endpoints.ConsoleLogs.Recent.Endpoint"); diff --git a/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsSourcesEndpointTests.cs b/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsSourcesEndpointTests.cs index 715d31b59..8fd387e33 100644 --- a/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsSourcesEndpointTests.cs +++ b/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/ConsoleLogsSourcesEndpointTests.cs @@ -5,7 +5,7 @@ public class ConsoleLogsSourcesEndpointTests [Fact] public void SourcesEndpoint_ExistsInConsoleLogsAssembly() { - var endpointType = typeof(Elsa.Diagnostics.ConsoleLogs.Features.ConsoleLogsFeature) + var endpointType = typeof(Features.ConsoleLogsFeature) .Assembly .GetType("Elsa.Diagnostics.ConsoleLogs.Endpoints.ConsoleLogs.Sources.Endpoint"); diff --git a/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/Elsa.Diagnostics.ConsoleLogs.IntegrationTests.csproj b/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/Elsa.Diagnostics.ConsoleLogs.IntegrationTests.csproj index 67ef05beb..ac46ee106 100644 --- a/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/Elsa.Diagnostics.ConsoleLogs.IntegrationTests.csproj +++ b/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/Elsa.Diagnostics.ConsoleLogs.IntegrationTests.csproj @@ -7,6 +7,7 @@ + diff --git a/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/TestConsoleLogSourceRegistry.cs b/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/TestConsoleLogSourceRegistry.cs new file mode 100644 index 000000000..120a176f6 --- /dev/null +++ b/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/TestConsoleLogSourceRegistry.cs @@ -0,0 +1,28 @@ +using ConsoleLogStreaming.Core; +using ConsoleLogStreaming.Core.Models; + +namespace Elsa.Diagnostics.ConsoleLogs.IntegrationTests; + +internal sealed class TestConsoleLogSourceRegistry : IConsoleLogSourceRegistry +{ + public event Action? SourceChanged; + + public ConsoleLogSource Current { get; private set; } = new() { Id = "test-source" }; + + public ConsoleLogSource MarkSeen(ConsoleLogSource source, DateTimeOffset timestamp) + { + Current = source; + SourceChanged?.Invoke(source); + return source; + } + + public IReadOnlyCollection List() + { + return [Current]; + } + + public void Raise(ConsoleLogSource source) + { + SourceChanged?.Invoke(source); + } +} diff --git a/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/Elsa.Diagnostics.OpenTelemetry.IntegrationTests.csproj b/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/Elsa.Diagnostics.OpenTelemetry.IntegrationTests.csproj new file mode 100644 index 000000000..ce0f941e2 --- /dev/null +++ b/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/Elsa.Diagnostics.OpenTelemetry.IntegrationTests.csproj @@ -0,0 +1,14 @@ + + + + [Elsa.Diagnostics.OpenTelemetry]* + 0 + true + + + + + + + + diff --git a/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/OpenTelemetryAuthorizationTests.cs b/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/OpenTelemetryAuthorizationTests.cs new file mode 100644 index 000000000..b5c8d37a3 --- /dev/null +++ b/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/OpenTelemetryAuthorizationTests.cs @@ -0,0 +1,102 @@ +using System.Reflection; +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Features; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Permissions; +using FastEndpoints; + +namespace Elsa.Diagnostics.OpenTelemetry.IntegrationTests; + +public class OpenTelemetryAuthorizationTests +{ + [Theory] + [InlineData("Elsa.Diagnostics.OpenTelemetry.Endpoints.OpenTelemetry.Resources.Endpoint")] + [InlineData("Elsa.Diagnostics.OpenTelemetry.Endpoints.OpenTelemetry.Traces.Endpoint")] + [InlineData("Elsa.Diagnostics.OpenTelemetry.Endpoints.OpenTelemetry.Trace.Endpoint")] + [InlineData("Elsa.Diagnostics.OpenTelemetry.Endpoints.OpenTelemetry.Metrics.Endpoint")] + [InlineData("Elsa.Diagnostics.OpenTelemetry.Endpoints.OpenTelemetry.Logs.Endpoint")] + [InlineData("Elsa.Diagnostics.OpenTelemetry.Endpoints.OpenTelemetry.Storage.Endpoint")] + [InlineData("Elsa.Diagnostics.OpenTelemetry.Endpoints.OpenTelemetry.CollectorConfiguration.Endpoint")] + public void RestEndpoints_RequireOpenTelemetryReadPermission(string endpointTypeName) + { + var permissions = GetConfiguredPermissions(endpointTypeName); + + Assert.Contains(OpenTelemetryPermissions.Read, permissions); + } + + private static IReadOnlyCollection GetConfiguredPermissions(string endpointTypeName) + { + var endpointType = typeof(OpenTelemetryFeature).Assembly.GetType(endpointTypeName, throwOnError: true)!; + var endpoint = Activator.CreateInstance(endpointType, new TestOpenTelemetryProvider())!; + var (requestDtoType, responseDtoType) = GetEndpointDtoTypes(endpointType); + var definition = new EndpointDefinition(endpointType, requestDtoType, responseDtoType); + + endpointType + .GetProperty("Definition", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)! + .SetValue(endpoint, definition); + + endpointType.GetMethod("Configure")!.Invoke(endpoint, null); + + var permissions = definition + .GetType() + .GetProperty("AllowedPermissions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)! + .GetValue(definition); + + return Assert.IsAssignableFrom>(permissions).ToArray(); + } + + private static (Type RequestDtoType, Type ResponseDtoType) GetEndpointDtoTypes(Type endpointType) + { + var type = endpointType; + + while (type.BaseType != null) + { + type = type.BaseType; + + if (!type.IsGenericType) + continue; + + var genericTypeDefinition = type.GetGenericTypeDefinition(); + var genericArguments = type.GetGenericArguments(); + + if (genericTypeDefinition == typeof(Elsa.Abstractions.ElsaEndpoint<,>)) + return (genericArguments[0], genericArguments[1]); + + if (genericTypeDefinition == typeof(Elsa.Abstractions.ElsaEndpoint<,,>)) + return (genericArguments[0], genericArguments[1]); + + if (genericTypeDefinition == typeof(Elsa.Abstractions.ElsaEndpointWithoutRequest<>)) + return (typeof(EmptyRequest), genericArguments[0]); + } + + throw new InvalidOperationException($"Unsupported endpoint type '{endpointType.FullName}'."); + } + + private class TestOpenTelemetryProvider : IOpenTelemetryProvider + { + public ValueTask GetResourcesAsync(OpenTelemetryResourceFilter filter, CancellationToken cancellationToken = default) => ValueTask.FromResult(new OpenTelemetryResourceResult([], 0)); + + public ValueTask GetTracesAsync(OpenTelemetryTraceFilter filter, CancellationToken cancellationToken = default) => ValueTask.FromResult(new OpenTelemetryTraceResult([], 0)); + + public ValueTask GetTraceAsync(string traceId, CancellationToken cancellationToken = default) => ValueTask.FromResult(null); + + public ValueTask GetMetricsAsync(OpenTelemetryMetricFilter filter, CancellationToken cancellationToken = default) => ValueTask.FromResult(new OpenTelemetryMetricResult([], [], 0)); + + public ValueTask GetLogsAsync(OpenTelemetryLogFilter filter, CancellationToken cancellationToken = default) => ValueTask.FromResult(new OpenTelemetryLogResult([], 0)); + + public ValueTask GetStorageDiagnosticsAsync(CancellationToken cancellationToken = default) => ValueTask.FromResult(new OpenTelemetryStorageDiagnostics(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); + + public ValueTask GetCollectorConfigurationAsync(CancellationToken cancellationToken = default) + { + var configuration = new CollectorConfiguration( + new CollectorEndpointInfo("http/protobuf", "/elsa/otlp/v1", true, null), + new CollectorEndpointInfo("grpc", null, false, "Disabled"), + "OTEL_SERVICE_NAME", + "OTEL_EXPORTER_OTLP_ENDPOINT", + "OTEL_EXPORTER_OTLP_PROTOCOL", + new Dictionary()); + + return ValueTask.FromResult(configuration); + } + } +} diff --git a/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/OpenTelemetryHubTests.cs b/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/OpenTelemetryHubTests.cs new file mode 100644 index 000000000..fae7cc61b --- /dev/null +++ b/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/OpenTelemetryHubTests.cs @@ -0,0 +1,304 @@ +using System.Security.Claims; +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Options; +using Elsa.Diagnostics.OpenTelemetry.Permissions; +using Elsa.Diagnostics.OpenTelemetry.Providers.InMemory; +using Elsa.Diagnostics.OpenTelemetry.RealTime; +using FastEndpoints; +using FastEndpoints.Security; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging.Abstractions; +using Xunit.Sdk; +using OptionsFactory = Microsoft.Extensions.Options.Options; + +namespace Elsa.Diagnostics.OpenTelemetry.IntegrationTests; + +public class OpenTelemetryHubTests +{ + private readonly DateTimeOffset _now = new(2026, 5, 26, 10, 0, 0, TimeSpan.Zero); + + [Fact] + public async Task SubscribeAsync_WhenUserLacksPermission_DeniesAccess() + { + var hub = CreateHub(new TestLiveFeed(), "write:diagnostics:opentelemetry"); + + await Assert.ThrowsAsync(() => hub.SubscribeAsync(new())); + } + + [Theory] + [InlineData(OpenTelemetryPermissions.Read)] + [InlineData(PermissionNames.All)] + [InlineData("read:*")] + public async Task SubscribeAsync_WhenUserCanRead_ForwardsItemsToCaller(string permission) + { + var liveFeed = new TestLiveFeed(new OpenTelemetryStreamItem { Trace = Trace("trace-1") }); + var caller = new CapturingOpenTelemetryClient(); + var hub = CreateHub(liveFeed, permission, caller); + + await hub.SubscribeAsync(new OpenTelemetryTraceFilter { TraceId = "trace-1" }); + + await AssertEventuallyAsync(() => + { + Assert.Equal("trace-1", Assert.Single(caller.Items).Trace?.TraceId); + Assert.Equal("trace-1", liveFeed.Filter?.TraceId); + }); + } + + [Fact] + public async Task SubscribeAsync_WhenFilterTimeRangeIsInvalid_RejectsFilter() + { + var hub = CreateHub(new TestLiveFeed(), OpenTelemetryPermissions.Read); + + await Assert.ThrowsAsync(() => hub.SubscribeAsync(new OpenTelemetryTraceFilter + { + From = _now.AddMinutes(1), + To = _now + })); + } + + [Fact] + public async Task LiveFeed_WhenTraceFilterIsSet_OnlyPublishesMatchingTraces() + { + var liveFeed = new InMemoryOpenTelemetryLiveFeed(OptionsFactory.Create(new OpenTelemetryDiagnosticsOptions())); + using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5)); + await using var enumerator = liveFeed.SubscribeAsync(new OpenTelemetryTraceFilter { TraceId = "trace-keep" }, timeout.Token).GetAsyncEnumerator(timeout.Token); + var next = enumerator.MoveNextAsync().AsTask(); + + await liveFeed.PublishAsync(new OpenTelemetryBatch([], [Trace("trace-skip"), Trace("trace-keep")], [], [], [], []), timeout.Token); + + Assert.True(await next); + Assert.Equal("trace-keep", enumerator.Current.Trace?.TraceId); + } + + [Fact] + public async Task LiveFeed_WhenServiceNameFilterIsSet_OnlyPublishesMatchingResourcesAndTraces() + { + var liveFeed = new InMemoryOpenTelemetryLiveFeed(OptionsFactory.Create(new OpenTelemetryDiagnosticsOptions())); + using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5)); + await using var enumerator = liveFeed.SubscribeAsync(new OpenTelemetryTraceFilter { ServiceName = "api" }, timeout.Token).GetAsyncEnumerator(timeout.Token); + var next = enumerator.MoveNextAsync().AsTask(); + + await liveFeed.PublishAsync(new OpenTelemetryBatch( + [Resource("resource-skip", "worker")], + [Trace("trace-skip", ["resource-skip"])], + [], [], [], []), timeout.Token); + + var completed = await Task.WhenAny(next, Task.Delay(TimeSpan.FromMilliseconds(150), timeout.Token)); + Assert.NotSame(next, completed); + + await liveFeed.PublishAsync(new OpenTelemetryBatch( + [Resource("resource-keep", "api")], + [Trace("trace-keep", ["resource-keep"])], + [], [], [], []), timeout.Token); + + Assert.True(await next); + Assert.Equal("resource-keep", enumerator.Current.Resource?.Id); + + Assert.True(await enumerator.MoveNextAsync()); + Assert.Equal("trace-keep", enumerator.Current.Trace?.TraceId); + } + + [Fact] + public async Task LiveFeed_WhenResourceFilterIsSet_FiltersLogsAndMetricPoints() + { + var liveFeed = new InMemoryOpenTelemetryLiveFeed(OptionsFactory.Create(new OpenTelemetryDiagnosticsOptions())); + using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5)); + await using var enumerator = liveFeed.SubscribeAsync(new OpenTelemetryTraceFilter { ResourceId = "resource-keep" }, timeout.Token).GetAsyncEnumerator(timeout.Token); + var first = enumerator.MoveNextAsync().AsTask(); + + await liveFeed.PublishAsync(new OpenTelemetryBatch( + [], + [], + [], + [], + [MetricPoint("point-skip", "resource-skip"), MetricPoint("point-keep", "resource-keep")], + [Log("log-skip", "resource-skip"), Log("log-keep", "resource-keep")]), timeout.Token); + + Assert.True(await first); + Assert.Equal("log-keep", enumerator.Current.Log?.Id); + + Assert.True(await enumerator.MoveNextAsync()); + Assert.Equal("point-keep", enumerator.Current.MetricPoint?.Id); + } + + [Fact] + public async Task LiveFeed_WhenSubscriberQueueOverflows_PublishesDroppedItemSummary() + { + var liveFeed = new InMemoryOpenTelemetryLiveFeed(OptionsFactory.Create(new OpenTelemetryDiagnosticsOptions { SubscriberChannelCapacity = 1 })); + using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5)); + await using var enumerator = liveFeed.SubscribeAsync(new OpenTelemetryTraceFilter(), timeout.Token).GetAsyncEnumerator(timeout.Token); + var first = enumerator.MoveNextAsync().AsTask(); + + await liveFeed.PublishAsync(new OpenTelemetryBatch([], [Trace("trace-1"), Trace("trace-2"), Trace("trace-3")], [], [], [], []), timeout.Token); + + Assert.True(await first); + + OpenTelemetryStreamItem? summary = enumerator.Current.DroppedItems != null ? enumerator.Current : null; + for (var i = 0; summary == null && i < 5 && await enumerator.MoveNextAsync(); i++) + { + if (enumerator.Current.DroppedItems != null) + summary = enumerator.Current; + } + + Assert.NotNull(summary); + var nonNullSummary = summary!; + Assert.Equal(OpenTelemetrySignalType.Trace, nonNullSummary.DroppedItems!.SignalType); + Assert.Equal("SubscriberQueueFull", nonNullSummary.DroppedItems.Reason); + Assert.True(nonNullSummary.DroppedItems.Count > 0); + } + + private OpenTelemetryHub CreateHub(IOpenTelemetryLiveFeed liveFeed, string permission, IOpenTelemetryClient? caller = null) + { + caller ??= new CapturingOpenTelemetryClient(); + var hubContext = new TestHubContext(caller); + var subscriptionManager = new OpenTelemetrySubscriptionManager(liveFeed, hubContext, NullLogger.Instance); + + return new OpenTelemetryHub(subscriptionManager) + { + Context = new TestHubCallerContext(CreateUser(permission)), + Clients = new TestHubCallerClients(caller) + }; + } + + private ClaimsPrincipal CreateUser(string permission) + { + var permissionClaimType = (string)typeof(SecurityOptions) + .GetProperty(nameof(SecurityOptions.PermissionsClaimType))! + .GetValue(new Config().Security)!; + var identity = new ClaimsIdentity([new Claim(permissionClaimType, permission)], "Test"); + + return new ClaimsPrincipal(identity); + } + + private TelemetryResource Resource(string id, string serviceName) + { + return new(id, serviceName, null, null, new Dictionary(), _now, TelemetryResourceStatus.Active); + } + + private TelemetryTrace Trace(string traceId, IReadOnlyCollection? resourceIds = null, IReadOnlyCollection? workflowInstanceIds = null) + { + return new(traceId, $"{traceId}-root", traceId, _now, _now.AddMilliseconds(10), TimeSpan.FromMilliseconds(10), SpanStatus.Ok, resourceIds ?? [], workflowInstanceIds ?? [], 1); + } + + private MetricPoint MetricPoint(string id, string resourceId) + { + return new(id, $"{id}-instrument", $"{id}-instrument", resourceId, _now, 1, null, null, new Dictionary(), null, null); + } + + private OtlpLogRecord Log(string id, string resourceId) + { + return new(id, resourceId, _now, "Information", 9, id, null, null, new Dictionary()); + } + + private class TestLiveFeed(params OpenTelemetryStreamItem[] items) : IOpenTelemetryLiveFeed + { + public OpenTelemetryTraceFilter? Filter { get; private set; } + + public ValueTask PublishAsync(OpenTelemetryBatch batch, CancellationToken cancellationToken = default) => ValueTask.CompletedTask; + + public async IAsyncEnumerable SubscribeAsync(OpenTelemetryTraceFilter filter, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default) + { + Filter = filter; + + foreach (var item in items) + { + cancellationToken.ThrowIfCancellationRequested(); + yield return item; + await Task.Yield(); + } + } + } + + private class CapturingOpenTelemetryClient : IOpenTelemetryClient + { + public List Items { get; } = []; + + public Task ReceiveAsync(OpenTelemetryStreamItem item) + { + Items.Add(item); + return Task.CompletedTask; + } + } + + private class TestHubCallerClients(IOpenTelemetryClient caller) : IHubCallerClients + { + public IOpenTelemetryClient Caller { get; } = caller; + public IOpenTelemetryClient Others => throw new NotSupportedException(); + public IOpenTelemetryClient All => throw new NotSupportedException(); + public IOpenTelemetryClient AllExcept(IReadOnlyList excludedConnectionIds) => throw new NotSupportedException(); + public IOpenTelemetryClient Client(string connectionId) => throw new NotSupportedException(); + public IOpenTelemetryClient Clients(IReadOnlyList connectionIds) => throw new NotSupportedException(); + public IOpenTelemetryClient Group(string groupName) => throw new NotSupportedException(); + public IOpenTelemetryClient GroupExcept(string groupName, IReadOnlyList excludedConnectionIds) => throw new NotSupportedException(); + public IOpenTelemetryClient Groups(IReadOnlyList groupNames) => throw new NotSupportedException(); + public IOpenTelemetryClient OthersInGroup(string groupName) => throw new NotSupportedException(); + public IOpenTelemetryClient User(string userId) => throw new NotSupportedException(); + public IOpenTelemetryClient Users(IReadOnlyList userIds) => throw new NotSupportedException(); + } + + private class TestHubContext(IOpenTelemetryClient caller) : IHubContext + { + public IHubClients Clients { get; } = new TestHubClients(caller); + + public IGroupManager Groups { get; } = new TestGroupManager(); + } + + private class TestHubClients(IOpenTelemetryClient caller) : IHubClients + { + public IOpenTelemetryClient All => throw new NotSupportedException(); + public IOpenTelemetryClient AllExcept(IReadOnlyList excludedConnectionIds) => throw new NotSupportedException(); + public IOpenTelemetryClient Client(string connectionId) => caller; + public IOpenTelemetryClient Clients(IReadOnlyList connectionIds) => throw new NotSupportedException(); + public IOpenTelemetryClient Group(string groupName) => throw new NotSupportedException(); + public IOpenTelemetryClient GroupExcept(string groupName, IReadOnlyList excludedConnectionIds) => throw new NotSupportedException(); + public IOpenTelemetryClient Groups(IReadOnlyList groupNames) => throw new NotSupportedException(); + public IOpenTelemetryClient User(string userId) => throw new NotSupportedException(); + public IOpenTelemetryClient Users(IReadOnlyList userIds) => throw new NotSupportedException(); + } + + private class TestGroupManager : IGroupManager + { + public Task AddToGroupAsync(string connectionId, string groupName, CancellationToken cancellationToken = default) => Task.CompletedTask; + + public Task RemoveFromGroupAsync(string connectionId, string groupName, CancellationToken cancellationToken = default) => Task.CompletedTask; + } + + private static async Task AssertEventuallyAsync(Action assertion) + { + var deadline = DateTimeOffset.UtcNow.AddSeconds(3); + Exception? lastException = null; + + while (DateTimeOffset.UtcNow < deadline) + { + try + { + assertion(); + return; + } + catch (XunitException e) + { + lastException = e; + await Task.Delay(25); + } + } + + if (lastException != null) + throw lastException; + } + + private class TestHubCallerContext(ClaimsPrincipal user) : HubCallerContext + { + public override string ConnectionId { get; } = "connection-1"; + public override string? UserIdentifier { get; } = "user-1"; + public override ClaimsPrincipal? User { get; } = user; + public override IDictionary Items { get; } = new Dictionary(); + public override IFeatureCollection Features { get; } = new FeatureCollection(); + public override CancellationToken ConnectionAborted { get; } = CancellationToken.None; + + public override void Abort() + { + } + } +} diff --git a/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/OtlpHttpIngestionTests.cs b/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/OtlpHttpIngestionTests.cs new file mode 100644 index 000000000..d0c48fb7a --- /dev/null +++ b/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/OtlpHttpIngestionTests.cs @@ -0,0 +1,189 @@ +using System.Buffers.Binary; +using System.Net; +using System.Text; +using Elsa.Diagnostics.OpenTelemetry.Contracts; +using Elsa.Diagnostics.OpenTelemetry.Extensions; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Options; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; + +namespace Elsa.Diagnostics.OpenTelemetry.IntegrationTests; + +public class OtlpHttpIngestionTests : IAsyncLifetime +{ + private static readonly byte[] TraceId = Convert.FromHexString("00112233445566778899aabbccddeeff"); + private static readonly byte[] SpanId = Convert.FromHexString("0011223344556677"); + private static readonly byte[] ChildSpanId = Convert.FromHexString("8899aabbccddeeff"); + private static readonly DateTimeOffset Timestamp = new(2026, 5, 26, 10, 0, 0, TimeSpan.Zero); + + private WebApplication? _app; + private HttpClient _httpClient = null!; + + public async Task InitializeAsync() + { + var builder = WebApplication.CreateSlimBuilder(); + builder.WebHost.UseTestServer(); + builder.Services.AddOpenTelemetryDiagnosticsServices(options => + { + options.AllowUnauthenticatedLoopback = true; + options.HttpEndpointPath = "/elsa/otlp/v1"; + }); + + _app = builder.Build(); + _app.Use((context, next) => + { + context.Connection.RemoteIpAddress = IPAddress.Loopback; + return next(); + }); + _app.MapOpenTelemetryHttpProtobufCollector(); + + await _app.StartAsync(); + _httpClient = _app.GetTestClient(); + } + + public async Task DisposeAsync() + { + _httpClient.Dispose(); + + if (_app == null) + return; + + await _app.StopAsync(); + await _app.DisposeAsync(); + } + + [Fact] + public async Task PostTraces_WhenPayloadIsValid_StoresQueryableTrace() + { + using var content = new ByteArrayContent(CreateTracePayload()); + content.Headers.ContentType = new("application/x-protobuf"); + + var response = await _httpClient.PostAsync("/elsa/otlp/v1/traces", content); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + var provider = _app!.Services.GetRequiredService(); + var result = await provider.GetTracesAsync(new OpenTelemetryTraceFilter { TraceId = "00112233445566778899aabbccddeeff" }); + var trace = Assert.Single(result.Items); + + Assert.Equal("Workflow/Approve", trace.Name); + Assert.Equal("wf-1", Assert.Single(trace.WorkflowInstanceIds)); + + var detail = await provider.GetTraceAsync(trace.TraceId); + + Assert.NotNull(detail); + Assert.Equal(2, detail.Spans.Count); + + var rootSpan = Assert.Single(detail.Spans, x => x.SpanId == "0011223344556677"); + Assert.Equal("order-workflow", rootSpan.Attributes["workflow.definition.id"]); + Assert.Equal("wf-1", rootSpan.Attributes["workflow.instance.id"]); + + var activitySpan = Assert.Single(detail.Spans, x => x.SpanId == "8899aabbccddeeff"); + Assert.Equal("0011223344556677", activitySpan.ParentSpanId); + Assert.Equal("approve-task", activitySpan.Attributes["activity.id"]); + Assert.Equal("node-approve", activitySpan.Attributes["activity.node.id"]); + } + + [Fact] + public async Task PostTraces_WhenPayloadExceedsConfiguredLimit_ReturnsPayloadTooLarge() + { + _app!.Services.GetRequiredService>().Value.MaxHttpRequestBodySize = 1; + using var content = new ByteArrayContent(CreateTracePayload()); + content.Headers.ContentType = new("application/x-protobuf"); + + var response = await _httpClient.PostAsync("/elsa/otlp/v1/traces", content); + + Assert.Equal(HttpStatusCode.RequestEntityTooLarge, response.StatusCode); + } + + [Fact] + public async Task PostTraces_WhenPayloadIsTruncated_ReturnsBadRequest() + { + using var content = new ByteArrayContent([0x0a, 0x04, 0x08]); + content.Headers.ContentType = new("application/x-protobuf"); + + var response = await _httpClient.PostAsync("/elsa/otlp/v1/traces", content); + + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + private static byte[] CreateTracePayload() + { + return Message(1, + Join( + Message(1, Resource()), + Message(2, + Join( + Message(2, + Join( + Bytes(1, TraceId), + Bytes(2, SpanId), + String(5, "Workflow/Approve"), + Varint(6, 1), + Varint(7, UnixNanos(Timestamp)), + Varint(8, UnixNanos(Timestamp.AddMilliseconds(25))), + Message(9, KeyValue("workflow.instance.id", "wf-1")), + Message(9, KeyValue("workflow.definition.id", "order-workflow")), + Message(15, Varint(3, 1)))), + Message(2, + Join( + Bytes(1, TraceId), + Bytes(2, ChildSpanId), + Bytes(4, SpanId), + String(5, "Activity/ApproveTask"), + Varint(6, 1), + Varint(7, UnixNanos(Timestamp.AddMilliseconds(5))), + Varint(8, UnixNanos(Timestamp.AddMilliseconds(20))), + Message(9, KeyValue("workflow.instance.id", "wf-1")), + Message(9, KeyValue("activity.id", "approve-task")), + Message(9, KeyValue("activity.node.id", "node-approve")), + Message(15, Varint(3, 1)))))))); + } + + private static byte[] Resource() + { + return Join( + Message(1, KeyValue("service.name", "elsa-server")), + Message(1, KeyValue("service.instance.id", "node-1")), + Message(1, KeyValue("telemetry.sdk.language", "dotnet"))); + } + + private static byte[] KeyValue(string key, string value) => Join(String(1, key), Message(2, String(1, value))); + + private static byte[] Message(int fieldNumber, byte[] value) => Join(Varint((ulong)((fieldNumber << 3) | 2)), Varint((ulong)value.Length), value); + + private static byte[] String(int fieldNumber, string value) => Message(fieldNumber, Encoding.UTF8.GetBytes(value)); + + private static byte[] Bytes(int fieldNumber, byte[] value) => Message(fieldNumber, value); + + private static byte[] Varint(int fieldNumber, ulong value) => Join(Varint((ulong)(fieldNumber << 3)), Varint(value)); + + private static byte[] Varint(ulong value) + { + var bytes = new List(); + while (value >= 0x80) + { + bytes.Add((byte)(value | 0x80)); + value >>= 7; + } + bytes.Add((byte)value); + return bytes.ToArray(); + } + + private static ulong UnixNanos(DateTimeOffset timestamp) => (ulong)(timestamp - DateTimeOffset.UnixEpoch).Ticks * 100; + + private static byte[] Join(params byte[][] segments) + { + var result = new byte[segments.Sum(x => x.Length)]; + var offset = 0; + foreach (var segment in segments) + { + segment.CopyTo(result, offset); + offset += segment.Length; + } + + return result; + } +} diff --git a/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/OtlpIngestionSecurityTests.cs b/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/OtlpIngestionSecurityTests.cs new file mode 100644 index 000000000..bee271fc8 --- /dev/null +++ b/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/OtlpIngestionSecurityTests.cs @@ -0,0 +1,101 @@ +using System.Net; +using Elsa.Diagnostics.OpenTelemetry.Extensions; +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Options; +using Elsa.Diagnostics.OpenTelemetry.Services; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using OptionsFactory = Microsoft.Extensions.Options.Options; + +namespace Elsa.Diagnostics.OpenTelemetry.IntegrationTests; + +public class OtlpIngestionSecurityTests +{ + [Fact] + public async Task PostTraces_WhenLoopbackAndNoApiKey_AllowsDevelopmentIngestion() + { + await using var app = await CreateAppAsync(); + using var client = app.GetTestClient(); + + var response = await client.PostAsync("/elsa/otlp/v1/traces", CreateEmptyProtobufContent()); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + [Fact] + public async Task PostTraces_WhenNonLoopbackAndNoApiKey_RejectsIngestion() + { + await using var app = await CreateAppAsync(); + using var client = app.GetTestClient(); + using var request = new HttpRequestMessage(HttpMethod.Post, "/elsa/otlp/v1/traces") + { + Content = CreateEmptyProtobufContent() + }; + request.Headers.Add("x-test-remote-ip", "10.0.0.5"); + + var response = await client.SendAsync(request); + + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + } + + [Fact] + public async Task PostTraces_WhenApiKeyMatches_AllowsNonLoopbackIngestion() + { + await using var app = await CreateAppAsync(options => options.ApiKey = "secret"); + using var client = app.GetTestClient(); + using var request = new HttpRequestMessage(HttpMethod.Post, "/elsa/otlp/v1/traces") + { + Content = CreateEmptyProtobufContent() + }; + request.Headers.Add("x-test-remote-ip", "10.0.0.5"); + request.Headers.Add("x-otlp-api-key", "secret"); + + var response = await client.SendAsync(request); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + [Fact] + public async Task CollectorConfiguration_WhenApiKeyIsConfigured_DoesNotExposeSecret() + { + var provider = new CollectorConfigurationProvider(OptionsFactory.Create(new OpenTelemetryDiagnosticsOptions { ApiKey = "secret" })); + + var configuration = await provider.GetAsync(); + + Assert.Equal("", configuration.RequiredHeaders["x-otlp-api-key"]); + Assert.DoesNotContain("secret", configuration.RequiredHeaders.Values); + } + + private static async Task CreateAppAsync(Action? configure = null) + { + var builder = WebApplication.CreateSlimBuilder(); + builder.WebHost.UseTestServer(); + builder.Services.AddOpenTelemetryDiagnosticsServices(options => + { + options.AllowUnauthenticatedLoopback = true; + options.HttpEndpointPath = "/elsa/otlp/v1"; + configure?.Invoke(options); + }); + + var app = builder.Build(); + app.Use(async (context, next) => + { + context.Connection.RemoteIpAddress = context.Request.Headers.TryGetValue("x-test-remote-ip", out var value) && IPAddress.TryParse(value.ToString(), out var remoteIpAddress) + ? remoteIpAddress + : IPAddress.Loopback; + + await next(); + }); + app.MapOpenTelemetryHttpProtobufCollector(); + await app.StartAsync(); + return app; + } + + private static ByteArrayContent CreateEmptyProtobufContent() + { + var content = new ByteArrayContent([]); + content.Headers.ContentType = new("application/x-protobuf"); + return content; + } +} diff --git a/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/Usings.cs b/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/Usings.cs new file mode 100644 index 000000000..c802f4480 --- /dev/null +++ b/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/Usings.cs @@ -0,0 +1 @@ +global using Xunit; diff --git a/test/integration/Elsa.JavaScript.IntegrationTests/JavaScriptFeatureTests.cs b/test/integration/Elsa.JavaScript.IntegrationTests/JavaScriptFeatureTests.cs deleted file mode 100644 index a6fcd4dfb..000000000 --- a/test/integration/Elsa.JavaScript.IntegrationTests/JavaScriptFeatureTests.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Reflection; -using Elsa.Expressions.JavaScript.ShellFeatures; -using Elsa.Expressions.Options; -using Elsa.Expressions.Services; -using Jint.Runtime; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; - -namespace Elsa.JavaScript.IntegrationTests; - -public class JavaScriptFeatureTests -{ - [Fact] - public void ConfigureServices_RegistersUniqueWrapperExceptionAlias() - { - var services = new ServiceCollection(); - var feature = new JavaScriptFeature(); - var wrapperExceptionType = typeof(JavaScriptException).GetNestedType("JavaScriptErrorWrapperException", BindingFlags.Public | BindingFlags.NonPublic); - - feature.ConfigureServices(services); - - using var serviceProvider = services.BuildServiceProvider(); - var expressionOptions = serviceProvider.GetRequiredService>(); - var registry = new WellKnownTypeRegistry(expressionOptions); - - Assert.NotNull(wrapperExceptionType); - Assert.True(registry.TryGetType("Jint.JavaScriptErrorWrapperException", out var type)); - Assert.Equal(wrapperExceptionType, type); - Assert.False(registry.TryGetType(wrapperExceptionType.Name, out _)); - } -} diff --git a/test/integration/Elsa.Workflows.IntegrationTests/Serialization/JsonSerialization/Tests.cs b/test/integration/Elsa.Workflows.IntegrationTests/Serialization/JsonSerialization/Tests.cs index 7684f1da3..1953f511e 100644 --- a/test/integration/Elsa.Workflows.IntegrationTests/Serialization/JsonSerialization/Tests.cs +++ b/test/integration/Elsa.Workflows.IntegrationTests/Serialization/JsonSerialization/Tests.cs @@ -1,6 +1,7 @@ using System.Text.Json; using System.Text.Json.Nodes; -using Elsa.Expressions.Options; +using Elsa.Common.Serialization; +using Elsa.Extensions; using Elsa.Testing.Shared; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json.Linq; @@ -11,7 +12,7 @@ namespace Elsa.Workflows.IntegrationTests.Serialization.JsonSerialization; public class SerializationTests(ITestOutputHelper testOutputHelper) { private readonly IServiceProvider _services = new TestApplicationBuilder(testOutputHelper) - .ConfigureServices(services => services.Configure(options => options.RegisterTypeAlias(typeof(TestObject), nameof(TestObject)))) + .ConfigureServices(services => services.Configure(options => options.AddTypeAlias())) .Build(); [Theory(DisplayName = "write")] diff --git a/test/integration/Elsa.Workflows.IntegrationTests/Serialization/Polymorphism/Tests.cs b/test/integration/Elsa.Workflows.IntegrationTests/Serialization/Polymorphism/Tests.cs index 29155c1b7..a99897a4d 100644 --- a/test/integration/Elsa.Workflows.IntegrationTests/Serialization/Polymorphism/Tests.cs +++ b/test/integration/Elsa.Workflows.IntegrationTests/Serialization/Polymorphism/Tests.cs @@ -2,9 +2,11 @@ using System.Dynamic; using System.Text.Json; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Metadata; -using Elsa.Expressions.Services; +using Elsa.Workflows.Options; using Elsa.Workflows.Serialization.Converters; using Elsa.Workflows.Serialization.ReferenceHandlers; +using Elsa.Workflows.Services; +using Elsa.Common.Serialization; namespace Elsa.Workflows.IntegrationTests.Serialization.Polymorphism; @@ -74,9 +76,9 @@ public class Tests private JsonSerializerOptions GetSerializerOptions() { var referenceHandler = new CrossScopedReferenceHandler(); - var wellKnownTypeRegistry = new WellKnownTypeRegistry(); - wellKnownTypeRegistry.RegisterType(typeof(Model), nameof(Model)); - wellKnownTypeRegistry.RegisterType(typeof(CustomDictionary), nameof(CustomDictionary)); + var workflowJsonTypeRegistry = new SerializationTypeRegistry(Microsoft.Extensions.Options.Options.Create(new SerializationTypeOptions())); + workflowJsonTypeRegistry.RegisterType(typeof(Model), nameof(Model)); + workflowJsonTypeRegistry.RegisterType(typeof(CustomDictionary), nameof(CustomDictionary)); var options = new JsonSerializerOptions { @@ -88,7 +90,7 @@ public class Tests options.Converters.Add(new JsonStringEnumConverter()); options.Converters.Add(JsonMetadataServices.TimeSpanConverter); - options.Converters.Add(new PolymorphicObjectConverterFactory(wellKnownTypeRegistry)); + options.Converters.Add(new PolymorphicObjectConverterFactory(workflowJsonTypeRegistry)); return options; } diff --git a/test/unit/Elsa.Common.UnitTests/Entities/OrderDefinitionTests.cs b/test/unit/Elsa.Common.UnitTests/Entities/OrderDefinitionTests.cs deleted file mode 100644 index dbecd8972..000000000 --- a/test/unit/Elsa.Common.UnitTests/Entities/OrderDefinitionTests.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Text.Json; -using Elsa.Common.Entities; - -namespace Elsa.Common.UnitTests.Entities; - -public class OrderDefinitionTests -{ - [Fact] - public void Serialize_DoesNotIncludeKeySelectorText() - { - var order = new OrderDefinition(x => x.Name, OrderDirection.Ascending); - - var json = JsonSerializer.Serialize(order); - - Assert.DoesNotContain(nameof(OrderDefinition.KeySelectorText), json); - } - - private sealed class TestEntity - { - public string Name { get; set; } = null!; - } -} diff --git a/test/unit/Elsa.Common.UnitTests/ShellHandlers/MediatorBackgroundTaskTests.cs b/test/unit/Elsa.Common.UnitTests/ShellHandlers/MediatorBackgroundTaskTests.cs new file mode 100644 index 000000000..1a69f350b --- /dev/null +++ b/test/unit/Elsa.Common.UnitTests/ShellHandlers/MediatorBackgroundTaskTests.cs @@ -0,0 +1,101 @@ +using Elsa.Common; +using Elsa.Common.ShellHandlers; +using Elsa.Mediator; +using Elsa.Mediator.Contracts; +using Elsa.Mediator.Models; +using Microsoft.Extensions.DependencyInjection; + +namespace Elsa.Common.UnitTests.ShellHandlers; + +public class MediatorBackgroundTaskTests +{ + [Fact] + public async Task StartAsync_StartsMediatorCommandProcessor() + { + // Arrange + await using var serviceProvider = CreateServiceProvider(); + var backgroundTask = GetMediatorBackgroundTask(serviceProvider); + var commandSender = serviceProvider.GetRequiredService(); + var sink = serviceProvider.GetRequiredService(); + + // Act + await backgroundTask.StartAsync(CancellationToken.None); + + try + { + await commandSender.SendAsync(new TestCommand("hello"), CommandStrategy.Background, CancellationToken.None); + + // Assert + var completedTask = await Task.WhenAny(sink.Handled.Task, Task.Delay(TimeSpan.FromSeconds(5))); + Assert.Same(sink.Handled.Task, completedTask); + Assert.Equal("hello", await sink.Handled.Task); + } + finally + { + await backgroundTask.StopAsync(CancellationToken.None); + } + } + + [Fact] + public async Task StopAsync_KeepsProcessorRunning_UntilAllBackgroundTaskReferencesStop() + { + // Arrange + await using var serviceProvider = CreateServiceProvider(); + await using var scope1 = serviceProvider.CreateAsyncScope(); + await using var scope2 = serviceProvider.CreateAsyncScope(); + var backgroundTask1 = GetMediatorBackgroundTask(scope1.ServiceProvider); + var backgroundTask2 = GetMediatorBackgroundTask(scope2.ServiceProvider); + var commandSender = serviceProvider.GetRequiredService(); + var sink = serviceProvider.GetRequiredService(); + + // Act + await backgroundTask1.StartAsync(CancellationToken.None); + await backgroundTask2.StartAsync(CancellationToken.None); + await backgroundTask1.StopAsync(CancellationToken.None); + + try + { + await commandSender.SendAsync(new TestCommand("hello"), CommandStrategy.Background, CancellationToken.None); + + // Assert + var completedTask = await Task.WhenAny(sink.Handled.Task, Task.Delay(TimeSpan.FromSeconds(5))); + Assert.Same(sink.Handled.Task, completedTask); + Assert.Equal("hello", await sink.Handled.Task); + } + finally + { + await backgroundTask2.StopAsync(CancellationToken.None); + } + } + + private static ServiceProvider CreateServiceProvider() + { + var services = new ServiceCollection(); + services.AddLogging(); + new ShellFeatures.MediatorFeature().ConfigureServices(services); + services.AddSingleton(); + services.AddCommandHandler(); + return services.BuildServiceProvider(); + } + + private static MediatorBackgroundTask GetMediatorBackgroundTask(IServiceProvider serviceProvider) + { + return serviceProvider.GetServices().OfType().Single(); + } + + private sealed record TestCommand(string Message) : ICommand; + + private sealed class CommandSink + { + public TaskCompletionSource Handled { get; } = new(TaskCreationOptions.RunContinuationsAsynchronously); + } + + private sealed class TestCommandHandler(CommandSink sink) : ICommandHandler + { + public Task HandleAsync(TestCommand command, CancellationToken cancellationToken) + { + sink.Handled.TrySetResult(command.Message); + return Task.FromResult(Unit.Instance); + } + } +} diff --git a/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/ConsoleHostStateCollection.cs b/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/ConsoleHostStateCollection.cs index 01db75930..23d0034e3 100644 --- a/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/ConsoleHostStateCollection.cs +++ b/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/ConsoleHostStateCollection.cs @@ -1,11 +1,9 @@ -using ConsoleLogStreaming.Core; - namespace Elsa.Diagnostics.ConsoleLogs.UnitTests; /// /// xUnit collection used by every test class that mutates the process-wide console stream hook -/// or . Members of this collection run sequentially, preventing parallel -/// tests from racing on the same static state. +/// or console capture. Members of this collection run sequentially, preventing parallel tests from racing +/// on the same static state. /// [CollectionDefinition(Name, DisableParallelization = true)] public sealed class ConsoleHostStateCollection diff --git a/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/ConsoleLogContextAccessorTests.cs b/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/ConsoleLogContextAccessorTests.cs index e85ba4dff..e756b6ece 100644 --- a/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/ConsoleLogContextAccessorTests.cs +++ b/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/ConsoleLogContextAccessorTests.cs @@ -1,5 +1,4 @@ using ConsoleLogStreaming.Core; -using ConsoleLogStreaming.Core.Capture; using ConsoleLogStreaming.Core.DependencyInjection; using Elsa.Diagnostics.ConsoleLogs.Contracts; using Elsa.Diagnostics.ConsoleLogs.Services; @@ -13,22 +12,10 @@ using Microsoft.Extensions.DependencyInjection; namespace Elsa.Diagnostics.ConsoleLogs.UnitTests; [Collection(ConsoleHostStateCollection.Name)] -public class ConsoleLogContextAccessorTests : IAsyncLifetime +public class ConsoleLogContextAccessorTests { private readonly ConsoleLogContextAccessor _accessor = ConsoleLogContextAccessor.Instance; - public Task InitializeAsync() - { - ConsoleStreamHook.Uninstall(); - return Task.CompletedTask; - } - - public Task DisposeAsync() - { - ConsoleStreamHook.Uninstall(); - return Task.CompletedTask; - } - [Fact] public void PushMetadata_RestoresNestedCaseInsensitiveMetadata() { @@ -90,49 +77,6 @@ public class ConsoleLogContextAccessorTests : IAsyncLifetime Assert.Equal("workflow-b", line.Metadata[ConsoleLogMetadataKeys.WorkflowInstanceId]); } - [Fact] - public void ConsoleLineBuffer_PreservesWorkflowMetadataForMultilineOutput() - { - var buffer = new ConsoleLineBuffer(Microsoft.Extensions.Options.Options.Create(new ConsoleLogStreaming.Core.Options.ConsoleLogOptions())); - IReadOnlyCollection lines; - - using (_accessor.PushWorkflowInstanceId("workflow-multiline")) - lines = buffer.Append("first line\nsecond line\n", DateTimeOffset.UtcNow, _accessor.GetMetadata()); - - Assert.Collection( - lines, - line => Assert.Equal("workflow-multiline", line.Metadata[ConsoleLogMetadataKeys.WorkflowInstanceId]), - line => Assert.Equal("workflow-multiline", line.Metadata[ConsoleLogMetadataKeys.WorkflowInstanceId])); - } - - [Fact] - public async Task ConsoleCapture_AttachesWorkflowMetadataToNonLoggerConsoleWrites() - { - await using var serviceProvider = new ServiceCollection() - .AddSingleton(_accessor) - .AddConsoleLogStreaming(options => options.SourceId = "test-source") - .BuildServiceProvider(); - - var capture = serviceProvider.GetRequiredService(); - await capture.StartAsync(); - - using (_accessor.PushWorkflowInstanceId("workflow-console")) - Console.WriteLine("plain console output"); - - await capture.StopAsync(); - - var result = await serviceProvider.GetRequiredService().GetRecentAsync(new ConsoleLogStreaming.Core.Models.ConsoleLogFilter - { - Metadata = new Dictionary - { - [ConsoleLogMetadataKeys.WorkflowInstanceId] = "workflow-console" - } - }); - - var line = Assert.Single(result.Items, x => x.Text == "plain console output"); - Assert.Equal("workflow-console", line.Metadata[ConsoleLogMetadataKeys.WorkflowInstanceId]); - } - [Fact] public async Task WorkflowExecutionMiddleware_PushesWorkflowInstanceMetadata() { diff --git a/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/ConsoleLogsRegistrationTests.cs b/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/ConsoleLogsRegistrationTests.cs index b3a0ecced..c82975ab1 100644 --- a/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/ConsoleLogsRegistrationTests.cs +++ b/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/ConsoleLogsRegistrationTests.cs @@ -1,9 +1,10 @@ using ConsoleLogStreaming.Core; using ConsoleLogStreaming.Core.Capture; -using ConsoleLogStreaming.Core.Hosting; -using ConsoleLogStreaming.Core.Providers; +using ConsoleLogStreaming.Core.Models; +using CShells.Lifecycle; using Elsa.Diagnostics.ConsoleLogs.Contracts; using Elsa.Diagnostics.ConsoleLogs.Extensions; +using Elsa.Diagnostics.ConsoleLogs.RealTime; using Elsa.Diagnostics.ConsoleLogs.Services; using Elsa.Workflows; using Microsoft.Extensions.DependencyInjection; @@ -28,93 +29,83 @@ public class ConsoleLogsRegistrationTests : IAsyncLifetime } [Fact] - public async Task AddConsoleLogsServices_ResolvesHostOwnedSingletons() + public async Task AddConsoleLogsServices_RegistersConsoleLogPipeline() { var services = new ServiceCollection(); + services.AddLogging(); services.AddConsoleLogsServices(); await using var serviceProvider = services.BuildServiceProvider(); - Assert.IsType(serviceProvider.GetRequiredService()); - var contextAccessor = serviceProvider.GetRequiredService(); - Assert.Same(ConsoleLogStreamingHost.SourceRegistry, serviceProvider.GetRequiredService()); - Assert.Same(ConsoleLogStreamingHost.RedactionPipeline, serviceProvider.GetRequiredService()); - Assert.Same(contextAccessor, serviceProvider.GetRequiredService()); - Assert.Same(contextAccessor, serviceProvider.GetRequiredService()); + Assert.NotNull(serviceProvider.GetRequiredService()); + Assert.NotNull(serviceProvider.GetRequiredService()); + Assert.NotNull(serviceProvider.GetRequiredService()); + Assert.NotNull(serviceProvider.GetRequiredService()); + Assert.Same(serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService()); + Assert.Same(serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService()); + Assert.Contains(serviceProvider.GetServices(), x => x.GetType() == typeof(ConsoleLogCaptureShellInitializer)); + Assert.Contains(serviceProvider.GetServices(), x => x.GetType() == typeof(ConsoleLogCaptureShellDrainHandler)); AssertConsoleLogPipelineContributors(serviceProvider); - Assert.Contains(serviceProvider.GetServices(), x => x.GetType() == typeof(ConsoleLogStreamingHostedService)); - Assert.Same(ConsoleLogStreamingHost.Capture, serviceProvider.GetRequiredService()); - - var services2 = new ServiceCollection(); - services2.AddConsoleLogsServices(); - await using var serviceProvider2 = services2.BuildServiceProvider(); - - Assert.Same(serviceProvider.GetRequiredService(), serviceProvider2.GetRequiredService()); - Assert.Same(serviceProvider.GetRequiredService(), serviceProvider2.GetRequiredService()); - Assert.Same(serviceProvider.GetRequiredService(), serviceProvider2.GetRequiredService()); - Assert.Same(contextAccessor, ConsoleLogStreamingHost.MetadataAccessor); } [Fact] - public async Task AddConsoleLogsServices_RegistersHostOwnedDependencies() + public async Task AddConsoleLogsServices_ShellInitializerStartsCapture() { var services = new ServiceCollection(); + services.AddLogging(); services.AddConsoleLogsServices(); await using var serviceProvider = services.BuildServiceProvider(); + var initializer = serviceProvider.GetServices().OfType().Single(); - foreach (var hostedService in serviceProvider.GetServices()) - await hostedService.StartAsync(CancellationToken.None); + await initializer.InitializeAsync(CancellationToken.None); - var contextAccessor = serviceProvider.GetRequiredService(); - Assert.Same(ConsoleLogStreamingHost.Provider, serviceProvider.GetRequiredService()); - Assert.Same(ConsoleLogStreamingHost.SourceRegistry, serviceProvider.GetRequiredService()); - Assert.Same(ConsoleLogStreamingHost.RedactionPipeline, serviceProvider.GetRequiredService()); - Assert.Same(ConsoleLogStreamingHost.Formatter, serviceProvider.GetRequiredService()); - Assert.Same(contextAccessor, serviceProvider.GetRequiredService()); - Assert.Same(contextAccessor, serviceProvider.GetRequiredService()); - AssertConsoleLogPipelineContributors(serviceProvider); + try + { + var line = $"console-shell-capture-{Guid.NewGuid():N}"; + Console.WriteLine(line); - foreach (var hostedService in serviceProvider.GetServices()) - await hostedService.StopAsync(CancellationToken.None); + var provider = serviceProvider.GetRequiredService(); + + await AssertEventuallyAsync(async () => + { + var result = await provider.GetRecentAsync(new() + { + Query = line, + Limit = 10 + }); + + Assert.Contains(result.Items, x => x.Text.Contains(line, StringComparison.Ordinal)); + }); + } + finally + { + var drainHandler = serviceProvider.GetServices().OfType().Single(); + await drainHandler.DrainAsync(new NoopDrainExtensionHandle(), CancellationToken.None); + } } [Fact] - public async Task ShutdownAsync_ResetsReferenceLeases() - { - ConsoleLogStreamingHost.AddReference(); - ConsoleLogStreamingHost.EnsureInitialized(); - - await ConsoleLogStreamingHost.ShutdownAsync(); - - ConsoleLogStreamingHost.AddReference(); - ConsoleLogStreamingHost.EnsureInitialized(); - await ConsoleLogStreamingHost.ReleaseReferenceAsync(); - - var provider = new CustomProvider(); - Assert.True(ConsoleLogStreamingHost.ConfigureProvider(_ => provider)); - Assert.Same(provider, ConsoleLogStreamingHost.Provider); - } - - [Fact] - public async Task AddConsoleLogsHost_RegistersHostedFlushService() + public async Task AddConsoleLogsHost_RegistersHostedServicesAndCaptureDependencies() { var services = new ServiceCollection(); + services.AddLogging(); services.AddConsoleLogsHost(); await using var serviceProvider = services.BuildServiceProvider(); - - var contextAccessor = serviceProvider.GetRequiredService(); - Assert.Contains(serviceProvider.GetServices(), x => x.GetType() == typeof(ConsoleLogStreamingHostedService)); - Assert.Same(contextAccessor, serviceProvider.GetRequiredService()); - Assert.Same(contextAccessor, serviceProvider.GetRequiredService()); + Assert.NotNull(serviceProvider.GetRequiredService()); + Assert.NotNull(serviceProvider.GetRequiredService()); + Assert.Same(serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService()); + Assert.Same(serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService()); + Assert.Contains(serviceProvider.GetServices(), x => x.GetType().Name == "ConsoleLogCaptureHostedService"); AssertConsoleLogPipelineContributors(serviceProvider); } [Fact] - public void AddConsoleLogsHost_AppliesConfigurationWhenCalledBeforeFirstAccess() + public void AddConsoleLogsHost_AppliesConfiguration() { var services = new ServiceCollection(); + services.AddLogging(); services.AddConsoleLogsHost(options => options.RecentCapacity = 17); using var serviceProvider = services.BuildServiceProvider(); @@ -123,16 +114,172 @@ public class ConsoleLogsRegistrationTests : IAsyncLifetime } [Fact] - public void AddConsoleLogsHost_DoesNotInitializeHostDuringRegistration() + public async Task DecoratedProvider_AttachesAmbientElsaMetadata() { - var services = new ServiceCollection(); - services.AddConsoleLogsHost(); + await using var serviceProvider = new ServiceCollection() + .AddLogging() + .AddConsoleLogsServices(options => options.SourceId = "test-source") + .BuildServiceProvider(); + var contextAccessor = serviceProvider.GetRequiredService(); + var provider = serviceProvider.GetRequiredService(); - Assert.True(ConsoleLogStreamingHost.Configure(options => options.RecentCapacity = 23)); + using (contextAccessor.PushWorkflowInstanceId("workflow-console")) + await provider.PublishAsync(new ConsoleLogLine { Text = "message", Source = new ConsoleLogSource { Id = "test-source" } }); - using var serviceProvider = services.BuildServiceProvider(); + var result = await provider.GetRecentAsync(new ConsoleLogFilter + { + Metadata = new Dictionary + { + [ConsoleLogMetadataKeys.WorkflowInstanceId] = "workflow-console" + } + }); - Assert.Equal(23, serviceProvider.GetRequiredService>().Value.RecentCapacity); + var line = Assert.Single(result.Items); + Assert.Equal("workflow-console", line.Metadata[ConsoleLogMetadataKeys.WorkflowInstanceId]); + } + + [Fact] + public async Task ConsoleCapture_AttachesAmbientElsaMetadataAtWriteTime() + { + await using var serviceProvider = new ServiceCollection() + .AddLogging() + .AddConsoleLogsServices(options => options.SourceId = "test-source") + .BuildServiceProvider(); + var contextAccessor = serviceProvider.GetRequiredService(); + var initializer = serviceProvider.GetServices().OfType().Single(); + + await initializer.InitializeAsync(CancellationToken.None); + + try + { + var line = $"console-workflow-capture-{Guid.NewGuid():N}"; + using (contextAccessor.PushWorkflowInstanceId("workflow-captured")) + Console.WriteLine(line); + + var provider = serviceProvider.GetRequiredService(); + + await AssertEventuallyAsync(async () => + { + var result = await provider.GetRecentAsync(new() + { + Metadata = new Dictionary + { + [ConsoleLogMetadataKeys.WorkflowInstanceId] = "workflow-captured" + }, + Query = line, + Limit = 10 + }); + + var capturedLine = Assert.Single(result.Items); + Assert.Equal("workflow-captured", capturedLine.Metadata[ConsoleLogMetadataKeys.WorkflowInstanceId]); + }); + } + finally + { + var drainHandler = serviceProvider.GetServices().OfType().Single(); + await drainHandler.DrainAsync(new NoopDrainExtensionHandle(), CancellationToken.None); + } + } + + [Fact] + public async Task AddConsoleLogsServices_DecoratesExistingProvider() + { + var innerProvider = new RecordingConsoleLogProvider(); + await using var serviceProvider = new ServiceCollection() + .AddLogging() + .AddSingleton(innerProvider) + .AddConsoleLogsServices() + .BuildServiceProvider(); + var contextAccessor = serviceProvider.GetRequiredService(); + var provider = serviceProvider.GetRequiredService(); + + using (contextAccessor.PushWorkflowInstanceId("workflow-console")) + await provider.PublishAsync(new ConsoleLogLine { Text = "message", Source = new ConsoleLogSource { Id = "test-source" } }); + + Assert.NotNull(innerProvider.PublishedLine); + Assert.Equal("workflow-console", innerProvider.PublishedLine.Metadata[ConsoleLogMetadataKeys.WorkflowInstanceId]); + } + + [Fact] + public async Task DecoratedProvider_FiltersRecentRowsByMetadataWhenInnerProviderDoesNot() + { + var innerProvider = new MetadataIgnoringConsoleLogProvider(); + await using var serviceProvider = new ServiceCollection() + .AddLogging() + .AddSingleton(innerProvider) + .AddConsoleLogsServices() + .BuildServiceProvider(); + var provider = serviceProvider.GetRequiredService(); + + await provider.PublishAsync(CreateLine("workflow-a", "a")); + await provider.PublishAsync(CreateLine("workflow-b", "b")); + + var result = await provider.GetRecentAsync(new() + { + Metadata = new Dictionary + { + [ConsoleLogMetadataKeys.WorkflowInstanceId] = "workflow-b" + } + }); + + var line = Assert.Single(result.Items); + Assert.Equal("b", line.Text); + } + + [Fact] + public async Task DecoratedProvider_FiltersRecentRowsByBufferedMetadataWhenInnerProviderDropsMetadata() + { + var innerProvider = new MetadataDroppingConsoleLogProvider(); + await using var serviceProvider = new ServiceCollection() + .AddLogging() + .AddSingleton(innerProvider) + .AddConsoleLogsServices() + .BuildServiceProvider(); + var contextAccessor = serviceProvider.GetRequiredService(); + var provider = serviceProvider.GetRequiredService(); + + using (contextAccessor.PushWorkflowInstanceId("workflow-buffered")) + await provider.PublishAsync(new ConsoleLogLine { Text = "buffered", Source = new ConsoleLogSource { Id = "test-source" } }); + + Assert.Empty(Assert.Single(innerProvider.PublishedLines).Metadata); + + var result = await provider.GetRecentAsync(new() + { + Metadata = new Dictionary + { + [ConsoleLogMetadataKeys.WorkflowInstanceId] = "workflow-buffered" + } + }); + + var line = Assert.Single(result.Items); + Assert.Equal("buffered", line.Text); + Assert.Equal("workflow-buffered", line.Metadata[ConsoleLogMetadataKeys.WorkflowInstanceId]); + } + + [Fact] + public async Task DecoratedProvider_FiltersLiveRowsByMetadataWhenInnerProviderDoesNot() + { + var innerProvider = new MetadataIgnoringConsoleLogProvider(); + innerProvider.LiveItems.Add(CreateLine("workflow-a", "a")); + innerProvider.LiveItems.Add(CreateLine("workflow-b", "b")); + + await using var serviceProvider = new ServiceCollection() + .AddLogging() + .AddSingleton(innerProvider) + .AddConsoleLogsServices() + .BuildServiceProvider(); + var provider = serviceProvider.GetRequiredService(); + + var lines = await provider.SubscribeAsync(new() + { + Metadata = new Dictionary + { + [ConsoleLogMetadataKeys.WorkflowInstanceId] = "workflow-b" + } + }).Where(x => x.Line != null).Select(x => x.Line!).ToListAsync(); + + var line = Assert.Single(lines); + Assert.Equal("b", line.Text); } private static void AssertConsoleLogPipelineContributors(IServiceProvider serviceProvider) @@ -141,22 +288,131 @@ public class ConsoleLogsRegistrationTests : IAsyncLifetime Assert.Contains(serviceProvider.GetServices(), x => x.GetType() == typeof(ConsoleLogActivityExecutionPipelineContributor)); } - private sealed class CustomProvider : IConsoleLogProvider + private static async Task AssertEventuallyAsync(Func assertion) { - public ValueTask PublishAsync(ConsoleLogStreaming.Core.Models.ConsoleLogLine line, CancellationToken cancellationToken = default) => ValueTask.CompletedTask; + var deadline = DateTimeOffset.UtcNow.AddSeconds(3); + Exception? lastException = null; - public ValueTask GetRecentAsync(ConsoleLogStreaming.Core.Models.ConsoleLogFilter filter, CancellationToken cancellationToken = default) => - ValueTask.FromResult(new ConsoleLogStreaming.Core.Models.RecentConsoleLogsResult()); - - public async IAsyncEnumerable SubscribeAsync( - ConsoleLogStreaming.Core.Models.ConsoleLogFilter filter, - [EnumeratorCancellation] CancellationToken cancellationToken = default) + while (DateTimeOffset.UtcNow < deadline) { - await Task.CompletedTask; - yield break; + try + { + await assertion(); + return; + } + catch (Xunit.Sdk.XunitException e) + { + lastException = e; + await Task.Delay(25); + } } - public ValueTask> ListSourcesAsync(CancellationToken cancellationToken = default) => - ValueTask.FromResult>([]); + if (lastException != null) + throw lastException; + } + + private static ConsoleLogLine CreateLine(string workflowInstanceId, string text) => new() + { + Text = text, + Source = new ConsoleLogSource { Id = "test-source" }, + Metadata = new Dictionary + { + [ConsoleLogMetadataKeys.WorkflowInstanceId] = workflowInstanceId + } + }; + + private sealed class RecordingConsoleLogProvider : IConsoleLogProvider + { + public ConsoleLogLine? PublishedLine { get; private set; } + + public ValueTask PublishAsync(ConsoleLogLine line, CancellationToken cancellationToken = default) + { + PublishedLine = line; + return ValueTask.CompletedTask; + } + + public ValueTask GetRecentAsync(ConsoleLogFilter filter, CancellationToken cancellationToken = default) + { + return ValueTask.FromResult(new RecentConsoleLogsResult()); + } + + public IAsyncEnumerable SubscribeAsync(ConsoleLogFilter filter, CancellationToken cancellationToken = default) + { + return AsyncEnumerable.Empty(); + } + + public ValueTask> ListSourcesAsync(CancellationToken cancellationToken = default) + { + return ValueTask.FromResult>([]); + } + } + + private sealed class MetadataIgnoringConsoleLogProvider : IConsoleLogProvider + { + public List RecentItems { get; } = []; + public List LiveItems { get; } = []; + + public ValueTask PublishAsync(ConsoleLogLine line, CancellationToken cancellationToken = default) + { + RecentItems.Add(line); + return ValueTask.CompletedTask; + } + + public ValueTask GetRecentAsync(ConsoleLogFilter filter, CancellationToken cancellationToken = default) + { + return ValueTask.FromResult(new RecentConsoleLogsResult { Items = RecentItems }); + } + + public async IAsyncEnumerable SubscribeAsync( + ConsoleLogFilter filter, + [EnumeratorCancellation] CancellationToken cancellationToken = default) + { + foreach (var line in LiveItems) + { + cancellationToken.ThrowIfCancellationRequested(); + yield return ConsoleLogStreamingItem.FromLine(line); + await Task.Yield(); + } + } + + public ValueTask> ListSourcesAsync(CancellationToken cancellationToken = default) + { + return ValueTask.FromResult>([]); + } + } + + private sealed class MetadataDroppingConsoleLogProvider : IConsoleLogProvider + { + public List PublishedLines { get; } = []; + + public ValueTask PublishAsync(ConsoleLogLine line, CancellationToken cancellationToken = default) + { + PublishedLines.Add(line with { Metadata = new Dictionary() }); + return ValueTask.CompletedTask; + } + + public ValueTask GetRecentAsync(ConsoleLogFilter filter, CancellationToken cancellationToken = default) + { + return ValueTask.FromResult(new RecentConsoleLogsResult { Items = PublishedLines }); + } + + public IAsyncEnumerable SubscribeAsync(ConsoleLogFilter filter, CancellationToken cancellationToken = default) + { + return AsyncEnumerable.Empty(); + } + + public ValueTask> ListSourcesAsync(CancellationToken cancellationToken = default) + { + return ValueTask.FromResult>([]); + } + } + + private sealed class NoopDrainExtensionHandle : IDrainExtensionHandle + { + public bool TryExtend(TimeSpan requestedExtension, out TimeSpan grantedExtension) + { + grantedExtension = TimeSpan.Zero; + return false; + } } } diff --git a/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/Elsa.Diagnostics.ConsoleLogs.UnitTests.csproj b/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/Elsa.Diagnostics.ConsoleLogs.UnitTests.csproj index 17fe4f464..b21be7aa8 100644 --- a/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/Elsa.Diagnostics.ConsoleLogs.UnitTests.csproj +++ b/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/Elsa.Diagnostics.ConsoleLogs.UnitTests.csproj @@ -6,6 +6,7 @@ + diff --git a/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/ElsaConsoleLogSubscriptionManagerTests.cs b/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/ElsaConsoleLogSubscriptionManagerTests.cs new file mode 100644 index 000000000..2ede75203 --- /dev/null +++ b/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/ElsaConsoleLogSubscriptionManagerTests.cs @@ -0,0 +1,175 @@ +using ConsoleLogStreaming.Core; +using ConsoleLogStreaming.Core.Models; +using Elsa.Diagnostics.ConsoleLogs.RealTime; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Elsa.Diagnostics.ConsoleLogs.UnitTests; + +public class ElsaConsoleLogSubscriptionManagerTests +{ + [Fact] + public async Task SubscribeAsync_DoesNotSendSourceChangedForRepeatedSource() + { + var source = new ConsoleLogSource + { + Id = "source-1", + DisplayName = "Source 1", + ServiceName = "service", + MachineName = "machine", + Health = ConsoleLogSourceHealth.Connected + }; + var provider = new StreamingConsoleLogProvider( + ConsoleLogStreamingItem.FromLine(CreateLine(source, "first")), + ConsoleLogStreamingItem.FromLine(CreateLine(source, "second"))); + var client = new RecordingConsoleLogsClient(); + var hubContext = new TestHubContext(client); + using var manager = new ElsaConsoleLogSubscriptionManager(provider, new TestConsoleLogSourceRegistry(), hubContext, NullLogger.Instance); + + await manager.SubscribeAsync("connection-1", new(), CancellationToken.None); + + await AssertEventuallyAsync(() => + { + Assert.Equal(2, client.Lines.Count); + Assert.Single(client.Sources); + }); + } + + private static ConsoleLogLine CreateLine(ConsoleLogSource source, string text) => new() + { + Text = text, + Source = source + }; + + private static async Task AssertEventuallyAsync(Action assertion) + { + Xunit.Sdk.XunitException? lastException = null; + + for (var i = 0; i < 40; i++) + { + try + { + assertion(); + return; + } + catch (Xunit.Sdk.XunitException e) + { + lastException = e; + await Task.Delay(25); + } + } + + if (lastException != null) + throw lastException; + } + + private sealed class StreamingConsoleLogProvider(params ConsoleLogStreamingItem[] items) : IConsoleLogProvider + { + public ValueTask PublishAsync(ConsoleLogLine line, CancellationToken cancellationToken = default) + { + return ValueTask.CompletedTask; + } + + public ValueTask GetRecentAsync(ConsoleLogFilter filter, CancellationToken cancellationToken = default) + { + return ValueTask.FromResult(new RecentConsoleLogsResult()); + } + + public async IAsyncEnumerable SubscribeAsync(ConsoleLogFilter filter, [EnumeratorCancellation] CancellationToken cancellationToken = default) + { + foreach (var item in items) + { + cancellationToken.ThrowIfCancellationRequested(); + yield return item; + await Task.Yield(); + } + } + + public ValueTask> ListSourcesAsync(CancellationToken cancellationToken = default) + { + return ValueTask.FromResult>([]); + } + } + + private sealed class TestConsoleLogSourceRegistry : IConsoleLogSourceRegistry + { + public event Action? SourceChanged; + + public ConsoleLogSource Current { get; private set; } = new() { Id = "test-source" }; + + public ConsoleLogSource MarkSeen(ConsoleLogSource source, DateTimeOffset timestamp) + { + Current = source; + SourceChanged?.Invoke(source); + return source; + } + + public IReadOnlyCollection List() + { + return [Current]; + } + } + + private sealed class RecordingConsoleLogsClient : IElsaConsoleLogsClient + { + public List Lines { get; } = []; + public List Sources { get; } = []; + + public Task ReceiveConsoleLogLineAsync(ConsoleLogLine line, CancellationToken cancellationToken = default) + { + Lines.Add(line); + return Task.CompletedTask; + } + + public Task ReceiveDroppedLinesAsync(ConsoleLogDroppedSummary summary, CancellationToken cancellationToken = default) + { + return Task.CompletedTask; + } + + public Task ReceiveSourceChangedAsync(ConsoleLogSource source, CancellationToken cancellationToken = default) + { + Sources.Add(source); + return Task.CompletedTask; + } + } + + private sealed class TestHubContext(IElsaConsoleLogsClient client) : IHubContext + { + public IHubClients Clients { get; } = new TestHubClients(client); + public IGroupManager Groups { get; } = new TestGroupManager(); + } + + private sealed class TestHubClients(IElsaConsoleLogsClient client) : IHubClients + { + public IElsaConsoleLogsClient All => client; + + public IElsaConsoleLogsClient AllExcept(IReadOnlyList excludedConnectionIds) => client; + + public IElsaConsoleLogsClient Client(string connectionId) => client; + + public IElsaConsoleLogsClient Clients(IReadOnlyList connectionIds) => client; + + public IElsaConsoleLogsClient Group(string groupName) => client; + + public IElsaConsoleLogsClient GroupExcept(string groupName, IReadOnlyList excludedConnectionIds) => client; + + public IElsaConsoleLogsClient Groups(IReadOnlyList groupNames) => client; + + public IElsaConsoleLogsClient User(string userId) => client; + + public IElsaConsoleLogsClient Users(IReadOnlyList userIds) => client; + } + + private sealed class TestGroupManager : IGroupManager + { + public Task AddToGroupAsync(string connectionId, string groupName, CancellationToken cancellationToken = default) + { + return Task.CompletedTask; + } + + public Task RemoveFromGroupAsync(string connectionId, string groupName, CancellationToken cancellationToken = default) + { + return Task.CompletedTask; + } + } +} diff --git a/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/RecentConsoleLogsEndpointTests.cs b/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/RecentConsoleLogsEndpointTests.cs new file mode 100644 index 000000000..064c9f793 --- /dev/null +++ b/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/RecentConsoleLogsEndpointTests.cs @@ -0,0 +1,16 @@ +using System.Text; +using System.Text.Json; +using Elsa.Diagnostics.ConsoleLogs.Endpoints.ConsoleLogs.Recent; + +namespace Elsa.Diagnostics.ConsoleLogs.UnitTests; + +public class RecentConsoleLogsEndpointTests +{ + [Fact] + public async Task DeserializeJsonBodyAsync_WhenJsonIsMalformed_ThrowsJsonException() + { + await using var body = new MemoryStream(Encoding.UTF8.GetBytes("{")); + + await Assert.ThrowsAsync(async () => await Endpoint.DeserializeJsonBodyAsync(body, CancellationToken.None)); + } +} diff --git a/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/Usings.cs b/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/Usings.cs index fd1941521..8457b59a5 100644 --- a/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/Usings.cs +++ b/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/Usings.cs @@ -1,4 +1,4 @@ global using System.Runtime.CompilerServices; -global using ConsoleLogStreaming.Contracts; +global using ConsoleLogStreaming.Core.Models; global using Microsoft.Extensions.Options; global using Xunit; diff --git a/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Elsa.Diagnostics.OpenTelemetry.UnitTests.csproj b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Elsa.Diagnostics.OpenTelemetry.UnitTests.csproj new file mode 100644 index 000000000..4c9e11f6b --- /dev/null +++ b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Elsa.Diagnostics.OpenTelemetry.UnitTests.csproj @@ -0,0 +1,12 @@ + + + + [Elsa.Diagnostics.OpenTelemetry]* + 0 + + + + + + + diff --git a/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/InMemory/RingBufferTests.cs b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/InMemory/RingBufferTests.cs new file mode 100644 index 000000000..3ec14fc7a --- /dev/null +++ b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/InMemory/RingBufferTests.cs @@ -0,0 +1,20 @@ +using Elsa.Diagnostics.OpenTelemetry.Providers.InMemory; + +namespace Elsa.Diagnostics.OpenTelemetry.UnitTests.InMemory; + +public class RingBufferTests +{ + [Fact] + public void Add_WhenCapacityIsExceeded_DropsOldestItems() + { + var buffer = new RingBuffer(3); + + buffer.Add(1); + buffer.Add(2); + buffer.Add(3); + buffer.Add(4); + + Assert.Equal([2, 3, 4], buffer.Snapshot()); + Assert.Equal(1, buffer.DroppedCount); + } +} diff --git a/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Ingestion/OtlpHttpProtobufParserTests.cs b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Ingestion/OtlpHttpProtobufParserTests.cs new file mode 100644 index 000000000..1d796473f --- /dev/null +++ b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Ingestion/OtlpHttpProtobufParserTests.cs @@ -0,0 +1,142 @@ +using System.Buffers.Binary; +using System.Text; +using Elsa.Diagnostics.OpenTelemetry.Ingestion.HttpProtobuf; +using Elsa.Diagnostics.OpenTelemetry.Models; + +namespace Elsa.Diagnostics.OpenTelemetry.UnitTests.Ingestion; + +public class OtlpHttpProtobufParserTests +{ + private static readonly byte[] TraceId = Convert.FromHexString("00112233445566778899aabbccddeeff"); + private static readonly byte[] SpanId = Convert.FromHexString("0011223344556677"); + private static readonly DateTimeOffset Timestamp = new(2026, 5, 26, 10, 0, 0, TimeSpan.Zero); + + [Fact(DisplayName = "OTLP trace payload is normalized to trace, span, resource, and workflow metadata")] + public void ParseTraces() + { + var payload = Message(1, + Join(Message(1, Resource()), + Message(2, Message(2, + Join(Bytes(1, TraceId), + Bytes(2, SpanId), + String(5, "Workflow/Approve"), + Varint(6, 1), + Varint(7, UnixNanos(Timestamp)), + Varint(8, UnixNanos(Timestamp.AddMilliseconds(25))), + Message(9, KeyValue("workflow.instance.id", "wf-1")), + Message(15, Varint(3, 2))))))); + + var batch = OtlpHttpProtobufParser.ParseTraces(payload); + var span = Assert.Single(batch.Spans); + var trace = Assert.Single(batch.Traces); + + Assert.Equal("elsa-server:node-1", span.ResourceId); + Assert.Equal("00112233445566778899aabbccddeeff", trace.TraceId); + Assert.Equal("0011223344556677", trace.RootSpanId); + Assert.Equal("wf-1", Assert.Single(trace.WorkflowInstanceIds)); + Assert.Equal(SpanStatus.Error, trace.Status); + } + + [Fact(DisplayName = "OTLP metric payload is normalized to metric instruments and points")] + public void ParseMetrics() + { + var point = + Join(Varint(3, UnixNanos(Timestamp)), + Fixed64(4, 42.5), + Message(7, KeyValue("workflow.definition.id", "orders"))); + var metric = + Join(String(1, "workflow.duration"), + String(2, "Workflow duration"), + String(3, "ms"), + Message(5, Message(1, point))); + var payload = Message(1, Join(Message(1, Resource()), Message(2, Message(2, metric)))); + + var batch = OtlpHttpProtobufParser.ParseMetrics(payload); + var instrument = Assert.Single(batch.Instruments); + var metricPoint = Assert.Single(batch.MetricPoints); + + Assert.Equal("workflow.duration", instrument.Name); + Assert.Equal("workflow.duration", metricPoint.InstrumentName); + Assert.Equal(MetricKind.Gauge, instrument.Kind); + Assert.Equal(42.5, metricPoint.Value); + Assert.Equal("orders", metricPoint.Attributes["workflow.definition.id"]); + } + + [Fact(DisplayName = "OTLP log payload is normalized to correlated OTLP log records")] + public void ParseLogs() + { + var log = + Join(Varint(1, UnixNanos(Timestamp)), + Varint(2, 17), + String(3, "Error"), + Message(5, AnyString("boom")), + Bytes(9, TraceId), + Bytes(10, SpanId), + Message(6, KeyValue("workflow.instance.id", "wf-1"))); + var payload = Message(1, Join(Message(1, Resource()), Message(2, Message(2, log)))); + + var batch = OtlpHttpProtobufParser.ParseLogs(payload); + var record = Assert.Single(batch.Logs); + + Assert.Equal("elsa-server:node-1", record.ResourceId); + Assert.Equal("Error", record.SeverityText); + Assert.Equal("boom", record.Body); + Assert.Equal("00112233445566778899aabbccddeeff", record.TraceId); + Assert.Equal("0011223344556677", record.SpanId); + } + + private static byte[] Resource() + { + return Join( + Message(1, KeyValue("service.name", "elsa-server")), + Message(1, KeyValue("service.instance.id", "node-1")), + Message(1, KeyValue("telemetry.sdk.language", "dotnet"))); + } + + private static byte[] KeyValue(string key, string value) => Join(String(1, key), Message(2, AnyString(value))); + + private static byte[] AnyString(string value) => String(1, value); + + private static byte[] Message(int fieldNumber, byte[] value) => Join(Varint((ulong)((fieldNumber << 3) | 2)), Varint((ulong)value.Length), value); + + private static byte[] String(int fieldNumber, string value) => Message(fieldNumber, Encoding.UTF8.GetBytes(value)); + + private static byte[] Bytes(int fieldNumber, byte[] value) => Message(fieldNumber, value); + + private static byte[] Varint(int fieldNumber, ulong value) => Join(Varint((ulong)(fieldNumber << 3)), Varint(value)); + + private static byte[] Fixed64(int fieldNumber, double value) + { + var bytes = new byte[9]; + bytes[0] = (byte)((fieldNumber << 3) | 1); + BinaryPrimitives.WriteUInt64LittleEndian(bytes.AsSpan(1), (ulong)BitConverter.DoubleToInt64Bits(value)); + return bytes; + } + + private static byte[] Varint(ulong value) + { + var bytes = new List(); + while (value >= 0x80) + { + bytes.Add((byte)(value | 0x80)); + value >>= 7; + } + bytes.Add((byte)value); + return bytes.ToArray(); + } + + private static ulong UnixNanos(DateTimeOffset timestamp) => (ulong)(timestamp - DateTimeOffset.UnixEpoch).Ticks * 100; + + private static byte[] Join(params byte[][] segments) + { + var result = new byte[segments.Sum(x => x.Length)]; + var offset = 0; + foreach (var segment in segments) + { + segment.CopyTo(result, offset); + offset += segment.Length; + } + + return result; + } +} diff --git a/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Ingestion/OtlpIngestionSecurityTests.cs b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Ingestion/OtlpIngestionSecurityTests.cs new file mode 100644 index 000000000..4ebee00f4 --- /dev/null +++ b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Ingestion/OtlpIngestionSecurityTests.cs @@ -0,0 +1,68 @@ +using System.Net; +using Elsa.Diagnostics.OpenTelemetry.Ingestion; +using Elsa.Diagnostics.OpenTelemetry.Options; +using Microsoft.AspNetCore.Http; + +namespace Elsa.Diagnostics.OpenTelemetry.UnitTests.Ingestion; + +public class OtlpIngestionSecurityTests +{ + [Fact(DisplayName = "Loopback ingestion is allowed without API key in development mode")] + public void AllowsLoopbackWithoutApiKey() + { + var context = CreateContext(IPAddress.Loopback); + + var authorized = OtlpIngestionSecurity.IsAuthorized(context, new OpenTelemetryDiagnosticsOptions()); + + Assert.True(authorized); + } + + [Fact(DisplayName = "Non-loopback ingestion is rejected without API key")] + public void RejectsNonLoopbackWithoutApiKey() + { + var context = CreateContext(IPAddress.Parse("10.0.0.5")); + + var authorized = OtlpIngestionSecurity.IsAuthorized(context, new OpenTelemetryDiagnosticsOptions()); + + Assert.False(authorized); + } + + [Fact(DisplayName = "Missing remote address is rejected without API key")] + public void RejectsMissingRemoteAddressWithoutApiKey() + { + var context = CreateContext(null); + + var authorized = OtlpIngestionSecurity.IsAuthorized(context, new OpenTelemetryDiagnosticsOptions()); + + Assert.False(authorized); + } + + [Fact(DisplayName = "Configured API key header authorizes ingestion")] + public void AllowsConfiguredApiKey() + { + var context = CreateContext(IPAddress.Parse("10.0.0.5")); + context.Request.Headers["x-otlp-api-key"] = "secret"; + + var authorized = OtlpIngestionSecurity.IsAuthorized(context, new OpenTelemetryDiagnosticsOptions { ApiKey = "secret" }); + + Assert.True(authorized); + } + + [Fact(DisplayName = "Incorrect API key header rejects ingestion")] + public void RejectsIncorrectConfiguredApiKey() + { + var context = CreateContext(IPAddress.Parse("10.0.0.5")); + context.Request.Headers["x-otlp-api-key"] = "not-secret"; + + var authorized = OtlpIngestionSecurity.IsAuthorized(context, new OpenTelemetryDiagnosticsOptions { ApiKey = "secret" }); + + Assert.False(authorized); + } + + private static DefaultHttpContext CreateContext(IPAddress? remoteAddress) + { + var context = new DefaultHttpContext(); + context.Connection.RemoteIpAddress = remoteAddress; + return context; + } +} diff --git a/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/InMemoryOpenTelemetryStoreTests.cs b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/InMemoryOpenTelemetryStoreTests.cs new file mode 100644 index 000000000..52087d27a --- /dev/null +++ b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/InMemoryOpenTelemetryStoreTests.cs @@ -0,0 +1,110 @@ +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Options; + +namespace Elsa.Diagnostics.OpenTelemetry.UnitTests.Providers; + +public class InMemoryOpenTelemetryStoreTests +{ + [Fact] + public async Task WriteAsync_WhenTraceCapacityIsExceeded_DropsOldestTraceAndReportsCount() + { + var context = new OpenTelemetryStoreTestContext(new OpenTelemetryDiagnosticsOptions + { + TraceCapacity = 2, + SpanCapacity = 10, + MetricPointCapacity = 10, + LogRecordCapacity = 10 + }); + var resource = context.Resource("resource-a", "api"); + + await context.WriteAsync(new OpenTelemetryBatch([resource], [context.Trace("trace-1", resource.Id, context.Now.AddSeconds(1))], [], [], [], [])); + await context.WriteAsync(new OpenTelemetryBatch([], [context.Trace("trace-2", resource.Id, context.Now.AddSeconds(2))], [], [], [], [])); + await context.WriteAsync(new OpenTelemetryBatch([], [context.Trace("trace-3", resource.Id, context.Now.AddSeconds(3))], [], [], [], [])); + + var result = await context.Store.QueryTracesAsync(new OpenTelemetryTraceFilter { Take = 10 }); + var diagnostics = await context.Store.GetDiagnosticsAsync(); + + Assert.Equal(["trace-2", "trace-3"], result.Items.Select(x => x.TraceId)); + Assert.Equal(1, result.DroppedCount); + Assert.Equal(1, diagnostics.DroppedTraceCount); + Assert.Equal(2, diagnostics.TraceCount); + } + + [Fact] + public async Task QueryResourcesAsync_WhenTakeExceedsMaxQuerySize_ClampsResult() + { + var context = new OpenTelemetryStoreTestContext(new OpenTelemetryDiagnosticsOptions { MaxQuerySize = 1 }); + + await context.WriteAsync(new OpenTelemetryBatch([context.Resource("resource-a", "api"), context.Resource("resource-b", "worker")], [], [], [], [], [])); + + var result = await context.Store.QueryResourcesAsync(new OpenTelemetryResourceFilter { Take = 10 }); + + Assert.Single(result.Items); + } + + [Fact] + public async Task QueryTracesAsync_WhenTraceIdAppearsInMultipleBatches_ReturnsLatestTrace() + { + var context = new OpenTelemetryStoreTestContext(new OpenTelemetryDiagnosticsOptions { TraceCapacity = 10 }); + var resource = context.Resource("resource-a", "api"); + + await context.WriteAsync(new OpenTelemetryBatch([resource], [context.Trace("trace-1", resource.Id, context.Now.AddSeconds(1))], [], [], [], [])); + await context.WriteAsync(new OpenTelemetryBatch([], [context.Trace("trace-1", resource.Id, context.Now.AddSeconds(2))], [], [], [], [])); + + var result = await context.Store.QueryTracesAsync(new OpenTelemetryTraceFilter { Take = 10 }); + + var trace = Assert.Single(result.Items); + Assert.Equal(context.Now.AddSeconds(2), trace.StartTime); + } + + [Fact] + public async Task WriteAsync_WhenResourceCapacityIsExceeded_DropsOldestResource() + { + var context = new OpenTelemetryStoreTestContext(new OpenTelemetryDiagnosticsOptions { ResourceCapacity = 2 }); + + await context.WriteAsync(new OpenTelemetryBatch( + [ + context.Resource("resource-a", "api", context.Now.AddSeconds(1)), + context.Resource("resource-b", "worker", context.Now.AddSeconds(2)), + context.Resource("resource-c", "jobs", context.Now.AddSeconds(3)) + ], + [], [], [], [], [])); + + var result = await context.Store.QueryResourcesAsync(new OpenTelemetryResourceFilter { Take = 10 }); + + Assert.Equal(["resource-c", "resource-b"], result.Items.Select(x => x.Id)); + Assert.Equal(1, result.DroppedCount); + } + + [Fact] + public async Task Constructor_WhenCapacitiesAreMisconfigured_ClampsToMinimumCapacity() + { + var context = new OpenTelemetryStoreTestContext(new OpenTelemetryDiagnosticsOptions + { + TraceCapacity = 0, + SpanCapacity = 0, + MetricPointCapacity = 0, + LogRecordCapacity = 0 + }); + var resource = context.Resource("resource-a", "api"); + + await context.WriteAsync(new OpenTelemetryBatch( + [resource], + [context.Trace("trace-1", resource.Id)], + [context.Span("span-1", "trace-1", "span-1", resource.Id)], + [context.Instrument("instrument-1", resource.Id, "metric")], + [context.Point("point-1", "instrument-1", resource.Id)], + [context.Log("log-1", resource.Id, "trace-1")])); + + var diagnostics = await context.Store.GetDiagnosticsAsync(); + + Assert.Equal(1, diagnostics.TraceCount); + Assert.Equal(1, diagnostics.SpanCount); + Assert.Equal(1, diagnostics.MetricPointCount); + Assert.Equal(1, diagnostics.LogRecordCount); + Assert.Equal(1, diagnostics.TraceCapacity); + Assert.Equal(1, diagnostics.SpanCapacity); + Assert.Equal(1, diagnostics.MetricPointCapacity); + Assert.Equal(1, diagnostics.LogRecordCapacity); + } +} diff --git a/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/OpenTelemetryMetricQueryTests.cs b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/OpenTelemetryMetricQueryTests.cs new file mode 100644 index 000000000..2787c6978 --- /dev/null +++ b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/OpenTelemetryMetricQueryTests.cs @@ -0,0 +1,45 @@ +using Elsa.Diagnostics.OpenTelemetry.Models; + +namespace Elsa.Diagnostics.OpenTelemetry.UnitTests.Providers; + +public class OpenTelemetryMetricQueryTests +{ + [Fact] + public async Task QueryMetricsAsync_WhenFilteringByInstrumentName_ReturnsMatchingInstrumentPoints() + { + var context = new OpenTelemetryStoreTestContext(); + var resource = context.Resource("resource-api", "api"); + var duration = context.Instrument("instrument-duration", resource.Id, "workflow.duration"); + var count = context.Instrument("instrument-count", resource.Id, "workflow.count"); + await context.WriteAsync(new OpenTelemetryBatch([resource], [], [], [duration, count], [context.Point("point-1", duration.Id, resource.Id), context.Point("point-2", count.Id, resource.Id)], [])); + + var result = await context.Store.QueryMetricsAsync(new OpenTelemetryMetricFilter { InstrumentName = "duration" }); + + Assert.Equal(duration.Id, Assert.Single(result.Instruments).Id); + Assert.Equal("point-1", Assert.Single(result.Points).Id); + } + + [Fact] + public async Task QueryMetricsAsync_WhenFilteringByInstrumentName_AppliesInstrumentFilterBeforeTake() + { + var context = new OpenTelemetryStoreTestContext(); + var resource = context.Resource("resource-api", "api"); + var duration = context.Instrument("instrument-duration", resource.Id, "workflow.duration"); + var count = context.Instrument("instrument-count", resource.Id, "workflow.count"); + await context.WriteAsync(new OpenTelemetryBatch( + [resource], + [], + [], + [duration, count], + [ + context.Point("point-1", duration.Id, resource.Id, context.Now), + context.Point("point-2", count.Id, resource.Id, context.Now.AddSeconds(1)) + ], + [])); + + var result = await context.Store.QueryMetricsAsync(new OpenTelemetryMetricFilter { InstrumentName = "duration", Take = 1 }); + + Assert.Equal(duration.Id, Assert.Single(result.Instruments).Id); + Assert.Equal("point-1", Assert.Single(result.Points).Id); + } +} diff --git a/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/OpenTelemetryStoreTestContext.cs b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/OpenTelemetryStoreTestContext.cs new file mode 100644 index 000000000..998bf2595 --- /dev/null +++ b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/OpenTelemetryStoreTestContext.cs @@ -0,0 +1,59 @@ +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Options; +using Elsa.Diagnostics.OpenTelemetry.Providers.InMemory; +using Elsa.Diagnostics.OpenTelemetry.Services; +using OptionsFactory = Microsoft.Extensions.Options.Options; + +namespace Elsa.Diagnostics.OpenTelemetry.UnitTests.Providers; + +public class OpenTelemetryStoreTestContext +{ + public OpenTelemetryStoreTestContext(OpenTelemetryDiagnosticsOptions? options = null) + { + Options = options ?? new OpenTelemetryDiagnosticsOptions(); + SourceRegistry = new OpenTelemetrySourceRegistry(OptionsFactory.Create(Options)); + Store = new InMemoryOpenTelemetryStore(OptionsFactory.Create(Options), SourceRegistry); + } + + public OpenTelemetryDiagnosticsOptions Options { get; } + public OpenTelemetrySourceRegistry SourceRegistry { get; } + public InMemoryOpenTelemetryStore Store { get; } + public DateTimeOffset Now { get; } = new(2026, 5, 26, 10, 0, 0, TimeSpan.Zero); + + public async Task WriteAsync(OpenTelemetryBatch batch) + { + await Store.WriteAsync(batch); + } + + public TelemetryResource Resource(string id, string serviceName, DateTimeOffset? lastSeen = null, TelemetryResourceStatus status = TelemetryResourceStatus.Active) + { + return new(id, serviceName, $"{id}-instance", "dotnet", new Dictionary(), lastSeen ?? Now, status); + } + + public TelemetryTrace Trace(string traceId, string resourceId, DateTimeOffset? startTime = null, SpanStatus status = SpanStatus.Ok, params string[] workflowInstanceIds) + { + var start = startTime ?? Now; + return new(traceId, $"{traceId}-root", $"trace-{traceId}", start, start.AddMilliseconds(25), TimeSpan.FromMilliseconds(25), status, [resourceId], workflowInstanceIds, 2); + } + + public TelemetrySpan Span(string id, string traceId, string spanId, string resourceId, DateTimeOffset? startTime = null) + { + var start = startTime ?? Now; + return new(id, traceId, spanId, null, resourceId, $"span-{spanId}", "internal", start, start.AddMilliseconds(10), SpanStatus.Ok, null, new Dictionary(), [], []); + } + + public MetricInstrument Instrument(string id, string resourceId, string name) + { + return new(id, resourceId, name, "ms", null, MetricKind.Gauge, new Dictionary()); + } + + public MetricPoint Point(string id, string instrumentId, string resourceId, DateTimeOffset? timestamp = null) + { + return new(id, instrumentId, instrumentId, resourceId, timestamp ?? Now, 42, null, null, new Dictionary(), null, null); + } + + public OtlpLogRecord Log(string id, string resourceId, string traceId, string severity = "Information", string body = "message") + { + return new(id, resourceId, Now, severity, null, body, traceId, $"{traceId}-span", new Dictionary()); + } +} diff --git a/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/OpenTelemetryTraceQueryTests.cs b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/OpenTelemetryTraceQueryTests.cs new file mode 100644 index 000000000..ac2154d66 --- /dev/null +++ b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/OpenTelemetryTraceQueryTests.cs @@ -0,0 +1,38 @@ +using Elsa.Diagnostics.OpenTelemetry.Models; + +namespace Elsa.Diagnostics.OpenTelemetry.UnitTests.Providers; + +public class OpenTelemetryTraceQueryTests +{ + [Fact] + public async Task QueryTracesAsync_WhenFilteringByServiceName_ReturnsMatchingResourceTraces() + { + var context = new OpenTelemetryStoreTestContext(); + var api = context.Resource("resource-api", "api"); + var worker = context.Resource("resource-worker", "worker"); + await context.WriteAsync(new OpenTelemetryBatch([api, worker], [context.Trace("trace-api", api.Id), context.Trace("trace-worker", worker.Id)], [], [], [], [])); + + var result = await context.Store.QueryTracesAsync(new OpenTelemetryTraceFilter { ServiceName = "api" }); + + Assert.Equal("trace-api", Assert.Single(result.Items).TraceId); + } + + [Fact] + public async Task GetTraceAsync_ReturnsOrderedSpansResourcesAndTraceLogs() + { + var context = new OpenTelemetryStoreTestContext(); + var resource = context.Resource("resource-api", "api"); + var trace = context.Trace("trace-1", resource.Id); + var laterSpan = context.Span("span-record-2", trace.TraceId, "span-2", resource.Id, context.Now.AddSeconds(2)); + var earlierSpan = context.Span("span-record-1", trace.TraceId, "span-1", resource.Id, context.Now.AddSeconds(1)); + var log = context.Log("log-1", resource.Id, trace.TraceId); + await context.WriteAsync(new OpenTelemetryBatch([resource], [trace], [laterSpan, earlierSpan], [], [], [log])); + + var detail = await context.Store.GetTraceAsync(trace.TraceId); + + Assert.NotNull(detail); + Assert.Equal(["span-1", "span-2"], detail.Spans.Select(x => x.SpanId)); + Assert.Equal(resource.Id, Assert.Single(detail.Resources).Id); + Assert.Equal(log.Id, Assert.Single(detail.Logs).Id); + } +} diff --git a/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/OtlpLogQueryTests.cs b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/OtlpLogQueryTests.cs new file mode 100644 index 000000000..1328b85ab --- /dev/null +++ b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Providers/OtlpLogQueryTests.cs @@ -0,0 +1,28 @@ +using Elsa.Diagnostics.OpenTelemetry.Models; + +namespace Elsa.Diagnostics.OpenTelemetry.UnitTests.Providers; + +public class OtlpLogQueryTests +{ + [Fact] + public async Task QueryLogsAsync_WhenFilteringByTraceAndSeverity_ReturnsMatchingLogs() + { + var context = new OpenTelemetryStoreTestContext(); + var resource = context.Resource("resource-api", "api"); + await context.WriteAsync(new OpenTelemetryBatch( + [resource], + [], + [], + [], + [], + [ + context.Log("log-1", resource.Id, "trace-1", "Information"), + context.Log("log-2", resource.Id, "trace-1", "Error"), + context.Log("log-3", resource.Id, "trace-2", "Error") + ])); + + var result = await context.Store.QueryLogsAsync(new OpenTelemetryLogFilter { TraceId = "trace-1", Severity = "Error" }); + + Assert.Equal("log-2", Assert.Single(result.Items).Id); + } +} diff --git a/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Services/CollectorConfigurationTests.cs b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Services/CollectorConfigurationTests.cs new file mode 100644 index 000000000..2d171a761 --- /dev/null +++ b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Services/CollectorConfigurationTests.cs @@ -0,0 +1,41 @@ +using Elsa.Diagnostics.OpenTelemetry.Options; +using Elsa.Diagnostics.OpenTelemetry.Services; +using OptionsFactory = Microsoft.Extensions.Options.Options; + +namespace Elsa.Diagnostics.OpenTelemetry.UnitTests.Services; + +public class CollectorConfigurationTests +{ + [Fact] + public async Task GetAsync_WhenGrpcIsDisabled_ReturnsDisabledGrpcMetadataWithoutSecretValue() + { + var provider = new CollectorConfigurationProvider(OptionsFactory.Create(new OpenTelemetryDiagnosticsOptions + { + ApiKey = "secret-value", + EnableGrpc = false + })); + + var configuration = await provider.GetAsync(); + + Assert.True(configuration.Http.Enabled); + Assert.False(configuration.Grpc.Enabled); + Assert.Null(configuration.Grpc.Endpoint); + Assert.Equal("", configuration.RequiredHeaders["x-otlp-api-key"]); + } + + [Fact] + public async Task GetAsync_WhenGrpcIsEnabled_ReturnsConfiguredGrpcEndpoint() + { + var provider = new CollectorConfigurationProvider(OptionsFactory.Create(new OpenTelemetryDiagnosticsOptions + { + EnableGrpc = true, + GrpcEndpointPath = "https://localhost:4317" + })); + + var configuration = await provider.GetAsync(); + + Assert.True(configuration.Grpc.Enabled); + Assert.Equal("https://localhost:4317", configuration.Grpc.Endpoint); + Assert.Null(configuration.Grpc.DisabledReason); + } +} diff --git a/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Services/OpenTelemetryRedactorTests.cs b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Services/OpenTelemetryRedactorTests.cs new file mode 100644 index 000000000..b100324dd --- /dev/null +++ b/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Services/OpenTelemetryRedactorTests.cs @@ -0,0 +1,39 @@ +using Elsa.Diagnostics.OpenTelemetry.Models; +using Elsa.Diagnostics.OpenTelemetry.Options; +using Elsa.Diagnostics.OpenTelemetry.Services; +using OptionsFactory = Microsoft.Extensions.Options.Options; + +namespace Elsa.Diagnostics.OpenTelemetry.UnitTests.Services; + +public class OpenTelemetryRedactorTests +{ + [Fact] + public void Redact_WhenSensitiveAttributeNameExists_RedactsValue() + { + var redactor = new OpenTelemetryRedactor(OptionsFactory.Create(new OpenTelemetryDiagnosticsOptions())); + var log = new OtlpLogRecord("1", "resource", DateTimeOffset.UtcNow, "Information", null, "hello", null, null, new Dictionary { ["password"] = "secret" }); + var batch = new OpenTelemetryBatch([], [], [], [], [], [log]); + + var result = redactor.Redact(batch); + + Assert.Equal("[Redacted]", result.Logs.Single().Attributes["password"]); + } + + [Fact] + public void Redact_WhenAttributeKeysDifferOnlyByCase_UsesLastValue() + { + var redactor = new OpenTelemetryRedactor(OptionsFactory.Create(new OpenTelemetryDiagnosticsOptions())); + var log = new OtlpLogRecord("1", "resource", DateTimeOffset.UtcNow, "Information", null, "hello", null, null, new Dictionary + { + ["Password"] = "first", + ["password"] = "second" + }); + var batch = new OpenTelemetryBatch([], [], [], [], [], [log]); + + var result = redactor.Redact(batch); + + var attributes = result.Logs.Single().Attributes; + Assert.Single(attributes); + Assert.Equal("[Redacted]", attributes["Password"]); + } +} diff --git a/test/unit/Elsa.Http.UnitTests/RateLimiting/IngressRateLimitingTests.cs b/test/unit/Elsa.Http.UnitTests/RateLimiting/IngressRateLimitingTests.cs index 4bdffea11..ec5eb2d7c 100644 --- a/test/unit/Elsa.Http.UnitTests/RateLimiting/IngressRateLimitingTests.cs +++ b/test/unit/Elsa.Http.UnitTests/RateLimiting/IngressRateLimitingTests.cs @@ -314,11 +314,15 @@ public class IngressRateLimitingTests app => app.UseWorkflowsApiRateLimiting("elsa/api", PolicyName), options => AddFixedWindowLimiter(options, "other")); - app.Configure(); - await app.StartAsync(); - var client = app.GetTestClient(); + var exception = await Record.ExceptionAsync(async () => + { + app.Configure(); + await app.StartAsync(); + var client = app.GetTestClient(); + await client.GetAsync("/elsa/api/ping"); + }); - await Assert.ThrowsAsync(() => client.GetAsync("/elsa/api/ping")); + Assert.IsType(exception); } [Fact] diff --git a/test/unit/Elsa.Http.UnitTests/ShellFeatures/HttpFeatureTests.cs b/test/unit/Elsa.Http.UnitTests/ShellFeatures/HttpFeatureTests.cs deleted file mode 100644 index 2774848a7..000000000 --- a/test/unit/Elsa.Http.UnitTests/ShellFeatures/HttpFeatureTests.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Elsa.Expressions.Options; -using Elsa.Expressions.Services; -using Elsa.Http.Bookmarks; -using Elsa.Http.ShellFeatures; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; - -namespace Elsa.Http.UnitTests.ShellFeatures; - -public class HttpFeatureTests -{ - [Fact] - public void ConfigureServices_RegistersHttpTypeAliases() - { - var services = new ServiceCollection(); - var feature = new HttpFeature(); - - feature.ConfigureServices(services); - - using var serviceProvider = services.BuildServiceProvider(); - var expressionOptions = serviceProvider.GetRequiredService>(); - var registry = new WellKnownTypeRegistry(expressionOptions); - - Assert.True(registry.TryGetType(nameof(HttpEndpointBookmarkPayload), out var type)); - Assert.Equal(typeof(HttpEndpointBookmarkPayload), type); - Assert.True(registry.TryGetType(nameof(HttpRequestException), out var exceptionType)); - Assert.Equal(typeof(HttpRequestException), exceptionType); - } -} diff --git a/test/unit/Elsa.Mediator.UnitTests/BackgroundCommandProcessorTests.cs b/test/unit/Elsa.Mediator.UnitTests/BackgroundCommandProcessorTests.cs new file mode 100644 index 000000000..21680a41b --- /dev/null +++ b/test/unit/Elsa.Mediator.UnitTests/BackgroundCommandProcessorTests.cs @@ -0,0 +1,111 @@ +using Elsa.Mediator.Channels; +using Elsa.Mediator.CommandStrategies; +using Elsa.Mediator.Contexts; +using Elsa.Mediator.Contracts; +using Elsa.Mediator.Middleware.Command; +using Elsa.Mediator.Models; +using Elsa.Mediator.Options; +using Elsa.Mediator.Services; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Elsa.Mediator.UnitTests; + +public class BackgroundCommandProcessorTests +{ + [Fact] + public async Task ExecuteAsync_UsesQueuedContextStrategyAndCancellationToken() + { + var services = new ServiceCollection(); + services.AddSingleton(); + services.AddScoped(); + await using var serviceProvider = services.BuildServiceProvider(); + var channel = new CommandsChannel(); + var processor = new BackgroundCommandProcessor( + Microsoft.Extensions.Options.Options.Create(new MediatorOptions { CommandWorkerCount = 1 }), + channel, + serviceProvider.GetRequiredService(), + NullLogger.Instance); + using var processorCancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + using var commandCancellationTokenSource = new CancellationTokenSource(); + var runTask = processor.ExecuteAsync(processorCancellationTokenSource.Token); + var strategy = new TestCommandStrategy(); + var context = new CommandContext(new TestCommand(), strategy, typeof(Unit), new Dictionary(), serviceProvider, commandCancellationTokenSource.Token); + + await commandCancellationTokenSource.CancelAsync(); + await channel.Writer.WriteAsync(context, processorCancellationTokenSource.Token); + + var recorder = serviceProvider.GetRequiredService(); + var recordedCall = await recorder.WaitForCallAsync(processorCancellationTokenSource.Token); + await processorCancellationTokenSource.CancelAsync(); + await runTask; + + Assert.Same(strategy, recordedCall.Strategy); + Assert.True(recordedCall.CancellationToken.IsCancellationRequested); + } + + [Fact] + public async Task BackgroundStrategy_QueuesExecutableContext() + { + var services = new ServiceCollection(); + services.AddSingleton(); + await using var serviceProvider = services.BuildServiceProvider(); + var channel = serviceProvider.GetRequiredService(); + using var commandCancellationTokenSource = new CancellationTokenSource(); + var commandContext = new CommandContext(new TestCommand(), CommandStrategy.Background, typeof(Unit), new Dictionary(), serviceProvider, commandCancellationTokenSource.Token); + var strategyContext = new CommandStrategyContext(commandContext, new TestCommandHandler(), serviceProvider); + + await commandCancellationTokenSource.CancelAsync(); + await CommandStrategy.Background.ExecuteAsync(strategyContext); + + var queuedContext = await channel.Reader.ReadAsync(); + + Assert.Same(CommandStrategy.Default, queuedContext.CommandStrategy); + Assert.Same(commandContext.Command, queuedContext.Command); + Assert.Same(commandContext.Headers, queuedContext.Headers); + Assert.False(queuedContext.CancellationToken.IsCancellationRequested); + } + + private sealed class RecordingCommandSender(CommandSenderRecorder recorder) : ICommandSender + { + public Task SendAsync(ICommand command, CancellationToken cancellationToken = default) => throw new NotSupportedException(); + + public Task SendAsync(ICommand command, IDictionary headers, CancellationToken cancellationToken = default) => throw new NotSupportedException(); + + public Task SendAsync(ICommand command, ICommandStrategy? strategy, CancellationToken cancellationToken = default) => throw new NotSupportedException(); + + public Task SendAsync(ICommand command, ICommandStrategy? strategy, IDictionary headers, CancellationToken cancellationToken = default) => throw new NotSupportedException(); + + public Task SendAsync(ICommand command, CancellationToken cancellationToken = default) => throw new NotSupportedException(); + + public Task SendAsync(ICommand command, ICommandStrategy? strategy, CancellationToken cancellationToken = default) => throw new NotSupportedException(); + + public Task SendAsync(ICommand command, ICommandStrategy? strategy, IDictionary headers, CancellationToken cancellationToken = default) + { + recorder.Record(new(strategy, cancellationToken)); + return Task.CompletedTask; + } + } + + private sealed class CommandSenderRecorder + { + private readonly TaskCompletionSource _completed = new(TaskCreationOptions.RunContinuationsAsynchronously); + + public void Record(RecordedCommandCall call) => _completed.TrySetResult(call); + + public Task WaitForCallAsync(CancellationToken cancellationToken) => _completed.Task.WaitAsync(cancellationToken); + } + + private sealed record RecordedCommandCall(ICommandStrategy? Strategy, CancellationToken CancellationToken); + + private sealed record TestCommand : ICommand; + + private sealed class TestCommandHandler : ICommandHandler + { + public Task HandleAsync(TestCommand command, CancellationToken cancellationToken) => Task.FromResult(Unit.Instance); + } + + private sealed class TestCommandStrategy : DefaultStrategy + { + } +} diff --git a/test/unit/Elsa.Mediator.UnitTests/BackgroundNotificationProcessorTests.cs b/test/unit/Elsa.Mediator.UnitTests/BackgroundNotificationProcessorTests.cs new file mode 100644 index 000000000..d1fe97828 --- /dev/null +++ b/test/unit/Elsa.Mediator.UnitTests/BackgroundNotificationProcessorTests.cs @@ -0,0 +1,145 @@ +using System.Collections.Concurrent; +using Elsa.Mediator.Channels; +using Elsa.Mediator.Contexts; +using Elsa.Mediator.Contracts; +using Elsa.Mediator.Middleware.Notification; +using Elsa.Mediator.Options; +using Elsa.Mediator.PublishingStrategies; +using Elsa.Mediator.Services; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Elsa.Mediator.UnitTests; + +public class BackgroundNotificationProcessorTests +{ + [Fact] + public async Task ExecuteAsync_CreatesIndependentScopePerWorker() + { + var services = new ServiceCollection(); + services.AddSingleton(); + services.AddScoped(); + services.AddScoped(); + await using var serviceProvider = services.BuildServiceProvider(); + var channel = new NotificationsChannel(); + var processor = new BackgroundNotificationProcessor( + Microsoft.Extensions.Options.Options.Create(new MediatorOptions { NotificationWorkerCount = 2 }), + channel, + serviceProvider.GetRequiredService(), + NullLogger.Instance); + using var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var runTask = processor.ExecuteAsync(cancellationTokenSource.Token); + var notificationStrategy = NotificationStrategy.Sequential; + + await channel.Writer.WriteAsync(new NotificationContext(new TestNotification(), notificationStrategy, serviceProvider), cancellationTokenSource.Token); + await channel.Writer.WriteAsync(new NotificationContext(new TestNotification(), notificationStrategy, serviceProvider), cancellationTokenSource.Token); + + var recorder = serviceProvider.GetRequiredService(); + await recorder.WaitForCallsAsync(2, cancellationTokenSource.Token); + await cancellationTokenSource.CancelAsync(); + await runTask; + + Assert.Equal(2, recorder.ScopeIds.Distinct().Count()); + } + + [Fact] + public async Task ExecuteAsync_UsesQueuedContextStrategy() + { + var services = new ServiceCollection(); + services.AddSingleton(); + services.AddScoped(); + services.AddScoped(); + await using var serviceProvider = services.BuildServiceProvider(); + var channel = new NotificationsChannel(); + var processor = new BackgroundNotificationProcessor( + Microsoft.Extensions.Options.Options.Create(new MediatorOptions { NotificationWorkerCount = 1 }), + channel, + serviceProvider.GetRequiredService(), + NullLogger.Instance); + using var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var runTask = processor.ExecuteAsync(cancellationTokenSource.Token); + var strategy = new TestNotificationStrategy(); + + await channel.Writer.WriteAsync(new NotificationContext(new TestNotification(), strategy, serviceProvider), cancellationTokenSource.Token); + + var recorder = serviceProvider.GetRequiredService(); + var recordedCall = await recorder.WaitForCallAsync(cancellationTokenSource.Token); + await cancellationTokenSource.CancelAsync(); + await runTask; + + Assert.Same(strategy, recordedCall.Strategy); + } + + [Fact] + public async Task BackgroundStrategy_QueuesExecutableContext() + { + var services = new ServiceCollection(); + services.AddSingleton(); + await using var serviceProvider = services.BuildServiceProvider(); + var channel = serviceProvider.GetRequiredService(); + var notificationContext = new NotificationContext(new TestNotification(), NotificationStrategy.Background, serviceProvider); + var strategyContext = new NotificationStrategyContext(notificationContext, [], NullLogger.Instance, serviceProvider); + + await NotificationStrategy.Background.PublishAsync(strategyContext); + + var queuedContext = await channel.Reader.ReadAsync(); + + Assert.Same(NotificationStrategy.Sequential, queuedContext.NotificationStrategy); + Assert.Same(notificationContext.Notification, queuedContext.Notification); + } + + private sealed class RecordingNotificationSender(WorkerScopeMarker scopeMarker, NotificationSenderRecorder recorder) : INotificationSender + { + public Task SendAsync(INotification notification, CancellationToken cancellationToken = default) + { + recorder.Record(scopeMarker.Id); + return Task.CompletedTask; + } + + public Task SendAsync(INotification notification, IEventPublishingStrategy? strategy, CancellationToken cancellationToken = default) + { + recorder.Record(scopeMarker.Id, strategy); + return Task.CompletedTask; + } + } + + private sealed class NotificationSenderRecorder + { + private int _callCount; + private readonly TaskCompletionSource _completed = new(TaskCreationOptions.RunContinuationsAsynchronously); + public ConcurrentBag ScopeIds { get; } = []; + private readonly TaskCompletionSource _firstCall = new(TaskCreationOptions.RunContinuationsAsynchronously); + + public void Record(Guid scopeId, IEventPublishingStrategy? strategy = null) + { + ScopeIds.Add(scopeId); + _firstCall.TrySetResult(new(strategy)); + + if (Interlocked.Increment(ref _callCount) == 2) + _completed.TrySetResult(); + } + + public async Task WaitForCallsAsync(int expectedCallCount, CancellationToken cancellationToken) + { + if (Volatile.Read(ref _callCount) >= expectedCallCount) + return; + + await _completed.Task.WaitAsync(cancellationToken); + } + + public Task WaitForCallAsync(CancellationToken cancellationToken) => _firstCall.Task.WaitAsync(cancellationToken); + } + + private sealed class WorkerScopeMarker + { + public Guid Id { get; } = Guid.NewGuid(); + } + + private sealed record TestNotification : INotification; + + private sealed record RecordedNotificationCall(IEventPublishingStrategy? Strategy); + + private sealed class TestNotificationStrategy : SequentialProcessingStrategy + { + } +} diff --git a/test/unit/Elsa.Secrets.UnitTests/SecretModelMapperTests.cs b/test/unit/Elsa.Secrets.UnitTests/SecretModelMapperTests.cs new file mode 100644 index 000000000..da588bfc6 --- /dev/null +++ b/test/unit/Elsa.Secrets.UnitTests/SecretModelMapperTests.cs @@ -0,0 +1,32 @@ +using Elsa.Secrets.Models; +using Elsa.Secrets.Services; +using Xunit; + +namespace Elsa.Secrets.UnitTests; + +public class SecretModelMapperTests +{ + [Fact] + public void ToModel_ReportsExpired_WhenActiveSecretHasOnlyExpiredVersions() + { + var secret = new Secret + { + Name = "smtp:password", + DisplayName = "SMTP password", + Versions = + { + new SecretVersion + { + Version = 1, + ExpiresAt = DateTimeOffset.UtcNow.AddMinutes(-1) + } + } + }; + + var model = secret.ToModel(); + + Assert.Equal(SecretStatus.Expired, model.Status); + Assert.Null(model.CurrentVersion); + Assert.Null(model.ExpiresAt); + } +} diff --git a/test/unit/Elsa.Secrets.UnitTests/SecretStoreTests.cs b/test/unit/Elsa.Secrets.UnitTests/SecretStoreTests.cs index fbcf9b67f..a4a00effe 100644 --- a/test/unit/Elsa.Secrets.UnitTests/SecretStoreTests.cs +++ b/test/unit/Elsa.Secrets.UnitTests/SecretStoreTests.cs @@ -40,6 +40,51 @@ public class SecretStoreTests Assert.Equal("configured-secret", value); } + [Fact] + public async Task ConfigurationStore_FallsBackToRootConfigurationKey() + { + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary { ["SmtpPassword"] = "root-configured-secret" }) + .Build(); + var fixture = new SecretTestFixture(configuration); + + var secret = await fixture.Manager.CreateAsync(new CreateSecretRequest + { + Name = "smtp:password", + StoreName = SecretStoreNames.Configuration, + ConfigurationKey = " SmtpPassword " + }); + var value = await fixture.Resolver.ResolveAsync("smtp:password"); + + Assert.Equal("root-configured-secret", value); + Assert.Null(secret.Versions.Single().Payload.Value); + Assert.Equal("SmtpPassword", secret.Versions.Single().Payload.Metadata["configurationKey"]); + } + + [Fact] + public async Task ConfigurationStore_RotateAsync_UsesReplacementConfigurationKey() + { + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + ["Elsa:Secrets:OldPassword"] = "old-configured-secret", + ["Elsa:Secrets:NewPassword"] = "new-configured-secret" + }) + .Build(); + var fixture = new SecretTestFixture(configuration); + + await fixture.Manager.CreateAsync(new CreateSecretRequest + { + Name = "smtp:password", + StoreName = SecretStoreNames.Configuration, + ConfigurationKey = "OldPassword" + }); + await fixture.Manager.RotateAsync("smtp:password", new RotateSecretRequest { ConfigurationKey = "NewPassword" }); + var value = await fixture.Resolver.ResolveAsync("smtp:password"); + + Assert.Equal("new-configured-secret", value); + } + [Fact] public async Task ConfigurationStore_TestAsync_ReturnsFalseWhenConfiguredValueIsMissing() { @@ -57,6 +102,18 @@ public class SecretStoreTests Assert.Equal("Secret value is unavailable.", result.Error); } + [Fact] + public void Registries_Throw_WhenTypeOrStoreIsMissing() + { + var fixture = new SecretTestFixture(); + + var missingType = Assert.Throws(() => fixture.TypeRegistry.Get("missing-type")); + var missingStore = Assert.Throws(() => fixture.StoreRegistry.Get("missing-store")); + + Assert.Contains("missing-type", missingType.Message); + Assert.Contains("missing-store", missingStore.Message); + } + [Fact] public async Task FileRepository_PersistsSecretAggregate() { diff --git a/test/unit/Elsa.Secrets.UnitTests/SecretValueProtectorTests.cs b/test/unit/Elsa.Secrets.UnitTests/SecretValueProtectorTests.cs new file mode 100644 index 000000000..47ec88f96 --- /dev/null +++ b/test/unit/Elsa.Secrets.UnitTests/SecretValueProtectorTests.cs @@ -0,0 +1,52 @@ +using Elsa.Secrets.Options; +using Elsa.Secrets.Services; +using Xunit; + +namespace Elsa.Secrets.UnitTests; + +public class SecretValueProtectorTests +{ + [Fact] + public void Protect_AndUnprotect_RoundTripsValue() + { + var protector = CreateProtector("0123456789abcdef0123456789abcdef"u8.ToArray()); + + var protectedValue = protector.Protect("plain-text-secret"); + var value = protector.Unprotect(protectedValue); + + Assert.NotEqual("plain-text-secret", protectedValue); + Assert.Equal("plain-text-secret", value); + } + + [Theory] + [InlineData(null)] + [InlineData(0)] + [InlineData(15)] + [InlineData(17)] + public void Protect_RejectsMissingOrInvalidEncryptionKey(int? keyLength) + { + var protector = CreateProtector(keyLength == null ? null : new byte[keyLength.Value]); + + var exception = Assert.Throws(() => protector.Protect("secret")); + + Assert.Contains("encryption key", exception.Message, StringComparison.OrdinalIgnoreCase); + } + + [Theory] + [InlineData("")] + [InlineData("v2.payload")] + [InlineData("v1.payload")] + public void Unprotect_RejectsUnsupportedPayloadFormat(string protectedValue) + { + var protector = CreateProtector("0123456789abcdef0123456789abcdef"u8.ToArray()); + + var exception = Assert.Throws(() => protector.Unprotect(protectedValue)); + + Assert.Contains("not supported", exception.Message, StringComparison.OrdinalIgnoreCase); + } + + private static DefaultSecretValueProtector CreateProtector(byte[]? key) + { + return new DefaultSecretValueProtector(Microsoft.Extensions.Options.Options.Create(new SecretsOptions { EncryptionKey = key })); + } +} diff --git a/test/unit/Elsa.Workflows.Api.UnitTests/ActivityExecutions/ActivityExecutionsEndpointTests.cs b/test/unit/Elsa.Workflows.Api.UnitTests/ActivityExecutions/ActivityExecutionsEndpointTests.cs new file mode 100644 index 000000000..39294d194 --- /dev/null +++ b/test/unit/Elsa.Workflows.Api.UnitTests/ActivityExecutions/ActivityExecutionsEndpointTests.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using Elsa.Workflows.Runtime.Entities; +using FastEndpoints; +using WorkflowsApiFeature = Elsa.Workflows.Api.Features.WorkflowsApiFeature; + +namespace Elsa.Workflows.Api.UnitTests.ActivityExecutions; + +public class ActivityExecutionsEndpointTests +{ + [Fact] + public void GetEndpoint_ExposesPathAndQueryRoutes() + { + var endpointType = typeof(WorkflowsApiFeature).Assembly.GetType("Elsa.Workflows.Api.Endpoints.ActivityExecutions.Get.Endpoint", throwOnError: true)!; + var endpoint = Activator.CreateInstance(endpointType, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, [null], null)!; + var definition = new EndpointDefinition(endpointType, typeof(EmptyRequest), typeof(ActivityExecutionRecord)); + + endpointType + .GetProperty("Definition", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)! + .SetValue(endpoint, definition); + + endpointType.GetMethod("Configure")!.Invoke(endpoint, null); + + Assert.Contains("/activity-executions/{id}", definition.Routes); + Assert.Contains("/activity-executions/{*id}", definition.Routes); + Assert.Contains("/activity-executions/by-id", definition.Routes); + } +} diff --git a/test/unit/Elsa.Workflows.Api.UnitTests/Endpoints/IncidentStrategies/ListTests.cs b/test/unit/Elsa.Workflows.Api.UnitTests/Endpoints/IncidentStrategies/ListTests.cs new file mode 100644 index 000000000..9bcbe5b90 --- /dev/null +++ b/test/unit/Elsa.Workflows.Api.UnitTests/Endpoints/IncidentStrategies/ListTests.cs @@ -0,0 +1,28 @@ +using Elsa.Extensions; +using Elsa.Workflows.Api.Endpoints.IncidentStrategies.List; +using Elsa.Workflows.IncidentStrategies; +using Elsa.Workflows.Options; +using Elsa.Workflows.Services; +using Elsa.Common.Serialization; + +namespace Elsa.Workflows.Api.UnitTests.Endpoints.IncidentStrategies; + +public class ListTests +{ + [Fact] + public async Task ExecuteAsync_ReturnsWorkflowJsonTypeIdentifier_ForIncidentStrategyTypeName() + { + var options = new SerializationTypeOptions(); + options.RegisterTypeAlias(typeof(ContinueWithIncidentsStrategy), nameof(ContinueWithIncidentsStrategy)); + options.RegisterLegacySimpleAssemblyQualifiedName(typeof(ContinueWithIncidentsStrategy)); + var registry = new SerializationTypeRegistry(Microsoft.Extensions.Options.Options.Create(options)); + var endpoint = new List([new ContinueWithIncidentsStrategy()], registry); + + var response = await endpoint.ExecuteAsync(CancellationToken.None); + + var descriptor = Assert.Single(response.Items); + Assert.Equal(nameof(ContinueWithIncidentsStrategy), descriptor.TypeName); + Assert.True(registry.TryGetType(typeof(ContinueWithIncidentsStrategy).GetSimpleAssemblyQualifiedName(), out var legacyType)); + Assert.Equal(typeof(ContinueWithIncidentsStrategy), legacyType); + } +} diff --git a/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/ActivityJsonConverterTests.cs b/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/ActivityJsonConverterTests.cs index 54ce2cd71..7782aeb13 100644 --- a/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/ActivityJsonConverterTests.cs +++ b/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/ActivityJsonConverterTests.cs @@ -162,7 +162,7 @@ public sealed class ActivityJsonConverterTests Converters = { sut, - new TypeJsonConverter(WellKnownTypeRegistry.CreateDefault()), + new TypeJsonConverter(), new PolymorphicObjectConverterFactory() }, TypeInfoResolver = new ModifiableJsonTypeInfoResolver(new CustomConstructorConfigurator().GetModifiers()) @@ -352,4 +352,4 @@ public sealed class ActivityJsonConverterTests } private static ILogger CreateLogger() => LoggerFactory.Create(_ => { }).CreateLogger(); -} \ No newline at end of file +} diff --git a/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/ExcludeFromHashConverterTests.cs b/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/ExcludeFromHashConverterTests.cs deleted file mode 100644 index 493432cd4..000000000 --- a/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/ExcludeFromHashConverterTests.cs +++ /dev/null @@ -1,180 +0,0 @@ -using System.Text.Json; -using System.Text.Json.Serialization; -using Elsa.Workflows.Attributes; -using Elsa.Workflows.Serialization.Converters; - -namespace Elsa.Workflows.Core.UnitTests.Serialization.Converters; - -public class ExcludeFromHashConverterTests -{ - private readonly JsonSerializerOptions _options = new() - { - Converters = { new ExcludeFromHashConverterFactory() } - }; - - [Fact] - public void Write_IncludesConditionallyIgnoredProperty_WhenValueIsNotNull() - { - var json = JsonSerializer.Serialize(new ConditionalIgnoreModel { Name = "Alice" }, _options); - - Assert.Contains("\"Name\":\"Alice\"", json); - } - - [Fact] - public void Write_ExcludesConditionallyIgnoredProperty_WhenValueIsNull() - { - var json = JsonSerializer.Serialize(new ConditionalIgnoreModel(), _options); - - Assert.DoesNotContain("\"Name\"", json); - } - - [Fact] - public void Write_ExcludesAlwaysIgnoredProperty() - { - var json = JsonSerializer.Serialize(new AlwaysIgnoreModel { Secret = "hidden" }, _options); - - Assert.DoesNotContain("\"Secret\"", json); - } - - [Fact] - public void Write_SkipsIndexerProperties() - { - var json = JsonSerializer.Serialize(new IndexerModel(), _options); - - Assert.DoesNotContain("\"Item\"", json); - } - - [Fact] - public void Write_DoesNotEvaluateExcludedProperty() - { - var json = JsonSerializer.Serialize(new ExcludedThrowingModel(), _options); - - Assert.DoesNotContain("\"Secret\"", json); - } - - [Fact] - public void Write_DoesNotEvaluateAlwaysIgnoredProperty() - { - var json = JsonSerializer.Serialize(new AlwaysIgnoredThrowingModel(), _options); - - Assert.DoesNotContain("\"Secret\"", json); - } - - [Fact] - public void Write_IncludesNullableValueTypeWithDefaultUnderlyingValue_WhenIgnoringDefaults() - { - var json = JsonSerializer.Serialize(new DefaultIgnoreNullableModel { Count = 0 }, _options); - - Assert.Contains("\"Count\":0", json); - } - - [Fact] - public void Write_IncludesProperty_WhenJsonIgnoreConditionIsUnknown() - { - var json = JsonSerializer.Serialize(new UnknownIgnoreConditionModel { Name = "Alice" }, _options); - - Assert.Contains("\"Name\":\"Alice\"", json); - } - - [Fact] - public void Write_ExcludesStaticProperties() - { - var json = JsonSerializer.Serialize(new StaticPropertyModel { Name = "Alice" }, _options); - - Assert.Contains("\"Name\":\"Alice\"", json); - Assert.DoesNotContain("\"Secret\"", json); - } - - [Fact] - public void Write_PreservesDeclarationOrder() - { - var json = JsonSerializer.Serialize(new OrderedModel { B = "second", A = "first" }, _options); - - Assert.True(json.IndexOf("\"B\"", StringComparison.Ordinal) < json.IndexOf("\"A\"", StringComparison.Ordinal)); - } - - [Fact] - public void Write_OrdersInheritedProperties_ByDeclaringTypeThenDeclarationOrder() - { - var json = JsonSerializer.Serialize(new DerivedOrderedModel - { - BaseB = "base second", - BaseA = "base first", - DerivedB = "derived second", - DerivedA = "derived first" - }, _options); - - Assert.True(json.IndexOf("\"DerivedB\"", StringComparison.Ordinal) < json.IndexOf("\"DerivedA\"", StringComparison.Ordinal)); - Assert.True(json.IndexOf("\"DerivedA\"", StringComparison.Ordinal) < json.IndexOf("\"BaseB\"", StringComparison.Ordinal)); - Assert.True(json.IndexOf("\"BaseB\"", StringComparison.Ordinal) < json.IndexOf("\"BaseA\"", StringComparison.Ordinal)); - } - - private sealed class ConditionalIgnoreModel - { - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public string? Name { get; set; } - } - - private sealed class AlwaysIgnoreModel - { - [JsonIgnore] - public string? Secret { get; set; } - } - - private sealed class IndexerModel - { - public string this[int index] => index.ToString(); - } - - private sealed class ExcludedThrowingModel - { - [ExcludeFromHash] - public string Secret => throw new InvalidOperationException(); - } - - private sealed class AlwaysIgnoredThrowingModel - { - [JsonIgnore] - public string Secret => throw new InvalidOperationException(); - } - - private sealed class DefaultIgnoreNullableModel - { - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public int? Count { get; set; } - } - - private sealed class UnknownIgnoreConditionModel - { - [JsonIgnore(Condition = (JsonIgnoreCondition)999)] - public string? Name { get; set; } - } - - private sealed class StaticPropertyModel - { - public static string Secret => throw new InvalidOperationException(); - - public string? Name { get; set; } - } - - private sealed class OrderedModel - { - public string? B { get; set; } - - public string? A { get; set; } - } - - private class BaseOrderedModel - { - public string? BaseB { get; set; } - - public string? BaseA { get; set; } - } - - private sealed class DerivedOrderedModel : BaseOrderedModel - { - public string? DerivedB { get; set; } - - public string? DerivedA { get; set; } - } -} diff --git a/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/WorkflowJsonTypeResolverTests.cs b/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/SerializationTypeResolverTests.cs similarity index 78% rename from test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/WorkflowJsonTypeResolverTests.cs rename to test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/SerializationTypeResolverTests.cs index fd1a5d414..e392d6d09 100644 --- a/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/WorkflowJsonTypeResolverTests.cs +++ b/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/SerializationTypeResolverTests.cs @@ -5,27 +5,28 @@ using Elsa.Expressions.Services; using Elsa.Extensions; using Elsa.Workflows.Exceptions; using Elsa.Workflows.Memory; +using Elsa.Workflows.Options; using Elsa.Workflows.Serialization.Converters; -using Elsa.Workflows.Serialization.Helpers; +using Elsa.Workflows.Services; using Elsa.Workflows.State; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Core.UnitTests.Serialization.Converters; -public sealed class WorkflowJsonTypeResolverTests +public sealed class SerializationTypeResolverTests { private static readonly string UnsafeAssemblyQualifiedTypeAlias = typeof(System.Text.StringBuilder).AssemblyQualifiedName!; - private readonly WellKnownTypeRegistry _wellKnownTypeRegistry = new(Microsoft.Extensions.Options.Options.Create(new ExpressionOptions())); + private readonly SerializationTypeRegistry _workflowJsonTypeRegistry = new(Microsoft.Extensions.Options.Options.Create(new SerializationTypeOptions())); private readonly JsonSerializerOptions _options; - public WorkflowJsonTypeResolverTests() + public SerializationTypeResolverTests() { - _wellKnownTypeRegistry.RegisterType(typeof(ExceptionState), nameof(ExceptionState)); - _wellKnownTypeRegistry.RegisterType(typeof(FaultException), nameof(FaultException)); - _wellKnownTypeRegistry.RegisterType(typeof(RegisteredPayload), "RegisteredPayload"); - _options = CreateOptions(_wellKnownTypeRegistry); + _workflowJsonTypeRegistry.RegisterType(typeof(ExceptionState), nameof(ExceptionState)); + _workflowJsonTypeRegistry.RegisterType(typeof(FaultException), nameof(FaultException)); + _workflowJsonTypeRegistry.RegisterType(typeof(RegisteredPayload), "RegisteredPayload"); + _options = CreateOptions(_workflowJsonTypeRegistry); } [Theory] @@ -55,6 +56,14 @@ public sealed class WorkflowJsonTypeResolverTests Assert.Equal(typeof(RegisteredPayload), result); } + [Fact] + public void When_DeserializeRegisteredTypeAliasWithDifferentCasing_Then_ReturnsExpectedType() + { + var result = JsonSerializer.Deserialize(JsonString("registeredpayload"), _options); + + Assert.Equal(typeof(RegisteredPayload), result); + } + [Fact] public void When_DeserializeRegisteredLegacyGenericCollectionTypeAlias_Then_ReturnsExpectedType() { @@ -105,8 +114,8 @@ public sealed class WorkflowJsonTypeResolverTests [MemberData(nameof(JsonIslandValues))] public void When_SerializeSpecialJsonIslandType_Then_CanBeDeserialized(object value, Type expectedType) { - _wellKnownTypeRegistry.RegisterType(typeof(JObject), nameof(JObject)); - _wellKnownTypeRegistry.RegisterType(typeof(JArray), nameof(JArray)); + _workflowJsonTypeRegistry.RegisterType(typeof(JObject), nameof(JObject)); + _workflowJsonTypeRegistry.RegisterType(typeof(JArray), nameof(JArray)); var json = JsonSerializer.Serialize(value, _options); var result = JsonSerializer.Deserialize(json, _options); @@ -149,8 +158,7 @@ public sealed class WorkflowJsonTypeResolverTests module.UseWorkflows(); module.Apply(); using var serviceProvider = services.BuildServiceProvider(); - var expressionOptions = serviceProvider.GetRequiredService>(); - var registry = new WellKnownTypeRegistry(expressionOptions); + var registry = serviceProvider.GetRequiredService(); var aliasRegistered = registry.TryGetAlias(typeof(NullReferenceException), out var alias); var typeRegistered = registry.TryGetType(nameof(NullReferenceException), out var type); @@ -165,6 +173,21 @@ public sealed class WorkflowJsonTypeResolverTests Assert.Equal(typeof(MemoryStorageDriver), memoryStorageDriverType); Assert.True(registry.TryGetType(typeof(MemoryStorageDriver).GetSimpleAssemblyQualifiedName(), out var legacyMemoryStorageDriverType)); Assert.Equal(typeof(MemoryStorageDriver), legacyMemoryStorageDriverType); + Assert.True(registry.TryGetAlias(typeof(Elsa.Workflows.IncidentStrategies.ContinueWithIncidentsStrategy), out var incidentStrategyAlias)); + Assert.Equal(nameof(Elsa.Workflows.IncidentStrategies.ContinueWithIncidentsStrategy), incidentStrategyAlias); + Assert.True(registry.TryGetType(typeof(Elsa.Workflows.IncidentStrategies.ContinueWithIncidentsStrategy).GetSimpleAssemblyQualifiedName(), out var legacyIncidentStrategyType)); + Assert.Equal(typeof(Elsa.Workflows.IncidentStrategies.ContinueWithIncidentsStrategy), legacyIncidentStrategyType); + } + + [Fact] + public void When_TypeAliasExistsOnlyInExpressionOptions_Then_WorkflowJsonDoesNotResolveIt() + { + var expressionOptions = new ExpressionOptions(); + expressionOptions.RegisterTypeAlias(typeof(ExpressionOnlyPayload), "ExpressionOnlyPayload"); + var expressionRegistry = new WellKnownTypeRegistry(Microsoft.Extensions.Options.Options.Create(expressionOptions)); + + Assert.True(expressionRegistry.TryGetType("ExpressionOnlyPayload", out _)); + Assert.Throws(() => JsonSerializer.Deserialize(JsonString("ExpressionOnlyPayload"), _options)); } [Fact] @@ -233,7 +256,7 @@ public sealed class WorkflowJsonTypeResolverTests [Fact] public void When_DeserializePolymorphicObjectWithNonInstantiableType_Then_ThrowsJsonException() { - _wellKnownTypeRegistry.RegisterType(typeof(AbstractPayload), "AbstractPayload"); + _workflowJsonTypeRegistry.RegisterType(typeof(AbstractPayload), "AbstractPayload"); var json = """ { "_type": "AbstractPayload" @@ -259,7 +282,7 @@ public sealed class WorkflowJsonTypeResolverTests [Fact] public void When_DeserializePolymorphicObjectWithoutTypeJsonConverterAndUnknownAssemblyQualifiedType_Then_ThrowsJsonException() { - var options = CreatePolymorphicOnlyOptions(_wellKnownTypeRegistry); + var options = CreatePolymorphicOnlyOptions(_workflowJsonTypeRegistry); var json = $$""" { "capacity": 16, @@ -307,32 +330,32 @@ public sealed class WorkflowJsonTypeResolverTests public void When_RegistryChangesAfterLegacyResolutionAttempt_Then_LegacyResolutionUsesCurrentRegistry() { var typeAlias = typeof(LateRegisteredPayload).GetSimpleAssemblyQualifiedName(); - Assert.False(WorkflowJsonTypeResolver.TryResolveType(_wellKnownTypeRegistry, typeAlias, out _)); + Assert.False(SerializationTypeResolver.TryResolveType(_workflowJsonTypeRegistry, typeAlias, out _)); - _wellKnownTypeRegistry.RegisterType(typeof(LateRegisteredPayload), "LateRegisteredPayload"); + _workflowJsonTypeRegistry.RegisterType(typeof(LateRegisteredPayload), "LateRegisteredPayload"); - Assert.True(WorkflowJsonTypeResolver.TryResolveType(_wellKnownTypeRegistry, typeAlias, out var result)); + Assert.True(SerializationTypeResolver.TryResolveType(_workflowJsonTypeRegistry, typeAlias, out var result)); Assert.Equal(typeof(LateRegisteredPayload), result); } - private static JsonSerializerOptions CreateOptions(WellKnownTypeRegistry wellKnownTypeRegistry) => new() + private static JsonSerializerOptions CreateOptions(ISerializationTypeRegistry workflowJsonTypeRegistry) => new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, PropertyNameCaseInsensitive = true, Converters = { - new PolymorphicObjectConverterFactory(wellKnownTypeRegistry), - new TypeJsonConverter(wellKnownTypeRegistry) + new PolymorphicObjectConverterFactory(workflowJsonTypeRegistry), + new TypeJsonConverter(workflowJsonTypeRegistry) } }; - private static JsonSerializerOptions CreatePolymorphicOnlyOptions(WellKnownTypeRegistry wellKnownTypeRegistry) => new() + private static JsonSerializerOptions CreatePolymorphicOnlyOptions(ISerializationTypeRegistry workflowJsonTypeRegistry) => new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, PropertyNameCaseInsensitive = true, Converters = { - new PolymorphicObjectConverterFactory(wellKnownTypeRegistry) + new PolymorphicObjectConverterFactory(workflowJsonTypeRegistry) } }; @@ -365,4 +388,9 @@ public sealed class WorkflowJsonTypeResolverTests { public string? Name { get; set; } } + + public sealed class ExpressionOnlyPayload + { + public string? Name { get; set; } + } } diff --git a/test/unit/Elsa.Workflows.Core.UnitTests/Services/VariableMapperTests.cs b/test/unit/Elsa.Workflows.Core.UnitTests/Services/VariableMapperTests.cs index 4cc8b8eb1..24dea445c 100644 --- a/test/unit/Elsa.Workflows.Core.UnitTests/Services/VariableMapperTests.cs +++ b/test/unit/Elsa.Workflows.Core.UnitTests/Services/VariableMapperTests.cs @@ -1,15 +1,16 @@ -using Elsa.Expressions.Services; using Elsa.Extensions; using Elsa.Workflows.Memory; using Elsa.Workflows.Models; +using Elsa.Workflows.Options; using Elsa.Workflows.Services; using Microsoft.Extensions.Logging.Abstractions; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Core.UnitTests.Services; public class VariableMapperTests { - private readonly WellKnownTypeRegistry _registry = new(); + private readonly SerializationTypeRegistry _registry = new(Microsoft.Extensions.Options.Options.Create(new SerializationTypeOptions())); private readonly VariableMapper _mapper; public VariableMapperTests() @@ -44,6 +45,14 @@ public class VariableMapperTests Assert.Equal(typeof(MemoryStorageDriver), variable.StorageDriverType); } + [Fact] + public void Map_WritesRegisteredStorageDriverAlias() + { + var model = _mapper.Map(new Variable("name", "") { StorageDriverType = typeof(WorkflowStorageDriver) }); + + Assert.Equal(nameof(WorkflowStorageDriver), model.StorageDriverTypeName); + } + [Fact] public void Map_DoesNotLoadUnregisteredStorageDriverAssemblyQualifiedName() { diff --git a/test/unit/Elsa.Workflows.Management.UnitTests/Mappers/VariableDefinitionMapperTests.cs b/test/unit/Elsa.Workflows.Management.UnitTests/Mappers/VariableDefinitionMapperTests.cs new file mode 100644 index 000000000..8110b8d3d --- /dev/null +++ b/test/unit/Elsa.Workflows.Management.UnitTests/Mappers/VariableDefinitionMapperTests.cs @@ -0,0 +1,83 @@ +using Elsa.Extensions; +using Elsa.Workflows.Management.Mappers; +using Elsa.Workflows.Memory; +using Elsa.Workflows.Models; +using Elsa.Workflows.Options; +using Elsa.Workflows.Services; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging.Abstractions; +using NSubstitute; +using Elsa.Common.Serialization; + +namespace Elsa.Workflows.Management.UnitTests.Mappers; + +public class VariableDefinitionMapperTests +{ + private readonly IServiceScopeFactory _scopeFactory = Substitute.For(); + private readonly SerializationTypeOptions _workflowJsonTypeOptions = new(); + private readonly VariableDefinitionMapper _mapper; + + public VariableDefinitionMapperTests() + { + _workflowJsonTypeOptions.RegisterTypeAlias(typeof(string), "String"); + _workflowJsonTypeOptions.RegisterTypeAlias(typeof(MemoryStorageDriver), nameof(MemoryStorageDriver)); + _mapper = CreateMapper(_workflowJsonTypeOptions); + } + + [Fact] + public void Map_DoesNotResolveUnregisteredClrTypeName() + { + var definition = new VariableDefinition("id", "payload", typeof(UnregisteredPayload).GetSimpleAssemblyQualifiedName(), false, null, null); + + var variable = _mapper.Map(definition); + + Assert.Null(variable); + } + + [Fact] + public void Map_ResolvesRegisteredLegacyClrTypeName() + { + var workflowJsonTypeOptions = new SerializationTypeOptions(); + workflowJsonTypeOptions.RegisterTypeAlias(typeof(UnregisteredPayload), nameof(UnregisteredPayload)); + workflowJsonTypeOptions.RegisterLegacySimpleAssemblyQualifiedName(typeof(UnregisteredPayload)); + var mapper = CreateMapper(workflowJsonTypeOptions); + var definition = new VariableDefinition("id", "payload", typeof(UnregisteredPayload).GetSimpleAssemblyQualifiedName(), false, null, null); + + var variable = mapper.Map(definition); + + Assert.IsType>(variable); + } + + [Fact] + public void Map_WritesUnregisteredVariableTypeAsClrTypeName() + { + var variable = new Variable("payload", new()); + + var definition = _mapper.Map(variable); + + Assert.Equal(typeof(UnregisteredPayload).GetSimpleAssemblyQualifiedName(), definition.TypeName); + } + + [Fact] + public void Map_WritesRegisteredVariableTypeAsAlias() + { + var workflowJsonTypeOptions = new SerializationTypeOptions(); + workflowJsonTypeOptions.RegisterTypeAlias(typeof(UnregisteredPayload), nameof(UnregisteredPayload)); + var mapper = CreateMapper(workflowJsonTypeOptions); + var variable = new Variable("payload", new()); + + var definition = mapper.Map(variable); + + Assert.Equal(nameof(UnregisteredPayload), definition.TypeName); + } + + private VariableDefinitionMapper CreateMapper(SerializationTypeOptions workflowJsonTypeOptions) + { + var workflowJsonTypeRegistry = new SerializationTypeRegistry(Microsoft.Extensions.Options.Options.Create(workflowJsonTypeOptions)); + return new(workflowJsonTypeRegistry, _scopeFactory, NullLogger.Instance); + } + + private sealed class UnregisteredPayload + { + } +} diff --git a/test/unit/Elsa.Workflows.Management.UnitTests/Services/WorkflowDefinitionExporterRegressionTests.cs b/test/unit/Elsa.Workflows.Management.UnitTests/Services/WorkflowDefinitionExporterRegressionTests.cs index f9748dc49..1fe4344ae 100644 --- a/test/unit/Elsa.Workflows.Management.UnitTests/Services/WorkflowDefinitionExporterRegressionTests.cs +++ b/test/unit/Elsa.Workflows.Management.UnitTests/Services/WorkflowDefinitionExporterRegressionTests.cs @@ -1,15 +1,16 @@ using System.IO.Compression; using System.Text.Json; -using Elsa.Expressions.Contracts; using Elsa.Workflows.Activities; using Elsa.Workflows.Management.Entities; using Elsa.Workflows.Management.Filters; using Elsa.Workflows.Management.Mappers; using Elsa.Workflows.Management.Services; using Elsa.Workflows.Models; +using Elsa.Workflows.Services; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging.Abstractions; using NSubstitute; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Management.UnitTests.Services; @@ -60,9 +61,9 @@ public class WorkflowDefinitionExporterRegressionTests private WorkflowDefinitionExporter CreateExporter() { var activitySerializer = Substitute.For(); - var wellKnownTypeRegistry = Substitute.For(); var scopeFactory = Substitute.For(); - var variableDefinitionMapper = new VariableDefinitionMapper(wellKnownTypeRegistry, scopeFactory, NullLogger.Instance); + var workflowJsonTypeRegistry = SerializationTypeRegistry.CreateDefault(); + var variableDefinitionMapper = new VariableDefinitionMapper(workflowJsonTypeRegistry, scopeFactory, NullLogger.Instance); var workflowDefinitionMapper = new WorkflowDefinitionMapper(activitySerializer, _workflowDefinitionService, variableDefinitionMapper); var fileNameSanitizer = new DefaultFileNameSanitizer(); @@ -77,4 +78,4 @@ public class WorkflowDefinitionExporterRegressionTests return new(workflow, rootNode, [rootNode]); } -} \ No newline at end of file +} diff --git a/test/unit/Elsa.Workflows.Runtime.UnitTests/Comparers/WorkflowTriggerEqualityComparerTests.cs b/test/unit/Elsa.Workflows.Runtime.UnitTests/Comparers/WorkflowTriggerEqualityComparerTests.cs index 6299d3a86..c283566b1 100644 --- a/test/unit/Elsa.Workflows.Runtime.UnitTests/Comparers/WorkflowTriggerEqualityComparerTests.cs +++ b/test/unit/Elsa.Workflows.Runtime.UnitTests/Comparers/WorkflowTriggerEqualityComparerTests.cs @@ -1,10 +1,11 @@ using System.Text.Json; using System.Text.Json.Serialization; -using Elsa.Expressions.Contracts; -using Elsa.Expressions.Services; using Elsa.Workflows.Helpers; +using Elsa.Workflows.Options; using Elsa.Workflows.Runtime.Comparers; using Elsa.Workflows.Runtime.Entities; +using Elsa.Workflows.Services; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Runtime.UnitTests.Comparers; @@ -190,9 +191,9 @@ public class WorkflowTriggerEqualityComparerTests return deserialized!; } - private static IWellKnownTypeRegistry CreateTypeRegistry() + private static ISerializationTypeRegistry CreateTypeRegistry() { - var registry = WellKnownTypeRegistry.CreateDefault(); + var registry = new SerializationTypeRegistry(Microsoft.Extensions.Options.Options.Create(new SerializationTypeOptions())); registry.RegisterType(typeof(TestPayload), nameof(TestPayload)); registry.RegisterType(typeof(TypedPayload), nameof(TypedPayload)); registry.RegisterType(typeof(NestedPayload), nameof(NestedPayload)); diff --git a/test/unit/Elsa.Workflows.Runtime.UnitTests/Extensions/ServiceCollectionWorkflowExtensionsTests.cs b/test/unit/Elsa.Workflows.Runtime.UnitTests/Extensions/ServiceCollectionWorkflowExtensionsTests.cs new file mode 100644 index 000000000..97084a465 --- /dev/null +++ b/test/unit/Elsa.Workflows.Runtime.UnitTests/Extensions/ServiceCollectionWorkflowExtensionsTests.cs @@ -0,0 +1,29 @@ +using Elsa.Extensions; +using Elsa.Workflows; +using Elsa.Workflows.Runtime.Options; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace Elsa.Workflows.Runtime.UnitTests.Extensions; + +public class ServiceCollectionWorkflowExtensionsTests +{ + [Fact] + public void AddWorkflow_PostConfiguresRuntimeOptions() + { + var services = new ServiceCollection(); + var configuredWorkflows = new Dictionary>>(); + + services.Configure(options => options.Workflows = configuredWorkflows); + services.AddWorkflow(); + + using var serviceProvider = services.BuildServiceProvider(); + var options = serviceProvider.GetRequiredService>().Value; + var workflowKey = typeof(ServiceCollectionRegisteredWorkflow).GetSimpleAssemblyQualifiedName(); + + Assert.Same(configuredWorkflows, options.Workflows); + Assert.Contains(workflowKey, options.Workflows.Keys); + } +} + +public class ServiceCollectionRegisteredWorkflow : WorkflowBase; diff --git a/test/unit/Elsa.Workflows.Runtime.UnitTests/Features/WorkflowRuntimeFeatureTests.cs b/test/unit/Elsa.Workflows.Runtime.UnitTests/Features/WorkflowRuntimeFeatureTests.cs index d68ca615b..ea633c152 100644 --- a/test/unit/Elsa.Workflows.Runtime.UnitTests/Features/WorkflowRuntimeFeatureTests.cs +++ b/test/unit/Elsa.Workflows.Runtime.UnitTests/Features/WorkflowRuntimeFeatureTests.cs @@ -1,16 +1,17 @@ using System.Reflection; -using Elsa.Expressions.Options; using Elsa.Features.Attributes; using Elsa.Features.Services; using Elsa.Extensions; using Elsa.Workflows; using Elsa.Workflows.Activities; using Elsa.Workflows.Features; +using Elsa.Workflows.Options; using Elsa.Workflows.Runtime.Options; using Elsa.Workflows.Runtime.Providers; using NSubstitute; using RuntimeFeature = Elsa.Workflows.Runtime.Features.WorkflowRuntimeFeature; using ShellRuntimeFeature = Elsa.Workflows.Runtime.ShellFeatures.WorkflowRuntimeFeature; +using Elsa.Common.Serialization; namespace Elsa.Workflows.Runtime.UnitTests.Features; @@ -71,7 +72,7 @@ public class WorkflowRuntimeFeatureTests public void WorkflowsAdd_RegistersWorkflowTypeAlias() { var workflowType = typeof(GenericWorkflow); - var options = new ExpressionOptions(); + var options = new SerializationTypeOptions(); _feature.Workflows.Add(workflowType); @@ -117,7 +118,7 @@ public class WorkflowRuntimeFeatureTests public void ShellWorkflowsAdd_RegistersWorkflowTypeAlias() { var workflowType = typeof(GenericWorkflow); - var options = new ExpressionOptions(); + var options = new SerializationTypeOptions(); _shellFeature.Workflows.Add(workflowType); @@ -146,7 +147,7 @@ public class WorkflowRuntimeFeatureTests public void RegisterWorkflowTypeAliases_RegistersOnlyTrackedWorkflowTypes() { var workflowType = typeof(GenericWorkflow); - var options = new ExpressionOptions(); + var options = new SerializationTypeOptions(); _feature.AddWorkflow(workflowType); _feature.Workflows[typeof(NotAWorkflow).AssemblyQualifiedName!] = _ => new ValueTask(new GenericWorkflow()); @@ -160,7 +161,7 @@ public class WorkflowRuntimeFeatureTests public void ShellRegisterWorkflowTypeAliases_RegistersOnlyTrackedWorkflowTypes() { var workflowType = typeof(GenericWorkflow); - var options = new ExpressionOptions(); + var options = new SerializationTypeOptions(); _shellFeature.AddWorkflow(workflowType); _shellFeature.Workflows[typeof(NotAWorkflow).AssemblyQualifiedName!] = _ => new ValueTask(new GenericWorkflow()); @@ -204,7 +205,7 @@ public class WorkflowRuntimeFeatureTests } } - private static void RegisterWorkflowTypeAliases(object feature, ExpressionOptions options) + private static void RegisterWorkflowTypeAliases(object feature, SerializationTypeOptions options) { feature.GetType() .GetMethod("RegisterWorkflowTypeAliases", BindingFlags.Instance | BindingFlags.NonPublic)!