[
  {
    "path": ".flubu",
    "content": "\nbuild/BuildScript.csproj\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: 🐞 Bug Report\ndescription: Report a reproducible issue or unexpected behavior in CAP\ntitle: \"[Bug] \"\nlabels: [bug]\nassignees: []\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        ## Thanks for reporting a CAP issue!\n\n        Before submitting:\n        - Make sure you've read the documentation at [https://cap.dotnetcore.xyz](https://cap.dotnetcore.xyz).\n        - It's **recommended** to submit a PR directly for typos or trivial fixes.\n        - If this is a **feature request**, please use the *Feature Request* template instead.\n\n  - type: input\n    id: summary\n    attributes:\n      label: Summary\n      description: A short, clear summary of the bug.\n      placeholder: e.g. CAP fails to publish message after transaction commit\n    validations:\n      required: true\n\n  - type: textarea\n    id: reproduce_steps\n    attributes:\n      label: Steps to Reproduce\n      description: Describe how to reproduce the issue step by step.\n      placeholder: |\n        1. Configure CAP with MySQL and RabbitMQ\n        2. Publish message inside a transaction\n        3. Commit transaction\n        4. Observe error or missing message\n    validations:\n      required: true\n\n  - type: textarea\n    id: expected_behavior\n    attributes:\n      label: Expected Behavior\n      description: What should have happened?\n      placeholder: The message should be published and consumed successfully.\n\n  - type: textarea\n    id: actual_behavior\n    attributes:\n      label: Actual Behavior\n      description: What actually happened?\n      placeholder: Message not sent / consumer not triggered / error occurred\n\n  - type: textarea\n    id: logs\n    attributes:\n      label: Log Output\n      description: Paste the relevant CAP logs or exception stack traces here.\n      render: shell\n      placeholder: |\n        [Error] DotNetCore.CAP.Internal.SubscriberExecutor: Exception occurred while processing message\n        System.NullReferenceException: Object reference not set to an instance of an object\n          at DotNetCore.CAP...\n\n  - type: textarea\n    id: config\n    attributes:\n      label: CAP Configuration\n      description: Paste your CAP configuration or initialization code.\n      render: yaml\n      placeholder: |\n        {\n          \"UseDashboard\": true,\n          \"UseMySql\": \"Server=localhost;Database=capdb;Uid=root;Pwd=123456;\",\n          \"UseRabbitMQ\": \"HostName=localhost\"\n        }\n\n  - type: dropdown\n    id: transport\n    attributes:\n      label: Transport Used\n      description: Which message broker are you using?\n      options:\n        - RabbitMQ\n        - Kafka\n        - Pulsar\n        - Azure Service Bus\n        - InMemory\n        - Other\n\n  - type: dropdown\n    id: storage\n    attributes:\n      label: Storage Provider\n      description: Which storage provider are you using?\n      options:\n        - MySQL\n        - PostgreSQL\n        - SQL Server\n        - MongoDB\n        - InMemory\n        - Other\n\n  - type: input\n    id: environment\n    attributes:\n      label: Environment\n      description: OS, .NET version, and CAP version.\n      placeholder: e.g. Windows 11 / .NET 8.0 / CAP 7.2.1\n\n  - type: textarea\n    id: additional\n    attributes:\n      label: Additional Context\n      description: Add any other information, configuration, or screenshots that may help.\n      placeholder: e.g. This issue only occurs under heavy load or after multiple retries.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "content": "name: ✨ Feature Request\ndescription: Suggest a new feature or improvement for CAP\ntitle: \"[Feature] \"\nlabels: [enhancement]\nassignees: []\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        ## Thanks for contributing ideas to CAP!\n\n        Before submitting:\n        - Please make sure your idea isn’t already discussed in [Issues](https://github.com/dotnetcore/CAP/issues) or [Discussions](https://github.com/dotnetcore/CAP/discussions).\n        - For minor code changes (typos, docs, small improvements), submitting a PR directly is recommended.\n        - Be specific — describe the **problem**, not just the solution.\n\n  - type: input\n    id: summary\n    attributes:\n      label: Summary\n      description: A short, clear summary of your proposed feature.\n      placeholder: e.g. Add native support for Azure Event Hubs\n    validations:\n      required: true\n\n  - type: textarea\n    id: motivation\n    attributes:\n      label: Motivation / Problem\n      description: Explain why this feature is needed. What problem does it solve or what limitation does it remove?\n      placeholder: |\n        CAP currently doesn't support Azure Event Hubs as a transport layer.\n        This feature would allow easier integration with Azure cloud environments.\n    validations:\n      required: true\n\n  - type: textarea\n    id: proposed_solution\n    attributes:\n      label: Proposed Solution\n      description: Describe how you think the feature should work or be implemented.\n      placeholder: |\n        Add a new `UseEventHubs()` extension similar to `UseRabbitMQ()` and `UseKafka()`.\n        It should handle publish and consume operations via Azure SDK.\n\n  - type: textarea\n    id: alternatives\n    attributes:\n      label: Alternatives Considered\n      description: Have you considered any workarounds or alternative approaches?\n      placeholder: |\n        We can currently bridge Event Hubs via Kafka protocol, but it adds complexity.\n\n  - type: textarea\n    id: impact\n    attributes:\n      label: Expected Impact\n      description: Describe how this feature would improve CAP or its usability.\n      placeholder: |\n        This would expand CAP’s support for Azure ecosystems and help enterprise users.\n\n  - type: dropdown\n    id: scope\n    attributes:\n      label: Feature Scope\n      description: What area of CAP does this feature affect most?\n      options:\n        - Core\n        - Transport (e.g., RabbitMQ, Kafka, Pulsar)\n        - Storage (e.g., MySQL, PostgreSQL, MongoDB)\n        - Dashboard / UI\n        - Documentation\n        - Other\n\n  - type: textarea\n    id: additional\n    attributes:\n      label: Additional Context\n      description: Add any other relevant details, links, or references.\n      placeholder: e.g. Related issue numbers, design documents, or PR references.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/question.yml",
    "content": "name: ❓ Question or Help\ndescription: Ask a question or request usage help about CAP\ntitle: \"[Question] \"\nlabels: [question]\nassignees: []\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        ## Need help or have a question?\n\n        Before submitting, please:\n        - Read the documentation: [https://cap.dotnetcore.xyz](https://cap.dotnetcore.xyz)\n        - Check existing [Discussions](https://github.com/dotnetcore/CAP/discussions) and [Issues](https://github.com/dotnetcore/CAP/issues)\n        - Use this form for **usage questions**, **configuration issues**, or **how-to** discussions.\n        - If you think this is a **bug**, please use the *Bug Report* template instead.\n\n  - type: input\n    id: topic\n    attributes:\n      label: Question Summary\n      description: A short summary of what you need help with.\n      placeholder: e.g. How to retry messages when using RabbitMQ?\n    validations:\n      required: true\n\n  - type: textarea\n    id: context\n    attributes:\n      label: Context\n      description: Explain your question, what you have tried, and what you expected.\n      placeholder: |\n        I'm using CAP with MySQL and RabbitMQ.\n        The message was not retried after exception.\n        Is there a configuration to enable retry?\n\n  - type: textarea\n    id: code\n    attributes:\n      label: Relevant Code or Configuration\n      description: Provide related code snippets, config, or setup details.\n      render: csharp\n      placeholder: |\n        builder.Services.AddCap(x =>\n        {\n            x.UseRabbitMQ(\"localhost\");\n            x.UseMySql(\"Server=127.0.0.1;Database=capdb;Uid=root;Pwd=123456;\");\n        });\n\n  - type: dropdown\n    id: environment\n    attributes:\n      label: Environment\n      description: What environment are you using CAP in?\n      options:\n        - .NET 8.0\n        - .NET 7.0\n        - .NET 6.0\n        - Other\n\n  - type: textarea\n    id: additional\n    attributes:\n      label: Additional Information\n      description: Add any other context or reference links that may help answer your question.\n      placeholder: e.g. Related GitHub issue, article, or code sample link.\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "### Description:\n_Provide a more detailed description of the changes made in this PR. Explain the reason behind the changes and their expected impact on the project._\n\n#### Issue(s) addressed:\n- [Link to the related issue(s), if any]\n\n#### Changes:\n- _List the major changes made in this PR, preferably in bullet points._\n\n#### Affected components:\n- _List the components of the project that are affected by this PR._\n\n#### How to test:\n_Provide a step-by-step guide on how to test your changes. Include any relevant information like environment setup, dependencies, etc._\n\n### Additional notes (optional):\n_Provide any additional notes or context that may be relevant to the changes._\n\n### Checklist:\n- [ ] I have tested my changes locally\n- [ ] I have added necessary documentation (if applicable)\n- [ ] I have updated the relevant tests (if applicable)\n- [ ] My changes follow the project's code style guidelines\n\n### Reviewers:\n- _Mention any reviewers you would like to review your PR. This can be helpful if you know someone who is familiar with the part of the codebase you're working on._\n"
  },
  {
    "path": ".github/workflows/deploy-docs-and-dashboard.yml",
    "content": "name: docs & dashboard-dist\non:\n  push:\n    branches:\n      - master\njobs:\n  changes:\n    runs-on: ubuntu-latest\n    outputs:\n      docs: ${{ steps.filter.outputs.docs }}\n      dashboard: ${{ steps.filter.outputs.dashboard }}\n    steps:\n    - name: Checkout 🛎️\n      uses: actions/checkout@v3\n      with:\n        persist-credentials: false \n    - name: Check for changes 🎯\n      uses: dorny/paths-filter@v2\n      id: filter\n      with:\n        filters: |\n          docs:\n            - 'docs/**'\n          dashboard:\n            - 'src/DotNetCore.CAP.Dashboard/wwwroot/src/**'\n  \n  build-dashboard-and-push:\n    needs: changes\n    if: ${{ needs.changes.outputs.dashboard == 'true' }}    \n    runs-on: ubuntu-latest\n    defaults:\n      run:\n        working-directory: src/DotNetCore.CAP.Dashboard/wwwroot  \n    steps:\n    - name: Checkout 🛎️\n      uses: actions/checkout@v3\n      with:\n        persist-credentials: false \n    - name: Use Node.js 🥽\n      uses: actions/setup-node@v3\n      with:\n        node-version: 16\n    - name: Install dependencies 🧵\n      run: npm install\n    - name: Build to dist 🧨\n      run: npm run build\n    - name: Commit & Push dist changes 🚀\n      uses: actions-js/push@master\n      with:\n        branch: master\n        github_token: ${{ secrets.GITHUB_TOKEN }}\n\n  build-docs-and-deploy:\n    needs: changes\n    if: ${{ needs.changes.outputs.docs == 'true' }}\n    runs-on: ubuntu-latest\n    steps:\n    - name: Checkout 🛎️\n      uses: actions/checkout@v3\n      with:\n        persist-credentials: false \n    - name: Deploy docs 🚀\n      uses: mhausenblas/mkdocs-deploy-gh-pages@master\n      env:\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        GOOGLE_ANALYTICS_KEY: ${{ secrets.GOOGLE_ANALYTICS_KEY }}\n        CONFIG_FILE: docs/mkdocs.yml\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\n[Oo]bj/\n[Bb]in/\nTestResults/\n.nuget/\n_ReSharper.*/\npackages/\nartifacts/\nPublishProfiles/\n*.user\n*.suo\n*.cache\n*.docstates\n_ReSharper.*\n*.[Rr]e[Ss]harper\n*.DotSettings.user\nnuget.exe\n*k10.csproj\n*.psess\n*.vsp\n*.pidb\n*.userprefs\n*DS_Store\n*.ncrunchsolution\n*.*sdf\n*.ipch\n*.sln.ide\n.vs\n.build/\n/.idea/.idea.CAP\n/.idea\nProperties\n/pack.bat\n.vscode/*\nsite/\n*.lock\n"
  },
  {
    "path": "CAP.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.31919.166\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"src\", \"src\", \"{9B2AE124-6636-4DE9-83A3-70360DABD0C4}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"test\", \"test\", \"{C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Solution Items\", \"Solution Items\", \"{57A8A8E5-5715-41BF-A0A6-46B819933FBC}\"\n\tProjectSection(SolutionItems) = preProject\n\t\t.flubu = .flubu\n\t\t.gitignore = .gitignore\n\t\tappveyor.yml = appveyor.yml\n\t\t.github\\workflows\\deploy-docs-and-dashboard.yml = .github\\workflows\\deploy-docs-and-dashboard.yml\n\t\t.github\\ISSUE_TEMPLATE = .github\\ISSUE_TEMPLATE\n\t\tLICENSE.txt = LICENSE.txt\n\t\tREADME.md = README.md\n\t\tREADME.zh-cn.md = README.zh-cn.md\n\tEndProjectSection\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP\", \"src\\DotNetCore.CAP\\DotNetCore.CAP.csproj\", \"{E8AF8611-0EA4-4B19-BC48-87C57A87DC66}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"samples\", \"samples\", \"{3A6B6931-A123-477A-9469-8B468B5385AF}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.Kafka\", \"src\\DotNetCore.CAP.Kafka\\DotNetCore.CAP.Kafka.csproj\", \"{C42CDE33-0878-4BA0-96F2-4CB7C8FDEAAD}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.RabbitMQ\", \"src\\DotNetCore.CAP.RabbitMQ\\DotNetCore.CAP.RabbitMQ.csproj\", \"{9961B80E-0718-4280-B2A0-271B003DE26B}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"build\", \"build\", \"{10C0818D-9160-4B80-BB86-DDE925B64D43}\"\n\tProjectSection(SolutionItems) = preProject\n\t\tsrc\\Directory.Build.props = src\\Directory.Build.props\n\t\tbuild\\version.props = build\\version.props\n\tEndProjectSection\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.SqlServer\", \"src\\DotNetCore.CAP.SqlServer\\DotNetCore.CAP.SqlServer.csproj\", \"{3B577468-6792-4EF1-9237-15180B176A24}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.MySql\", \"src\\DotNetCore.CAP.MySql\\DotNetCore.CAP.MySql.csproj\", \"{FA15685A-778A-4D2A-A2FE-27FAD2FFA65B}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.MySql.Test\", \"test\\DotNetCore.CAP.MySql.Test\\DotNetCore.CAP.MySql.Test.csproj\", \"{80A84F62-1558-427B-BA74-B47AA8A665B5}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sample.RabbitMQ.MySql\", \"samples\\Sample.RabbitMQ.MySql\\Sample.RabbitMQ.MySql.csproj\", \"{9F3F9BFE-7B6A-4A7A-A6E6-8B517D611873}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.PostgreSql\", \"src\\DotNetCore.CAP.PostgreSql\\DotNetCore.CAP.PostgreSql.csproj\", \"{82C403AB-ED68-4084-9A1D-11334F9F08F9}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.MongoDB\", \"src\\DotNetCore.CAP.MongoDB\\DotNetCore.CAP.MongoDB.csproj\", \"{77C0AC02-C44B-49D5-B969-7D5305FC20A5}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sample.RabbitMQ.MongoDB\", \"samples\\Sample.RabbitMQ.MongoDB\\Sample.RabbitMQ.MongoDB.csproj\", \"{4473DE19-E8D2-4B57-80A8-C8AAA2BFA20F}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.AzureServiceBus\", \"src\\DotNetCore.CAP.AzureServiceBus\\DotNetCore.CAP.AzureServiceBus.csproj\", \"{63B2A464-FBEA-42FB-8EFA-98AFA39FC920}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.Dashboard\", \"src\\DotNetCore.CAP.Dashboard\\DotNetCore.CAP.Dashboard.csproj\", \"{56FB261C-67AF-4715-9A46-4FA4FAB91B2C}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sample.RabbitMQ.SqlServer\", \"samples\\Sample.RabbitMQ.SqlServer\\Sample.RabbitMQ.SqlServer.csproj\", \"{F6C5C676-AF05-46D5-A45D-442137B31898}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sample.Kafka.PostgreSql\", \"samples\\Sample.Kafka.PostgreSql\\Sample.Kafka.PostgreSql.csproj\", \"{F1EF1D26-8A6B-403E-85B0-250DF44A4A7C}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"BuildScript\", \"build\\BuildScript.csproj\", \"{F8EF381A-FE83-40B3-A63D-09D83851B0FB}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.InMemoryStorage\", \"src\\DotNetCore.CAP.InMemoryStorage\\DotNetCore.CAP.InMemoryStorage.csproj\", \"{93176BAE-914B-4BED-9DE3-01FFB4F27FC5}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.Test\", \"test\\DotNetCore.CAP.Test\\DotNetCore.CAP.Test.csproj\", \"{75CC45E6-BF06-40F4-977D-10DCC05B2EFA}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sample.ConsoleApp\", \"samples\\Sample.ConsoleApp\\Sample.ConsoleApp.csproj\", \"{2B0F467E-ABBD-4A51-BF38-D4F609DB6266}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.AmazonSQS\", \"src\\DotNetCore.CAP.AmazonSQS\\DotNetCore.CAP.AmazonSQS.csproj\", \"{43475E00-51B7-443D-BC2D-FC21F9D8A0B4}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sample.AmazonSQS.InMemory\", \"samples\\Sample.AmazonSQS.InMemory\\Sample.AmazonSQS.InMemory.csproj\", \"{B187DD15-092D-4B72-9807-50856607D237}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.NATS\", \"src\\DotNetCore.CAP.NATS\\DotNetCore.CAP.NATS.csproj\", \"{8B2FD3EA-E72B-4A82-B182-B87EC0C15D07}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Samples.Redis.SqlServer\", \"samples\\Samples.Redis.SqlServer\\Samples.Redis.SqlServer.csproj\", \"{375AF85D-8C81-47C6-BE5B-D0874D4971EA}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.RedisStreams\", \"src\\DotNetCore.CAP.RedisStreams\\DotNetCore.CAP.RedisStreams.csproj\", \"{54458B54-49CC-454C-82B2-4AED681D9D07}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sample.Dashboard.Auth\", \"samples\\Sample.Dashboard.Auth\\Sample.Dashboard.Auth.csproj\", \"{6E059983-DE89-4D53-88F5-D9083BCE257F}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.MultiModuleSubscriberTests\", \"test\\DotNetCore.CAP.MultiModuleSubscriberTests\\DotNetCore.CAP.MultiModuleSubscriberTests.csproj\", \"{23684403-7DA8-489A-8A1E-8056D7683E18}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.Pulsar\", \"src\\DotNetCore.CAP.Pulsar\\DotNetCore.CAP.Pulsar.csproj\", \"{AB7A10CB-2C7E-49CE-AA21-893772FF6546}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sample.Pulsar.InMemory\", \"samples\\Sample.Pulsar.InMemory\\Sample.Pulsar.InMemory.csproj\", \"{B1D95CCD-0123-41D4-8CCB-9F834ED8D5C5}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.OpenTelemetry\", \"src\\DotNetCore.CAP.OpenTelemetry\\DotNetCore.CAP.OpenTelemetry.csproj\", \"{83DDB126-A00B-4064-86E7-568322CA67EC}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sample.AzureServiceBus.InMemory\", \"samples\\Sample.AzureServiceBus.InMemory\\Sample.AzureServiceBus.InMemory.csproj\", \"{0C734FB2-7D75-4FF3-B564-1E50E6280B14}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.AzureServiceBus.Test\", \"test\\DotNetCore.CAP.AzureServiceBus.Test\\DotNetCore.CAP.AzureServiceBus.Test.csproj\", \"{D9681967-DAC2-43EF-999F-3727F1046711}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sample.Dashboard.Jwt\", \"samples\\Sample.Dashboard.Jwt\\Sample.Dashboard.Jwt.csproj\", \"{F739A8C9-565F-4B1D-8F91-FEE056C03FBD}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotNetCore.CAP.Dashboard.K8s\", \"src\\DotNetCore.CAP.Dashboard.K8s\\DotNetCore.CAP.Dashboard.K8s.csproj\", \"{48655118-CEC3-4BD9-B510-64C1195C2729}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{E8AF8611-0EA4-4B19-BC48-87C57A87DC66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E8AF8611-0EA4-4B19-BC48-87C57A87DC66}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E8AF8611-0EA4-4B19-BC48-87C57A87DC66}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E8AF8611-0EA4-4B19-BC48-87C57A87DC66}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{C42CDE33-0878-4BA0-96F2-4CB7C8FDEAAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C42CDE33-0878-4BA0-96F2-4CB7C8FDEAAD}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C42CDE33-0878-4BA0-96F2-4CB7C8FDEAAD}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C42CDE33-0878-4BA0-96F2-4CB7C8FDEAAD}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{9961B80E-0718-4280-B2A0-271B003DE26B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9961B80E-0718-4280-B2A0-271B003DE26B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9961B80E-0718-4280-B2A0-271B003DE26B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9961B80E-0718-4280-B2A0-271B003DE26B}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{3B577468-6792-4EF1-9237-15180B176A24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3B577468-6792-4EF1-9237-15180B176A24}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3B577468-6792-4EF1-9237-15180B176A24}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3B577468-6792-4EF1-9237-15180B176A24}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{FA15685A-778A-4D2A-A2FE-27FAD2FFA65B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{FA15685A-778A-4D2A-A2FE-27FAD2FFA65B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{FA15685A-778A-4D2A-A2FE-27FAD2FFA65B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{FA15685A-778A-4D2A-A2FE-27FAD2FFA65B}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{80A84F62-1558-427B-BA74-B47AA8A665B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{80A84F62-1558-427B-BA74-B47AA8A665B5}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{80A84F62-1558-427B-BA74-B47AA8A665B5}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{80A84F62-1558-427B-BA74-B47AA8A665B5}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{9F3F9BFE-7B6A-4A7A-A6E6-8B517D611873}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9F3F9BFE-7B6A-4A7A-A6E6-8B517D611873}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9F3F9BFE-7B6A-4A7A-A6E6-8B517D611873}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9F3F9BFE-7B6A-4A7A-A6E6-8B517D611873}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{82C403AB-ED68-4084-9A1D-11334F9F08F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{82C403AB-ED68-4084-9A1D-11334F9F08F9}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{82C403AB-ED68-4084-9A1D-11334F9F08F9}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{82C403AB-ED68-4084-9A1D-11334F9F08F9}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{77C0AC02-C44B-49D5-B969-7D5305FC20A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{77C0AC02-C44B-49D5-B969-7D5305FC20A5}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{77C0AC02-C44B-49D5-B969-7D5305FC20A5}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{77C0AC02-C44B-49D5-B969-7D5305FC20A5}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{4473DE19-E8D2-4B57-80A8-C8AAA2BFA20F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4473DE19-E8D2-4B57-80A8-C8AAA2BFA20F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{4473DE19-E8D2-4B57-80A8-C8AAA2BFA20F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{4473DE19-E8D2-4B57-80A8-C8AAA2BFA20F}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{63B2A464-FBEA-42FB-8EFA-98AFA39FC920}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{63B2A464-FBEA-42FB-8EFA-98AFA39FC920}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{63B2A464-FBEA-42FB-8EFA-98AFA39FC920}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{63B2A464-FBEA-42FB-8EFA-98AFA39FC920}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{56FB261C-67AF-4715-9A46-4FA4FAB91B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{56FB261C-67AF-4715-9A46-4FA4FAB91B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{56FB261C-67AF-4715-9A46-4FA4FAB91B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{56FB261C-67AF-4715-9A46-4FA4FAB91B2C}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{F6C5C676-AF05-46D5-A45D-442137B31898}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F6C5C676-AF05-46D5-A45D-442137B31898}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F6C5C676-AF05-46D5-A45D-442137B31898}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F6C5C676-AF05-46D5-A45D-442137B31898}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{F1EF1D26-8A6B-403E-85B0-250DF44A4A7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F1EF1D26-8A6B-403E-85B0-250DF44A4A7C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F1EF1D26-8A6B-403E-85B0-250DF44A4A7C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F1EF1D26-8A6B-403E-85B0-250DF44A4A7C}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{F8EF381A-FE83-40B3-A63D-09D83851B0FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F8EF381A-FE83-40B3-A63D-09D83851B0FB}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F8EF381A-FE83-40B3-A63D-09D83851B0FB}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F8EF381A-FE83-40B3-A63D-09D83851B0FB}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{93176BAE-914B-4BED-9DE3-01FFB4F27FC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{93176BAE-914B-4BED-9DE3-01FFB4F27FC5}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{93176BAE-914B-4BED-9DE3-01FFB4F27FC5}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{93176BAE-914B-4BED-9DE3-01FFB4F27FC5}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{75CC45E6-BF06-40F4-977D-10DCC05B2EFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{75CC45E6-BF06-40F4-977D-10DCC05B2EFA}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{75CC45E6-BF06-40F4-977D-10DCC05B2EFA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{75CC45E6-BF06-40F4-977D-10DCC05B2EFA}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{2B0F467E-ABBD-4A51-BF38-D4F609DB6266}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{2B0F467E-ABBD-4A51-BF38-D4F609DB6266}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{2B0F467E-ABBD-4A51-BF38-D4F609DB6266}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{2B0F467E-ABBD-4A51-BF38-D4F609DB6266}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{43475E00-51B7-443D-BC2D-FC21F9D8A0B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{43475E00-51B7-443D-BC2D-FC21F9D8A0B4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{43475E00-51B7-443D-BC2D-FC21F9D8A0B4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{43475E00-51B7-443D-BC2D-FC21F9D8A0B4}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B187DD15-092D-4B72-9807-50856607D237}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B187DD15-092D-4B72-9807-50856607D237}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B187DD15-092D-4B72-9807-50856607D237}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B187DD15-092D-4B72-9807-50856607D237}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{8B2FD3EA-E72B-4A82-B182-B87EC0C15D07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8B2FD3EA-E72B-4A82-B182-B87EC0C15D07}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8B2FD3EA-E72B-4A82-B182-B87EC0C15D07}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8B2FD3EA-E72B-4A82-B182-B87EC0C15D07}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{375AF85D-8C81-47C6-BE5B-D0874D4971EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{375AF85D-8C81-47C6-BE5B-D0874D4971EA}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{375AF85D-8C81-47C6-BE5B-D0874D4971EA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{375AF85D-8C81-47C6-BE5B-D0874D4971EA}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{54458B54-49CC-454C-82B2-4AED681D9D07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{54458B54-49CC-454C-82B2-4AED681D9D07}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{54458B54-49CC-454C-82B2-4AED681D9D07}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{54458B54-49CC-454C-82B2-4AED681D9D07}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{6E059983-DE89-4D53-88F5-D9083BCE257F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6E059983-DE89-4D53-88F5-D9083BCE257F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6E059983-DE89-4D53-88F5-D9083BCE257F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6E059983-DE89-4D53-88F5-D9083BCE257F}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{23684403-7DA8-489A-8A1E-8056D7683E18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{23684403-7DA8-489A-8A1E-8056D7683E18}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{23684403-7DA8-489A-8A1E-8056D7683E18}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{23684403-7DA8-489A-8A1E-8056D7683E18}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{AB7A10CB-2C7E-49CE-AA21-893772FF6546}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AB7A10CB-2C7E-49CE-AA21-893772FF6546}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AB7A10CB-2C7E-49CE-AA21-893772FF6546}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AB7A10CB-2C7E-49CE-AA21-893772FF6546}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B1D95CCD-0123-41D4-8CCB-9F834ED8D5C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B1D95CCD-0123-41D4-8CCB-9F834ED8D5C5}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B1D95CCD-0123-41D4-8CCB-9F834ED8D5C5}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B1D95CCD-0123-41D4-8CCB-9F834ED8D5C5}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{83DDB126-A00B-4064-86E7-568322CA67EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{83DDB126-A00B-4064-86E7-568322CA67EC}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{83DDB126-A00B-4064-86E7-568322CA67EC}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{83DDB126-A00B-4064-86E7-568322CA67EC}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{0C734FB2-7D75-4FF3-B564-1E50E6280B14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0C734FB2-7D75-4FF3-B564-1E50E6280B14}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{0C734FB2-7D75-4FF3-B564-1E50E6280B14}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{0C734FB2-7D75-4FF3-B564-1E50E6280B14}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{D9681967-DAC2-43EF-999F-3727F1046711}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{D9681967-DAC2-43EF-999F-3727F1046711}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{D9681967-DAC2-43EF-999F-3727F1046711}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{D9681967-DAC2-43EF-999F-3727F1046711}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{F739A8C9-565F-4B1D-8F91-FEE056C03FBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F739A8C9-565F-4B1D-8F91-FEE056C03FBD}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F739A8C9-565F-4B1D-8F91-FEE056C03FBD}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F739A8C9-565F-4B1D-8F91-FEE056C03FBD}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{48655118-CEC3-4BD9-B510-64C1195C2729}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{48655118-CEC3-4BD9-B510-64C1195C2729}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{48655118-CEC3-4BD9-B510-64C1195C2729}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{48655118-CEC3-4BD9-B510-64C1195C2729}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{E8AF8611-0EA4-4B19-BC48-87C57A87DC66} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}\n\t\t{C42CDE33-0878-4BA0-96F2-4CB7C8FDEAAD} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}\n\t\t{9961B80E-0718-4280-B2A0-271B003DE26B} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}\n\t\t{3B577468-6792-4EF1-9237-15180B176A24} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}\n\t\t{FA15685A-778A-4D2A-A2FE-27FAD2FFA65B} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}\n\t\t{80A84F62-1558-427B-BA74-B47AA8A665B5} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0}\n\t\t{9F3F9BFE-7B6A-4A7A-A6E6-8B517D611873} = {3A6B6931-A123-477A-9469-8B468B5385AF}\n\t\t{82C403AB-ED68-4084-9A1D-11334F9F08F9} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}\n\t\t{77C0AC02-C44B-49D5-B969-7D5305FC20A5} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}\n\t\t{4473DE19-E8D2-4B57-80A8-C8AAA2BFA20F} = {3A6B6931-A123-477A-9469-8B468B5385AF}\n\t\t{63B2A464-FBEA-42FB-8EFA-98AFA39FC920} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}\n\t\t{56FB261C-67AF-4715-9A46-4FA4FAB91B2C} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}\n\t\t{F6C5C676-AF05-46D5-A45D-442137B31898} = {3A6B6931-A123-477A-9469-8B468B5385AF}\n\t\t{F1EF1D26-8A6B-403E-85B0-250DF44A4A7C} = {3A6B6931-A123-477A-9469-8B468B5385AF}\n\t\t{F8EF381A-FE83-40B3-A63D-09D83851B0FB} = {10C0818D-9160-4B80-BB86-DDE925B64D43}\n\t\t{93176BAE-914B-4BED-9DE3-01FFB4F27FC5} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}\n\t\t{75CC45E6-BF06-40F4-977D-10DCC05B2EFA} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0}\n\t\t{2B0F467E-ABBD-4A51-BF38-D4F609DB6266} = {3A6B6931-A123-477A-9469-8B468B5385AF}\n\t\t{43475E00-51B7-443D-BC2D-FC21F9D8A0B4} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}\n\t\t{B187DD15-092D-4B72-9807-50856607D237} = {3A6B6931-A123-477A-9469-8B468B5385AF}\n\t\t{8B2FD3EA-E72B-4A82-B182-B87EC0C15D07} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}\n\t\t{375AF85D-8C81-47C6-BE5B-D0874D4971EA} = {3A6B6931-A123-477A-9469-8B468B5385AF}\n\t\t{54458B54-49CC-454C-82B2-4AED681D9D07} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}\n\t\t{6E059983-DE89-4D53-88F5-D9083BCE257F} = {3A6B6931-A123-477A-9469-8B468B5385AF}\n\t\t{23684403-7DA8-489A-8A1E-8056D7683E18} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0}\n\t\t{AB7A10CB-2C7E-49CE-AA21-893772FF6546} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}\n\t\t{B1D95CCD-0123-41D4-8CCB-9F834ED8D5C5} = {3A6B6931-A123-477A-9469-8B468B5385AF}\n\t\t{83DDB126-A00B-4064-86E7-568322CA67EC} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}\n\t\t{0C734FB2-7D75-4FF3-B564-1E50E6280B14} = {3A6B6931-A123-477A-9469-8B468B5385AF}\n\t\t{D9681967-DAC2-43EF-999F-3727F1046711} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0}\n\t\t{F739A8C9-565F-4B1D-8F91-FEE056C03FBD} = {3A6B6931-A123-477A-9469-8B468B5385AF}\n\t\t{48655118-CEC3-4BD9-B510-64C1195C2729} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {2E70565D-94CF-40B4-BFE1-AC18D5F736AB}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "CAP.sln.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:String x:Key=\"/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DB/@EntryIndexedValue\">DB</s:String>\n\t<s:String x:Key=\"/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=NATS/@EntryIndexedValue\">NATS</s:String>\n\t<s:String x:Key=\"/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SNS/@EntryIndexedValue\">SNS</s:String>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Mongo/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=NATS/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Postgre/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "LICENSE.txt",
    "content": "MIT License\n\nCopyright (c) 2016 Savorboard\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <img height=\"140\" src=\"https://raw.githubusercontent.com/dotnetcore/CAP/master/docs/content/img/logo.svg\" alt=\"CAP Logo\">\n</p>\n\n# CAP 　　　　　　　　　　　　　　　　　　　　[中文](https://github.com/dotnetcore/CAP/blob/master/README.zh-cn.md)\n\n[![Docs & Dashboard](https://github.com/dotnetcore/CAP/actions/workflows/deploy-docs-and-dashboard.yml/badge.svg?branch=master)](https://github.com/dotnetcore/CAP/actions/workflows/deploy-docs-and-dashboard.yml)\n[![AppVeyor](https://ci.appveyor.com/api/projects/status/v8gfh6pe2u2laqoa/branch/master?svg=true)](https://ci.appveyor.com/project/yang-xiaodong/cap/branch/master)\n[![NuGet](https://img.shields.io/nuget/v/DotNetCore.CAP.svg)](https://www.nuget.org/packages/DotNetCore.CAP/)\n[![NuGet Preview](https://img.shields.io/nuget/vpre/DotNetCore.CAP.svg?label=nuget-pre)](https://www.nuget.org/packages/DotNetCore.CAP/)\n[![Member project of .NET Core Community](https://img.shields.io/badge/member%20project%20of-NCC-9e20c9.svg)](https://github.com/dotnetcore)\n[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/dotnetcore/CAP/master/LICENSE.txt)\n\nCAP is a .NET library that provides a lightweight, easy-to-use, and efficient solution for distributed transactions and event bus integration.\n\nWhen building SOA or Microservice-based systems, services often need to be integrated via events. However, simply using a message queue cannot guarantee reliability. CAP leverages a local message table, integrated with your current database, to solve exceptions that can occur during distributed system communications. This ensures that event messages are never lost.\n\nYou can also use CAP as a standalone EventBus. It offers a simplified approach to event publishing and subscribing without requiring you to inherit or implement any specific interfaces.\n\n## Key Features\n\n*   **Core Functionality**\n    *   **Distributed Transactions**: Guarantees data consistency across microservices using a local message table (Outbox Pattern).\n    *   **Event Bus**: High-performance, lightweight event bus for decoupled communication.\n    *   **Guaranteed Delivery**: Ensures messages are never lost, with automatic retries for failed messages.\n\n*   **Advanced Messaging**\n    *   **Delayed Messages**: Native support for publishing messages with a delay, without relying on message queue features.\n    *   **Flexible Subscriptions**: Supports attribute-based, wildcard (`*`, `#`), and partial topic subscriptions.\n    *   **Consumer Groups & Fan-Out**: Easily implement competing consumer or fan-out patterns for load balancing or broadcasting.\n    *   **Parallel & Serial Processing**: Configure consumers for high-throughput parallel processing or ordered sequential execution.\n    *   **Backpressure Mechanism**: Automatically manages processing speed to prevent memory overload (OOM) under high load.\n\n*   **Extensibility & Integration**\n    *   **Pluggable Architecture**: Supports a wide range of message queues (RabbitMQ, Kafka, Azure Service Bus, etc.) and databases (SQL Server, PostgreSQL, MongoDB, etc.).\n    *   **Heterogeneous Systems**: Provides mechanisms to integrate with non-CAP or legacy systems.\n    *   **Customizable Filters & Serialization**: Intercept the processing pipeline with custom filters and support various serialization formats.\n\n*   **Monitoring & Observability**\n    *   **Real-time Dashboard**: A built-in web dashboard to monitor messages, view status, and manually retry.\n    *   **Service Discovery**: Integrates with Consul and Kubernetes for node discovery in a distributed environment.\n    *   **OpenTelemetry Support**: Built-in instrumentation for distributed tracing, providing end-to-end visibility.\n\n## Architecture Overview\n\n![CAP Architecture](https://raw.githubusercontent.com/dotnetcore/CAP/master/docs/content/img/architecture-new.png)\n\n> CAP implements the **Outbox Pattern** as described in the [eShop on .NET ebook](https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/multi-container-microservice-net-applications/subscribe-events#designing-atomicity-and-resiliency-when-publishing-to-the-event-bus).\n\n## Getting Started\n\n### 1. Installation\n\nInstall the main CAP package into your project using NuGet.\n\n```shell\nPM> Install-Package DotNetCore.CAP\n```\n\nNext, install the desired transport and storage providers.\n\n**Transports (Message Queues):**\n\n```shell\nPM> Install-Package DotNetCore.CAP.Kafka\nPM> Install-Package DotNetCore.CAP.RabbitMQ\nPM> Install-Package DotNetCore.CAP.AzureServiceBus\nPM> Install-Package DotNetCore.CAP.AmazonSQS\nPM> Install-Package DotNetCore.CAP.NATS\nPM> Install-Package DotNetCore.CAP.RedisStreams\nPM> Install-Package DotNetCore.CAP.Pulsar\n```\n\n**Storage (Databases):**\n\nThe event log table will be integrated into the database you select.\n\n```shell\nPM> Install-Package DotNetCore.CAP.SqlServer\nPM> Install-Package DotNetCore.CAP.MySql\nPM> Install-Package DotNetCore.CAP.PostgreSql\nPM> Install-Package DotNetCore.CAP.MongoDB     // Requires MongoDB 4.0+ cluster\n```\n\n### 2. Configuration\n\nConfigure CAP in your `Startup.cs` or `Program.cs`.\n\n```csharp\npublic void ConfigureServices(IServiceCollection services)\n{\n    // If you are using EF as the ORM\n    services.AddDbContext<AppDbContext>(); \n    \n    // If you are using MongoDB\n    services.AddSingleton<IMongoClient>(new MongoClient(\"...\"));\n\n    services.AddCap(x =>\n    {\n        // Using Entity Framework\n        // CAP can auto-discover the connection string\n        x.UseEntityFramework<AppDbContext>();\n\n        // Using ADO.NET\n        x.UseSqlServer(\"Your ConnectionString\");\n        x.UseMySql(\"Your ConnectionString\");\n        x.UsePostgreSql(\"Your ConnectionString\");\n\n        // Using MongoDB (requires a 4.0+ cluster)\n        x.UseMongoDB(\"Your ConnectionString\");\n\n        // Choose your message transport\n        x.UseRabbitMQ(\"HostName\");\n        x.UseKafka(\"ConnectionString\");\n        x.UseAzureServiceBus(\"ConnectionString\");\n        x.UseAmazonSQS(options => { /* ... */ });\n        x.UseNATS(\"ConnectionString\");\n        x.UsePulsar(\"ConnectionString\");\n        x.UseRedisStreams(\"ConnectionString\");\n    });\n}\n```\n\n### 3. Publish Messages\n\nInject `ICapPublisher` into your controller or service to publish events. As of version 7.0, you can also publish delayed messages.\n\n```csharp\npublic class PublishController : Controller\n{\n    private readonly ICapPublisher _capBus;\n\n    public PublishController(ICapPublisher capPublisher)\n    {\n        _capBus = capPublisher;\n    }\n\n    [Route(\"~/adonet/transaction\")]\n    public IActionResult AdonetWithTransaction()\n    {\n        using (var connection = new MySqlConnection(ConnectionString))\n        {\n            // Start a transaction with auto-commit enabled\n            using (var transaction = connection.BeginTransaction(_capBus, autoCommit: true))\n            {\n                // Your business logic...\n                _capBus.Publish(\"xxx.services.show.time\", DateTime.Now);\n            }\n        }\n        return Ok();\n    }\n\n    [Route(\"~/ef/transaction\")]\n    public IActionResult EntityFrameworkWithTransaction([FromServices] AppDbContext dbContext)\n    {\n        using (var trans = dbContext.Database.BeginTransaction(_capBus, autoCommit: true))\n        {\n            // Your business logic...\n            _capBus.Publish(\"xxx.services.show.time\", DateTime.Now);\n        }\n        return Ok();\n    }\n\n    [Route(\"~/publish/delay\")]\n    public async Task<IActionResult> PublishWithDelay()\n    {\n        // Publish a message with a 30-second delay\n        await _capBus.PublishDelayAsync(TimeSpan.FromSeconds(30), \"xxx.services.show.time\", DateTime.Now);\n        return Ok();\n    }\n}\n```\n\n### 4. Subscribe to Messages\n\n#### In a Controller Action\n\nAdd the `[CapSubscribe]` attribute to a controller action to subscribe to a topic.\n\n```csharp\npublic class SubscriptionController : Controller\n{\n    [CapSubscribe(\"xxx.services.show.time\")]\n    public void CheckReceivedMessage(DateTime messageTime)\n    {\n        Console.WriteLine($\"Message received: {messageTime}\");\n    }\n}\n```\n\n#### In a Business Logic Service\n\nIf your subscriber is not in a controller, the class must implement the `ICapSubscribe` interface.\n\n```csharp\nnamespace BusinessCode.Service\n{\n    public interface ISubscriberService\n    {\n        void CheckReceivedMessage(DateTime datetime);\n    }\n\n    public class SubscriberService : ISubscriberService, ICapSubscribe\n    {\n        [CapSubscribe(\"xxx.services.show.time\")]\n        public void CheckReceivedMessage(DateTime datetime)\n        {\n            // Handle the message\n        }\n    }\n}\n```\n\nRemember to register your service in `Startup.cs`:\n\n```csharp\npublic void ConfigureServices(IServiceCollection services)\n{\n    services.AddTransient<ISubscriberService, SubscriberService>();\n\n    services.AddCap(x =>\n    {\n        // ...\n    });\n}\n```\n\n#### Asynchronous Subscriptions\n\nFor async operations, your subscription method should return a `Task` and can accept a `CancellationToken`.\n\n```csharp\npublic class AsyncSubscriber : ICapSubscribe\n{\n    [CapSubscribe(\"topic.name\")]\n    public async Task ProcessAsync(Message message, CancellationToken cancellationToken)\n    {\n        await SomeOperationAsync(message, cancellationToken);\n    }\n}\n```\n\n#### Partial Topic Subscriptions\n\nGroup topic subscriptions by defining a partial topic on the class level. The final topic will be a combination of the class-level and method-level topics. In this example, the `Create` method subscribes to `customers.create`.\n\n```csharp\n[CapSubscribe(\"customers\")]\npublic class CustomersSubscriberService : ICapSubscribe\n{\n    [CapSubscribe(\"create\", isPartial: true)]\n    public void Create(Customer customer)\n    {\n        // ...\n    }\n}\n```\n\n#### Subscription Groups\n\nSubscription groups are similar to consumer groups in Kafka. They allow you to load-balance message processing across multiple instances of a service.\n\nBy default, CAP uses the assembly name as the group name. If multiple subscribers in the same group subscribe to the same topic, only one will receive the message (competing consumers). If they are in different groups, all will receive the message (fan-out).\n\nYou can specify a group directly in the attribute:\n\n```csharp\n[CapSubscribe(\"xxx.services.show.time\", Group = \"group1\")]\npublic void ShowTime1(DateTime datetime)\n{\n    // ...\n}\n\n[CapSubscribe(\"xxx.services.show.time\", Group = \"group2\")]\npublic void ShowTime2(DateTime datetime)\n{\n    // ...\n}\n```\n\nYou can also set a default group name in the configuration:\n\n```csharp\nservices.AddCap(x =>\n{\n    x.DefaultGroup = \"my-default-group\";  \n});\n```\n\n### Azure Service Bus Emulator Support\n\nThe [Azure Service Bus Emulator](https://learn.microsoft.com/en-us/azure/service-bus-messaging/overview-emulator) uses separate ports for AMQP messaging (5672) and the HTTP Admin API (5300). Because CAP uses a single connection string for both the `ServiceBusClient` (AMQP) and the `ServiceBusAdministrationClient` (HTTP), it cannot target both ports simultaneously.\n\nTo work around this, set `AutoProvision` to `false` to skip automatic creation of topics, subscriptions, and rules via the Admin API. You must pre-create the required entities in the emulator's configuration instead.\n\n```csharp\nservices.AddCap(x =>\n{\n    x.UseAzureServiceBus(opt =>\n    {\n        opt.ConnectionString = \"Endpoint=sb://localhost;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;\";\n        opt.AutoProvision = false;\n    });\n});\n```\n\n> **Note:** When `AutoProvision` is `false`, topics, subscriptions, and subscription filter rules must already exist before the application starts. This option is also useful when entities are managed externally (e.g., via Infrastructure as Code).\n\n## Dashboard\n\nCAP provides a real-time dashboard to view sent and received messages and their status.\n\n```shell\nPM> Install-Package DotNetCore.CAP.Dashboard\n```\n\nThe dashboard is accessible by default at `http://localhost:xxx/cap`. You can customize the path via options: `x.UseDashboard(opt => { opt.PathMatch = \"/my-cap\"; });`.\n\nFor distributed environments, the dashboard supports service discovery to view data from all nodes.\n- **Consul:** [View Consul config docs](https://cap.dotnetcore.xyz/user-guide/en/monitoring/consul/)\n- **Kubernetes:** Use the `DotNetCore.CAP.Dashboard.K8s` package. [View Kubernetes config docs](https://cap.dotnetcore.xyz/user-guide/en/monitoring/kubernetes/)\n\n## Contribute\n\nWe welcome contributions! Participating in discussions, reporting issues, and submitting pull requests are all great ways to help. Please read our [contributing guidelines](CONTRIBUTING.md) (we can create this file if it doesn't exist) to get started.\n\n### License\n\nCAP is licensed under the [MIT License](https://github.com/dotnetcore/CAP/blob/master/LICENSE.txt)."
  },
  {
    "path": "README.zh-cn.md",
    "content": "<p align=\"center\">\n  <img height=\"140\" src=\"https://raw.githubusercontent.com/dotnetcore/CAP/master/docs/content/img/logo.svg\">\n</p>\n\n# CAP 　　　　　　　　　　　　　　　　　　　　[English](https://github.com/dotnetcore/CAP/blob/master/README.md)\n[![Docs&Dashboard](https://github.com/dotnetcore/CAP/actions/workflows/deploy-docs-and-dashboard.yml/badge.svg?branch=master)](https://github.com/dotnetcore/CAP/actions/workflows/deploy-docs-and-dashboard.yml)\n[![AppVeyor](https://ci.appveyor.com/api/projects/status/v8gfh6pe2u2laqoa?svg=true)](https://ci.appveyor.com/project/yang-xiaodong/cap)\n[![NuGet](https://img.shields.io/nuget/v/DotNetCore.CAP.svg)](https://www.nuget.org/packages/DotNetCore.CAP/)\n[![NuGet Preview](https://img.shields.io/nuget/vpre/DotNetCore.CAP.svg?label=nuget-pre)](https://www.nuget.org/packages/DotNetCore.CAP/)\n[![Member project of .NET Core Community](https://img.shields.io/badge/member%20project%20of-NCC-9e20c9.svg)](https://github.com/dotnetcore)\n[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/dotnetcore/CAP/master/LICENSE.txt)\n\nCAP 是一个基于 .NET Standard 的 C# 库，它是一种处理分布式事务的解决方案，同样具有 EventBus 的功能，它具有轻量级、易使用、高性能等特点。\n\n你可以在这里 [CAP docs](http://cap.dotnetcore.xyz) 看到更多详细资料。\n\n你可以在这里看到 [CAP 视频教程](https://www.cnblogs.com/savorboard/p/cap-video-1.html)，学习如何在项目中集成CAP。\n\n在我们构建 SOA 或者 微服务系统的过程中，我们通常需要使用事件来对各个服务进行集成，在这过程中简单的使用消息队列并不能保证数据的最终一致性，\nCAP 采用的是和当前数据库集成的本地消息表的方案来解决在分布式系统互相调用的各个环节可能出现的异常，它能够保证任何情况下事件消息都是不会丢失的。\n\n你同样可以把 CAP 当做 EventBus 来使用，CAP提供了一种更加简单的方式来实现事件消息的发布和订阅，在订阅以及发布的过程中，你不需要继承或实现任何接口。\n\n这是 CAP 集在ASP.NET Core 微服务架构中的一个示意图：\n\n## 架构预览\n\n![architecture.png](https://raw.githubusercontent.com/dotnetcore/CAP/master/docs/content/img/architecture-new.png)\n\n> CAP 实现了 [eShop 电子书](https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/multi-container-microservice-net-applications/subscribe-events#designing-atomicity-and-resiliency-when-publishing-to-the-event-bus) 中描述的发件箱模式\n\n## Getting Started\n\n### NuGet \n\n你可以运行以下下命令在你的项目中安装 CAP。\n\n```\nPM> Install-Package DotNetCore.CAP\n```\n\nCAP 支持主流的消息队列作为传输器，你可以按需选择下面的包进行安装：\n\n```\nPM> Install-Package DotNetCore.CAP.Kafka\nPM> Install-Package DotNetCore.CAP.RabbitMQ\nPM> Install-Package DotNetCore.CAP.AzureServiceBus\nPM> Install-Package DotNetCore.CAP.AmazonSQS\nPM> Install-Package DotNetCore.CAP.NATS\nPM> Install-Package DotNetCore.CAP.RedisStreams\nPM> Install-Package DotNetCore.CAP.Pulsar\n```\n\nCAP 提供了主流数据库作为存储，你可以按需选择下面的包进行安装：\n\n```\n// 按需选择安装你正在使用的数据库\nPM> Install-Package DotNetCore.CAP.SqlServer\nPM> Install-Package DotNetCore.CAP.MySql\nPM> Install-Package DotNetCore.CAP.PostgreSql\nPM> Install-Package DotNetCore.CAP.MongoDB\n```\n\n### Configuration\n\n首先配置CAP到 Startup.cs 文件中，如下：\n\n```c#\npublic void ConfigureServices(IServiceCollection services)\n{\n    ......\n\n    services.AddDbContext<AppDbContext>();\n\n    services.AddCap(x =>\n    {\n        //如果你使用的 EF 进行数据操作，你需要添加如下配置：\n        x.UseEntityFramework<AppDbContext>();  //可选项，你不需要再次配置 x.UseSqlServer 了\n\t\t\n        //如果你使用的ADO.NET，根据数据库选择进行配置：\n        x.UseSqlServer(\"数据库连接字符串\");\n        x.UseMySql(\"数据库连接字符串\");\n        x.UsePostgreSql(\"数据库连接字符串\");\n\n        //如果你使用的 MongoDB，你可以添加如下配置：\n        x.UseMongoDB(\"ConnectionStrings\");  //注意，仅支持MongoDB 4.0+集群\n\t\n        //CAP支持 RabbitMQ、Kafka、AzureServiceBus、AmazonSQS 等作为MQ，根据使用选择配置：\n        x.UseRabbitMQ(\"ConnectionStrings\");\n        x.UseKafka(\"ConnectionStrings\");\n        x.UseAzureServiceBus(\"ConnectionStrings\");\n        x.UseAmazonSQS();\n    });\n}\n\n```\n\n### 发布\n\n在 Controller 中注入 `ICapPublisher` 然后使用 `ICapPublisher` 进行消息发送。\n\n> 版本 7.0+ 支持发送延迟消息。\n\n```c#\n\npublic class PublishController : Controller\n{\n    private readonly ICapPublisher _capBus;\n\n    public PublishController(ICapPublisher capPublisher)\n    {\n        _capBus = capPublisher;\n    }\n    \n    //不使用事务\n    [Route(\"~/without/transaction\")]\n    public IActionResult WithoutTransaction()\n    {\n        _capBus.Publish(\"xxx.services.show.time\", DateTime.Now);\n\n        // Publish delay message\n        _capBus.PublishDelayAsync(TimeSpan.FromSeconds(delaySeconds), \"xxx.services.show.time\", DateTime.Now);\n\t\n        return Ok();\n    }\n\n    //Ado.Net 中使用事务，自动提交\n    [Route(\"~/adonet/transaction\")]\n    public IActionResult AdonetWithTransaction()\n    {\n        using (var connection = new MySqlConnection(ConnectionString))\n        {\n            using (var transaction = connection.BeginTransaction(_capBus, autoCommit: true))\n            {\n                //业务代码\n\n                _capBus.Publish(\"xxx.services.show.time\", DateTime.Now);\n            }\n        }\n        return Ok();\n    }\n\n    //EntityFramework 中使用事务，自动提交\n    [Route(\"~/ef/transaction\")]\n    public IActionResult EntityFrameworkWithTransaction([FromServices]AppDbContext dbContext)\n    {\n        using (var trans = dbContext.Database.BeginTransaction(_capBus, autoCommit: true))\n        {\n            //业务代码\n\n            _capBus.Publish(\"xxx.services.show.time\", DateTime.Now);\n        }\n        return Ok();\n    }\n}\n\n```\n\n### 订阅\n\n**Action Method**\n\n在 Action 上添加 CapSubscribeAttribute 来订阅相关消息。\n\n```c#\npublic class PublishController : Controller\n{\n    [CapSubscribe(\"xxx.services.show.time\")]\n    public void CheckReceivedMessage(DateTime datetime)\n    {\n        Console.WriteLine(datetime);\n    }\n}\n\n```\n\n**Service Method**\n\n如果你的订阅方法没有位于 Controller 中，则你订阅的类需要继承 `ICapSubscribe`：\n\n```c#\n\nnamespace xxx.Service\n{\n    public interface ISubscriberService\n    {\n        void CheckReceivedMessage(DateTime datetime);\n    }\n\n    public class SubscriberService: ISubscriberService, ICapSubscribe\n    {\n        [CapSubscribe(\"xxx.services.show.time\")]\n        public void CheckReceivedMessage(DateTime datetime)\n        {\n        }\n    }\n}\n\n```\n\n然后在 Startup.cs 中的 `ConfigureServices()` 中注入你的  `ISubscriberService` 类\n\n```c#\npublic void ConfigureServices(IServiceCollection services)\n{\n    services.AddTransient<ISubscriberService,SubscriberService>();\n\t\n    services.AddCap(x=>{});\n}\n```\n\n#### 异步订阅\n\n你能够实现异步订阅。订阅方法应返回 `Task` 并接收 `CancellationToken` 作为参数。\n\n```c#\npublic class AsyncSubscriber : ICapSubscribe\n{\n    [CapSubscribe(\"name\")]\n    public async Task ProcessAsync(Message message, CancellationToken cancellationToken)\n    {\n        await SomeOperationAsync(message, cancellationToken);\n    }\n}\n```\n\n#### 使用多部分订阅名\n\n要在类级别对订阅的Topic进行分组，您可以将在方法上的订阅设置为部分订阅。 消息队列上的订阅将是类上定义的topic加上方法上定义的topic的拼合。 \n在下面的示例中，当收到关于 `customers.create` 的消息时，将调用 `Create(..)` 函数\n\n```c#\n[CapSubscribe(\"customers\")]\npublic class CustomersSubscriberService : ICapSubscribe\n{\n    [CapSubscribe(\"create\", isPartial: true)]\n    public void Create(Customer customer)\n    {\n    }\n}\n```\n\n#### 订阅者组\n\n订阅者组的概念类似于 Kafka 中的消费者组，它和消息队列中的广播模式相同，用来处理不同微服务实例之间同时消费相同的消息。\n\n当CAP启动的时候，她将创建一个默认的消费者组，如果多个相同消费者组的消费者消费同一个Topic消息的时候，只会有一个消费者被执行。\n相反，如果消费者都位于不同的消费者组，则所有的消费者都会被执行。\n\n相同的实例中，你可以通过下面的方式来指定他们位于不同的消费者组。\n\n```C#\n\n[CapSubscribe(\"xxx.services.show.time\", Group = \"group1\" )]\npublic void ShowTime1(DateTime datetime)\n{\n}\n\n[CapSubscribe(\"xxx.services.show.time\", Group = \"group2\")]\npublic void ShowTime2(DateTime datetime)\n{\n}\n\n```\n\n`ShowTime1` 和 `ShowTime2` 将被同时调用。\n\nPS，你可以通过下面的方式来指定默认的消费者组名称：\n\n```C#\nservices.AddCap(x =>\n{\n    x.DefaultGroup = \"default-group-name\";  \n});\n\n```\n\n### Dashboard\n\nCAP 同时提供了仪表盘（Dashboard）功能，你可以很方便的查看发出和接收到的消息。 除此之外，你还可以在仪表盘中实时查看发送或者接收到的消息。 \n\n使用以下命令安装 Dashboard：\n\n```\nPM> Install-Package DotNetCore.CAP.Dashboard\n```\n\n在分布式环境中，仪表盘内置集成了 [Consul](http://consul.io) 作为节点的注册发现，同时实现了网关代理功能，你同样可以方便的查看本节点或者其他节点的数据，它就像你访问本地资源一样。\n\n[查看 Consul 配置文档](https://cap.dotnetcore.xyz/user-guide/en/monitoring/consul)\n\n如果你的服务部署在Kubernetes中，请使用我们为Kubernetes专门提供的发现包。\n\n```\nPM> Install-Package DotNetCore.CAP.Dashboard.K8s\n```\n\n[查看 Kubernetes 配置文档](https://cap.dotnetcore.xyz/user-guide/en/monitoring/kubernetes/)\n\n仪表盘默认的访问地址是：[http://localhost:xxx/cap](http://localhost:xxx/cap)，你可以在`d.MatchPath`配置项中修改`cap`路径后缀为其他的名字。\n\n## 贡献\n\n贡献的最简单的方法之一就是是参与讨论和讨论问题（issue）。你也可以通过提交的 Pull Request 代码变更作出贡献。\n\n### License\n\nMIT\n"
  },
  {
    "path": "appveyor.yml",
    "content": "version: '{build}'\nos: Visual Studio 2022\nenvironment:\n  BUILDING_ON_PLATFORM: win\n  BuildEnvironment: appveyor\n  Cap_MySql_ConnectionString: Server=localhost;Database=cap_test;Uid=root;Pwd=Password12!;Allow User Variables=True;SslMode=Required\n  DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true\n  DOTNET_NOLOGO: true\ninstall:\n  - ps: |\n      Invoke-WebRequest -Uri 'https://dot.net/v1/dotnet-install.ps1' -UseBasicParsing -OutFile $env:TEMP\\dotnet-install.ps1\n      & $env:TEMP\\dotnet-install.ps1 -Architecture x64 -Version '10.0.100' -InstallDir \"$env:ProgramFiles\\dotnet\"\ninit:\n  - ps: Start-Service MySQL80\nbefore_build:\n  - ps: |\n      dotnet tool install --global FlubuCore.Tool --version 8.0.0\n      # optional: expose tools path for this step if needed later\n      $toolPath = Join-Path $env:USERPROFILE \".dotnet\\tools\"\n      if (Test-Path $toolPath) { $env:PATH = \"$toolPath;$env:PATH\" }\nbuild_script:\n  - ps: flubu\ntest: off\nartifacts:\n  - path: artifacts/**\ndeploy:\n  provider: NuGet\n  on:\n    appveyor_repo_tag: true\n  api_key:\n    secure: Q1wqF+LkkmABBflkQILr0cJidpEsD/ov1qoGrWGh9LdPZTZytIaxo+98mGndD/Ip\n  skip_symbols: false\n  artifact: '/artifacts\\/.+\\.s?nupkg/'\n"
  },
  {
    "path": "build/BuildScript.Util.cs",
    "content": "﻿using System;\n\nnamespace BuildScript\n{\n    public partial class BuildScript\n    {\n        public string CreateStamp()\n        {\n            var seconds = (long)(DateTime.UtcNow - new DateTime(2017, 1, 1)).TotalSeconds;\n            return seconds.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "build/BuildScript.Version.cs",
    "content": "﻿using System.IO;\nusing System.Xml;\nusing FlubuCore.Context;\nusing FlubuCore.Scripting.Attributes;\n\nnamespace BuildScript\n{\n    [Reference(\"System.Xml.XmlDocument, System.Xml, Version=4.0.0.0, Culture=neutral, publicKeyToken=b77a5c561934e089\")]\n    public partial class BuildScript\n    {\n        public BuildVersion FetchBuildVersion(ITaskContext context)\n        {\n            var content = File.ReadAllText(RootDirectory.CombineWith(\"build/version.props\"));\n\n            XmlDocument doc = new XmlDocument();\n            doc.LoadXml(content);\n\n            var versionMajor = doc.DocumentElement!.SelectSingleNode(\"/Project/PropertyGroup/VersionMajor\")!.InnerText;\n            var versionMinor = doc.DocumentElement.SelectSingleNode(\"/Project/PropertyGroup/VersionMinor\")!.InnerText;\n            var versionPatch = doc.DocumentElement.SelectSingleNode(\"/Project/PropertyGroup/VersionPatch\")!.InnerText;\n            var versionQuality = doc.DocumentElement.SelectSingleNode(\"/Project/PropertyGroup/VersionQuality\")!.InnerText;\n            versionQuality = string.IsNullOrWhiteSpace(versionQuality) ? null : versionQuality;\n\n            var suffix = versionQuality;\n\n            var isCi = false;\n            var isTagged = false;\n            if (!context.BuildServers().IsLocalBuild)\n            {\n                isCi = true;\n                var isTagAppveyor = context.BuildServers().AppVeyor().IsTag;\n                if (context.BuildServers().RunningOn == BuildServerType.AppVeyor && isTagAppveyor ||\n                    context.BuildServers().RunningOn == BuildServerType.TravisCI && string.IsNullOrWhiteSpace(context.BuildServers().Travis().TagName))\n                {\n                    isTagged = true;\n                }\n            }\n\n            if (!isTagged)\n            {\n                suffix += (isCi ? \"preview-\" : \"dv-\") + CreateStamp();\n            }\n\n            suffix = string.IsNullOrWhiteSpace(suffix) ? null : suffix;\n\n            var version = new BuildVersion\n            {\n                Major = int.Parse(versionMajor),\n                Minor = int.Parse(versionMinor),\n                Patch = int.Parse(versionPatch),\n                Quality = versionQuality,\n                Suffix = suffix\n            };\n\n            return version;\n        }\n    }\n}\n"
  },
  {
    "path": "build/BuildScript.cs",
    "content": "﻿using System.Collections.Generic;\nusing FlubuCore.Context;\nusing FlubuCore.Context.Attributes.BuildProperties;\nusing FlubuCore.IO;\nusing FlubuCore.Scripting;\nusing FlubuCore.Scripting.Attributes;\n\nnamespace BuildScript\n{\n    [Include(\"./build/BuildVersion.cs\")]\n    public partial class BuildScript : DefaultBuildScript\n    {\n        [FromArg(\"c|configuration\")]\n        [BuildConfiguration]\n        public string Configuration { get; set; } = \"Release\";\n\n        [SolutionFileName] public string SolutionFileName { get; set; } = \"CAP.sln\";\n\n        protected BuildVersion BuildVersion { get; set; }\n\n        protected string ArtifactsDir => RootDirectory.CombineWith(\"artifacts\");\n        \n        protected List<FileFullPath> ProjectFiles { get; set; }\n\n        protected List<FileFullPath> TestProjectFiles { get; set; }\n\n        protected override void BeforeBuildExecution(ITaskContext context)\n        {\n            BuildVersion = FetchBuildVersion(context);\n            TestProjectFiles = context.GetFiles(RootDirectory.CombineWith(\"test\"), \"*/*.csproj\");\n            ProjectFiles = context.GetFiles(RootDirectory.CombineWith(\"src\"), \"*/*.csproj\");\n        }\n\n        protected override void ConfigureTargets(ITaskContext context)\n        {\n            var clean = context.CreateTarget(\"Clean\")\n                .SetDescription(\"Cleans the output of all projects in the solution.\")\n                .AddCoreTask(x => x.Clean()\n                    .AddDirectoryToClean(ArtifactsDir, true));\n\n            var restore = context.CreateTarget(\"Restore\")\n                .SetDescription(\"Restores the dependencies and tools of all projects in the solution.\")\n                .DependsOn(clean)\n                .AddCoreTask(x => x.Restore());\n\n            var build = context.CreateTarget(\"Build\")\n                .SetDescription(\"Builds all projects in the solution.\")\n                .DependsOn(restore)\n                .AddCoreTask(x => x.Build()\n                    .InformationalVersion(BuildVersion.VersionWithSuffix()));\n\n            var tests = context.CreateTarget(\"Tests\")\n                .SetDescription(\"Runs all Cap tests.\")\n                .ForEach(TestProjectFiles,\n                    (projectFile, target) =>\n                    {\n                        target.AddCoreTask(x => x.Test()\n                            .Project(projectFile)\n                            .NoBuild());\n                    });\n\n          var pack = context.CreateTarget(\"Pack\")\n              .SetDescription(\"Creates nuget packages for Cap.\")\n                .ForEach(ProjectFiles, (projectFile, target) =>\n                {\n                    target.AddCoreTask(x => x.Pack()\n                        .NoBuild()\n                        .Project(projectFile)\n                        .IncludeSymbols()\n                        .VersionSuffix(BuildVersion.Suffix)\n                        .OutputDirectory(ArtifactsDir));\n                });\n\n          context.CreateTarget(\"Default\")\n              .SetDescription(\"Runs all targets.\")\n              .SetAsDefault()\n              .DependsOn(clean, restore, build, tests, pack);\n        }\n    }\n}\n"
  },
  {
    "path": "build/BuildScript.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|AnyCPU'\">\n    <NoWarn>1701;1702;NU1903</NoWarn>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|AnyCPU'\">\n    <NoWarn>1701;1702;NU1903</NoWarn>\n  </PropertyGroup>\n \n  <ItemGroup>\n    <None Remove=\"version.props\" />\n  </ItemGroup>\n\n  <ItemGroup>\n\t  <PackageReference Include=\"FlubuCore\" Version=\"9.0.0\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "build/BuildVersion.cs",
    "content": "﻿namespace BuildScript\n{\n    public class BuildVersion\n    {\n        public int Major { get; init; }\n\n        public int Minor { get; init; }\n\n        public int Patch { get; init; } \n\n        public string Quality { get; init; }\n\n        public string Suffix { get; set; }\n\n        public string VersionWithoutQuality()\n        {\n            return $\"{Major}.{Minor}.{Patch}\";\n        }\n\n        public string Version()\n        {\n            return VersionWithoutQuality() + (Quality == null ? string.Empty : $\"-{Quality}\");\n        }\n\n        public string VersionWithSuffix()\n        {\n            return Version() + (Suffix == null ? string.Empty : $\"-{Suffix}\");\n        }\n    }\n}\n"
  },
  {
    "path": "build/version.props",
    "content": "<Project>\n\t<PropertyGroup>\n\t\t<VersionMajor>10</VersionMajor>\n\t\t<VersionMinor>0</VersionMinor>\n\t\t<VersionPatch>2</VersionPatch>\n\t\t<VersionQuality></VersionQuality>\n\t\t<VersionPrefix>$(VersionMajor).$(VersionMinor).$(VersionPatch)</VersionPrefix>\n\t</PropertyGroup>\n</Project>\n"
  },
  {
    "path": "code-of-conduct.md",
    "content": "# MEMBER CODE OF CONDUCT\n\nThe .NET Core Community (NCC) was created to doster an open, innovative, inclusive and welcoming community around open source .NET/.NET Core. To clarify expected behaviour in our communities we have adopted the [Contributor Covenant](contributor-covenant.org). This code of conduct has been adopted by [many other open source communities](contributor-covenant.org/adopters) and we feel it expresses our values well.\n\n### Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n### Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n- Using welcoming and inclusive language\n- Being respectful of differing viewpoints and experiences\n- Gracefully accepting constructive criticism\n- Focusing on what is best for the community\n- Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n- The use of sexualized language or imagery and unwelcome sexual attention or advances\n- Trolling, insulting/derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others’ private information, such as a physical or electronic address, without explicit permission\n- Other conduct which could reasonably be considered inappropriate in a professional setting\n\n### Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n### Scope\n\nThis Code of Conduct applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n### Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [dotnet-community@outlook.com](dotnet-community@outlook.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project’s leadership.\n\n### Attribution\n\nThis Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n"
  },
  {
    "path": "docs/content/CNAME",
    "content": "cap.dotnetcore.xyz"
  },
  {
    "path": "docs/content/about/contact-us.md",
    "content": "---\nhide:\n  - feedback\n---\n\n# Contact Us\n\n## Authors\n\n* Author: [@yang-xiaodong](https://github.com/yang-xiaodong)\n* Email: yangxiaodong1214@126.com\n* Blogs: https://savorboard.cnblogs.com\n\n## NCC Organization\n\n* Email: dotnetcn@outlook.com\n* Twitter: https://twitter.com/ncc_community\n* Weibo: https://weibo.com/dotnetcore\n\n\n"
  },
  {
    "path": "docs/content/about/license.md",
    "content": "---\nhide:\n  - feedback\n---\n\n# License\n\n**MIT License**\n\nCopyright (c) 2016 - 2024 Savorboard\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "docs/content/about/release-notes.md",
    "content": "---\nhide:\n  - feedback\n---\n\n# Release Notes\n\n## Version 8.2.0 (Jun 23, 2024)\n\n**Features:**\n- Add support CustomHeadersBuilder option for NATS. (#1519)\n- Add GroupConcurrent option for [CapSubscribe] to support subscriber concurrent execution. (#1537)\n- Add option for controlling reponse from CapHeader. (#1541)\n- Improvements to the \"EnablePublishParallelSend\" option to \"true\" will put tasks into the .NET thread pool in batches. (#1540)\n\n**Bug Fixed:**\n- Fixed issue where CapTransaction was not disposed when the transaction failed for Sql Server. (#1521)\n- Fixed NATS reconnection publish issue after restarting server. (#1542)\n\n**What's Changed:**\n- Upgrade dashboard npm package to vue2 latest minor version.\n- Upgrade Ngpsql to 8.0.3 to fix \"Npgsql vulnerable to SQL Injection via Protocol Message Size Overflow\".\n- Simplify code using deconstruction. by @xiangxiren in #1533\n\n## Version 8.1.2 (May 7, 2024)\n\n**Bug Fixed:**\n* Fixed publish exception when event outside of transaction finishing scope. (#1521) Thanks @NikolozGob\n* Fixed PublishDelay synchronization method did not wait internally.\n\n## Version 8.1.1 (Apr 21, 2024)\n\n**Features:**\n- Add more granular option for AzureServiceBus. (#1514)\n- Add new options SubscriberParallelExecuteThreadCount,SubscriberParallelExecuteBufferFactor to better support parallel execte subscriber. (#1513)\n- Delete obsolete option CustomerHeader.\n\n## Version 8.0.0 (Dec 14, 2023)\n\n**Breaking Changes**\nRemoved `DefaultAuthenticationScheme`, `UseChallengeOnAuth`, `DefaultChallengeScheme` and `AuthorizationPolicy` options of DotNetCore.CAP.Dashboard.\nNow CAP dashboard auth/authz mechanism to leverage the \"ASP.NET Core\" way of doing it, see #1428.\n\n* Streamlined auth via asp.net middlewares. (#1434) Thanks @mviegas\n  \n**Features:**\n\n* Fully Support .NET 8.\n* Add `FallbackWindowLookbackSeconds` option to configure the retry processor to pick up the backtrack time window for Scheduled or Failed status messages. (#1455) Thanks @apatozi\n* Update IConsumerRegister.Default.cs to make dispose thread safe. (#1438) Thanks @blashbul\n* Compatible with .NET 8's dependency injection KeyedService. (#1436) Thanks @EashShow\n* Add virtual method to custom delay backtrack time window during delayed publishing large messges. (#1429) Thanks @PoteRii\n\n**Bug Fixed:**\n\n* Fixed message infinite retry of messages after subscriber is removed. (#1456) Thanks @bschwehn\n* Fixed open telemetry context lost on consumer retry and Baggage Propagation. (#1452) Thanks @bschwehn\n* Fixed NATS do not handle reconnect if the nats server is forcibly shutdown and then restarted. (#1449) Thanks @davidterins\n* Fixed outbox pattern messages does not recovery when using DotNetCore.CAP.InMemoryStorage. (#1439) Thanks @davidterins\n* Fixed open telemetry subscriber thows null reference when using azure service bus without connection string. (#1432) Thanks @demorgi\n* Fixed double registration of event handler for azure service bus. (#1427) Thanks @demorgi\n* Fixed publish delay message not working in sql server transaction. (#1422) Thanks @xiangxiren\n\n## Version 7.2.2 (Nov 1, 2023)\n\n**Features:**\n\n* NATS support consumer config DeliverPolicy, default to New. (#1404)\n* Be able to configure if to subscribe to custom producer topic. (#1409)  @demorgi\n  \n**Bug Fixed:**\n\n* Try to fixes RabbitMQ basicConsume TimeOutException. (#1405) @yang-xiaodong\n* Change MongoDb index from descending to ascending. (#1415) Thanks @ustaserdar\n* Fixed parent span for \"Event Persistence\" activity trace. (#1407) Thanks @blashbul\n* Fixed OpenTelemetry Dynatrace IsRemote flag. (#1402) Thanks @phmonte\n* Mark Mongo time serialized to local instance time by default. (#1400) \n* Fixed k8s dashboard meta query error in standalone mode. @yang-xiaodong\n* Azure Service Bus, consumer fails if subscription has session enabled. (#1396, #1397)  Thanks @demorgi\n\n## Version 7.2.1 (Sep 8, 2023)\n\n**Features:**\n\n*  The options `EnableConsumerPrefetch` and `UseDispatchingPerGroup` will work together without interference. (#1399)\n\n**Bug Fixed:**\n\n* Fixed SqlServer sql case sensitive in dashboard query.  (#1389)\n* Fixed Redis endpoint is null in DotNetCore.CAP.OpenTelemetry. (#1384)\n  \n\n## Version 7.2.0 (Jul 30, 2023)\n\n**Breaking Changes**\n\n* Remove `ProducerThreadCount` configuration option. Now automatically send task managed by the .NET thread pool. (#1380)\n* Change the SnowflakeId from static singleton to dependency injection singleton. (#1322)\n\n**Features:**\n\n* Add support for kubernetes discovery in dashboard. (#1362) \n* Message send task and consumer execute task managed by .net thread pool. (#1380)\n* Upgrade dependencies of NuGet packages.\n\n**Bug Fixed:**\n\n* Fixed BasicQosOptions not working as expected for RabbitMQ transport. (#1318)\n* Revert BeginTransactionAsync support. (#1376)\n* Fixed SqlServer transaction rollback message still sent out.  (#1378)\n* \n## Version 7.1.4 (Jun 17, 2023)\n\n**Features:**\n\n* Add suppport `AutoDeleteOnIdle` option for Azure Service Bus. (#1350) Thanks @StevenDevooght\n\n**Bug Fixed:**\n\n* Keep the originall stack when consumer exception occurs. (#1341) Thanks @tomyangOK\n* Fixed multiple invocations caused when the retry processor exceeded the `FailedRetryInterval`. (#1359) Thanks @li-zheng-hao\n* Fixed thread blocking when enable `UseDispatchingPerGroup` option. (#1356) Thanks @sampsonye @li-zheng-hao\n* \n## Version 7.1.3 (May 17, 2023)\n\n**Features:**\n\n* Allow Explicit to set AllowAnonymous for the dashboard API. (#1335)\n* Update dashboard UI style\n* Add Cancellation token for BeginTransactionAsync. (#1317)  Thanks @denis-tsv\n\n**Bug Fixed:**\n\n* Fixed postgresql AcquireLockAsync sql error. (#1320) Thanks @guochen2\n* Fixed redis transport order pool connections non-lazy created connections. (#1332) Thanks @MahmoudSamir101\n* Fixed mysql 8.0 storage skip locked not available bug. (#1330) Thanks @yang-xiaodong\n\n## Version 7.1.2 (Apr 25, 2023)\n\n**Bug Fixed:**\n\n* Optimizing consumer duplicate detection warning logs. (#1314)\n* Fixes NATS consumption repeat when multiple consumer threads.\n* Fixes NATS transport infinity reconnect race condition. (#1311)\n\n## Version 7.1.1 (Apr 7, 2023)\n\n**Features:**\n\n* Add support topic config for kafka. (#1303)\n* Log in to dashboard with JWT authentication. (#1306) \n\n**Bug Fixed:**\n\n* Fixed sqlserver character string convert to datetime2 exception. (#1302)\n* Fixed dashboard consul node proxy switch bug. (#1307)\n\n## Version 7.1.0 (Mar 5, 2023)\n\n**Features:**\n\n* Add option to support distributed locks for retry processor. (#1272) Thanks @li-zheng-hao\n* Add option to support set BasicQos for RabbitMQ. (#1267) Thanks @nunorelvao\n* Add option to set queue type for RabbitMQ. (#1281) Thanks @PaulCousinsTTEducation\n* Add support publish to mutiple topics for Azure Service Bus. (#1283) Thanks @jonekdahl @mviegas\n\n**Bug Fixed:**\n\n* Fixed dashboard re-execute message throw null exception for MongoDB. (#1279) Thanks @cagataykiziltan\n\n## Version 7.0.3 (Feb 2, 2023)\n\n**Features:**\n\n* Add SQL Filters option on topic subscribtion for AzureServiceBus. (#1263) Thanks @giorgilekveishvili-meama\n* Add EF BeginTransaction extensions overload with isolationlevel and async version. (#1266) @xshaheen\n\n**Bug Fixed:**\n\n* Fixed dashboard re-execute message throw null exception for SqlServer and Postgres. (#1259) Thanks @coolyuwk\n\n## Version 7.0.2 (Jan 9, 2023)\n\n**Features:**\n\n* Change AzureServiceBus nuget package from Microsoft.Azure.ServiceBus to Azure.Messaging.ServiceBus. (https://github.com/dotnetcore/CAP/pull/1253)\n\n**Bug Fixed:**\n\n* Fixed redis streams json serialize exception. (#1254)\n* Fixed dashboard route in balzor server app. (not support wasm) (#1244)\n\n## Version 7.0.1 (2022-12-16)\n\n**Bug Fixed:**\n\n* Fixed dashboard not working in balzor app. (#1244)\n* Fixed error when published Winform with 'Produce Single File'. (#1245)\n\n## Version 7.0.0 (2022-11-27)\n\n**Breaking Changes:**\n\n* `SubscribeFilter` method to asynchronous.\n* `IConsumerClient` interface `OnMessage` and `OnLog` is from event to delegate.\n\n**Features:**\n\n* Performance improvement\n* Add support publish delay message. (#1237)\n* Dashbord support viewing and immediately publish for delayed messages.\n* Add support for metrics diagnostics. (#1230)\n* Dashboard support real-time metric graph viewing.\n* Add support manual start/stop CAP process. (#1238)\n* Add EnableConsumerPrefetch option of consumer. (#1240)\n* Add PublishConfirms options for RabbitMQ.\n\n**Others:**\n\n* Change framework target from netstandard to net6.\n* Upgrade NuGet to the latest version.\n\n**Bug Fixed:**\n\n* RabbitMQ cluster connection failed without using default ports. (#1232)\n\n## Version 6.2.1 (2022-10-15)\n\n**Bug Fixed:**\n\n* Fixed EnvironmentVariableTarget.Machine only supported on windows. (#1220) Thanks @cuibty\n* Fixed RedisStream TryGetOrCreateStreamGroupAsync to create ConsumerGroup when not found. (#1212) Thanks @mlatoszek\n\n## Version 6.2.0 (2022-09-19)\n\n**Features:**\n\n* Add Chinese support for dashboard localization.  (#1157)  Thanks @tetris1128\n* Make DbTransaction property virtual for extend of CapTransactionBase. (#1179)  @yang-xiaodong \n* Add logs for duplicate subscriber in same group. (#1186)  @yang-xiaodong \n* Record the Instance Id in the executed received messages. (#1187)  @yang-xiaodong \n\n**Bug Fixed:**\n\n* SnowflakeId excludes virtual and loopback and non-working NICs. (#1163)  Thanks @xiatiandegaga\n* Fixed the health check could not get the status correctly when RabbitMQ lost connection and quickly recovered. (#1193) Thanks @rpenha\n* Fixed dashboard gateway proxy request missing QueryString (#1168) Thanks @wwwu\n* Fixed the disconnect detection of RabbitMQ connection abnormality. (#1178)\n* Fixed Mongo queries not returning results when a element convention name is registered. (#1193) Thanks @rpenha\n* Fixed subscriber lookup in scoped lifecycle of factory mode. (#1204) Thanks @sampsonye\n  \n## Version 6.1.0 (2022-06-10)\n\n**Features:**\n\n* Optimize snowflake algorithm. (#1065)  Thanks @Allen-dududu\n* Add authorization policy option feature to CAP dashboard. (#1113)  Thanks @albertopm19\n* Added support of ScheduledEnqueueTimeUtc for AzureServiceBus transport. (#1137)  Thanks @webinex\n* Add option to configure failed messages expiration term. (#1142) Thanks @dima-zhemkov\n\n**Bug Fixed:**\n\n* Fixed sequence validation error when both enable Challenge and Auth of dashboard authentication. (#1097)\n* Used concurrentdictionary since PublishedMessages and ReceivedMessages are public and accessed from various places. (#1104) Thanks @wakiter\n* Fixed the health check could not get the status correctly when RabbitMQ lost connection and quickly recovered. (#1140)\n* Fixed date file format bug when retrying query from database. (#1143)\n* Change reading/creating streams and consumer groups to handle non idempotent operations. (#1150) Thanks @MahmoudSamir101\n\n## Version 6.0.1 (2022-02-15)\n\n**Bug Fixed:**\n\n* Fixed kafka consume excepiton for GroupLoadInProress errcode (#1085)\n* Fixed deserialization exception when message body is empty byte array. (#1087)\n* Fixed dashboard authentication challenge bug. (#1077)\n  \n## Version 6.0.0 (2022-01-06)\n\n**Features:**\n\n* Fully support .NET 6.\n* Add support for OpenTelemetry. (#885)\n* Improve support for NATS JetStream wildcard topic. (#1047)\n* Add support customer header options for Azure Service Bus. (#1063) Thanks [@Mateus Viegas](https://github.com/mviegas)\n\n## Version 5.2.0 (2021-11-12)\n\n**Features:**\n\n* Add support for NATS JetStream. (#983)\n* Add support for Apache Pulsar. (#610)\n* Add possibility to process messages for each consumer group indepedently. (#1027)\n\n**Bug Fixed:**\n\n* Fixed message content of bigint type cannot be displayed correctly in dashboard. (#1028)\n* Fixed unobserved tasks of async method calls in Amazon SQS. (#1033)\n* Fixed RabbitMQ federation plugin message header object values cause exceptions. (#1036)\n\n## Version 5.1.2 (2021-07-26)\n\n**Bug Fixed:**\n\n* Fixed consumer register cancellation token source null referencee bug. (#952)\n* Fixed redis streams transport cluster keys cross-hashslot bug. (#944)\n\n\n## Version 5.1.1 (2021-07-09)\n\n**Features:**\n\n* Improve flow control for message cache of in memory. (#935)\n* Add cancellation token support to subscribers. (#912)\n* Add pathbase options for dashboard. (#901)\n* Add custom authorization scheme support for dashboard. (#906)\n\n**Bug Fixed:**\n\n* Fixed mysql connect timeout expired bug. (#931)\n* Fixed consul health check path invalid bug. (#921)\n* Fixed mongo dashboard query bug. (#909)\n\n## Version 5.1.0 (2021-06-07)\n\n**Features:**\n\n* Add configure options for json serialization. (#879)\n* Add Redis Streams transport support. (#817)\n* New dashboard build with vue. (#880)\n* Add subscribe filter support. (#894)\n\n**Bug Fixed:**\n\n* Fixed use CapEFDbTransaction to get dbtransaction extension method bug. (#868)\n* Fixed pending message has not been deleted from buffer list in SQL Server. (#889)\n* Fixed dispatcher processing when storage message exception bug. (#900)\n\n\n## Version 5.0.3 (2021-05-14)\n\n**Bug Fixed:**\n\n* Fix the bug of getting db transaction through the IDbContextTransaction for SQLServer. (#867)\n* Fix RabbitMQ Connection close forced. (#861)\n\n## Version 5.0.2 (2021-04-28)\n\n**Features:**\n\n* Add support for Azure Service Bus sessions. (#829)\n* Add custom message headers support for RabbitMQ consumer. (#818)\n\n**Bug Fixed:**\n\n* Downgrading Microsoft.Data.SqlClient to 2.0.1. (#839)\n* DiagnosticObserver does not use null connection. (#845)\n* Fix null reference in AmazonSQSTransport. (#846)\n\n## Version 5.0.1 (2021-04-07)\n\n**Features:**\n\n* Add KafkaOptions.MainConfig to AutoCreateTopic. (#810)\n* Add support rewriting the default configuration of Kafka consumer. (#822)\n* Add DefaultChallengeScheme dashboard options to specify dashboard auth challenge scheme. (#815)\n\n**Bug Fixed:**\n \n* Fixed topic selector in IConsumerServiceSelector. (#806)\n* Update AWS topic subscription and SQS access policy generation. (#808)\n* Fixed memory leak when using transction to publish message. (#816)\n* Fixed SQL content filter on IMonitoringApi.PostgreSql.cs. (#814)\n* Fixed the expiration time display problem in the dashboard due to time zone issues (#820)\n* Fixed the creation timing of Kafka automatically creating Topic. (#823)\n* Fixed Dashboard metric not update. (#819)\n\n## Version 5.0.0 (2021-03-23)\n \n**Features:**\n\n* Upgrade to .NET Standard 2.1 and support .NET 5. (#727)\n* Replace Newtonsoft.Json to System.Text.Json. (#740)\n* Support NATS Transport. (#595,#743)\n* Enabling publiser confirms for RabbitMQ. (#730)\n* Support query subscription from DI implementation factory. (#756)\n* Add options to create lazy queue for RabbitMQ. (#772)\n* Support to add custom tags for Consul. (#786)\n* Support custom group and topic prefiex. (#780)\n* Renemae DefaultGroup option to DefaultGroupName.\n* Add auto create topic at startup for Kafka. (#795,#744)\n\n**Bug Fixed:**\n\n* Fixed retrying process earlier than consumer registration to DI. (#760)\n* Fixed Amazon SQS missing pagination topics. (#765)\n* Fixed RabbitMQ MessageTTL option to int type. (#787)\n* Fixed Dashboard auth. (#793)\n* Fixed ClientProvidedName could not be renamed for RabbitMQ. (#791)\n* Fixed EntityFramework transaction will not rollback when exception occurred. (#798)\n\n## Version 3.1.2 (2020-12-03)\n\n**Features:**\n* Support record the exception message in the headers. (#679)\n* Support consul service check for https. (#722)\n* Support custom producer threads count options for sending. (#731)\n* Upgrade dependent nuget packages to latest.\n\n**Bug Fixed:**\n\n* Fixed InmemoryQueue expired messages are not removed bug. (#691)\n* Fixed Executor key change lead to possible null reference exception. (#698)\n* Fixed Postgresql delete expires data logic error. (#714)\n\n## Version 3.1.1 (2020-09-23)\n\n**Features:**\n\n* Add consumer parameter with interface suppport. (#669)\n* Add custom correlation id and message id support. (#668)\n* Enhanced custom serialization support. (#641)\n\n**Bug Fixed:**\n\n* Solve the issue of being duplicated executors from different assemblies. (#666)\n* Added comparer to remove duplicate ConsumerExecutors. (#653)\n* Add re-enable the auto create topics configuration item for Kafka, it's false by default. now is true. (#635)\n* Fixed postgresql transaction rollback invoke bug. (#640)\n* Fixed SQLServer table name customize bug. (#632)\n\n## Version 3.1.0 (2020-08-15)\n\n**Features:**\n\n* Add Amazon SQS support. (#597)\n* Remove Dapper and replace with ADO.NET in storage project. (#583)\n* Add debug symbols package to nuget.\n* Upgrade dependent nuget package version to latest.\n* English docs grammar correction. Thanks @mzorec\n\n**Bug Fixed:**\n\n* Fix mysql transaction rollback bug. (#598)\n* Fix dashboard query bug. (#600)\n* Fix mongo db query bug. (#611)\n* Fix dashboard browser language detection bug. (#631)\n\n## Version 3.0.4 (2020-05-27)\n\n**Bug Fixed:**\n\n* Fix kafka consumer group does not works bug. (#541)\n* Fix cast object to primitive types failed bug. (#547)\n* Fix subscriber primitive types convert exception. (#568)\n* Add conosole app sample.\n* Upgrade Confluent.Kafka to 1.4.3\n\n\n## Version 3.0.3 (2020-04-01)\n\n**Bug Fixed:**\n\n* Change ISubscribeInvoker interface access modifier to public. (#537)\n* Fix rabbitmq connection may be reused when close forced. (#533)\n* Fix dashboard message reexecute button throws exception bug. (#525)\n\n## Version 3.0.2 (2020-02-05)\n\n**Bug Fixed:**\n\n- Fixed diagnostics event data object error. (#504 )\n- Fixed RabbitMQ transport check not working. (#503 )\n- Fixed Azure Service Bus subscriber error. (#502  )\n\n## Version 3.0.1 (2020-01-19)\n\n**Bug Fixed:**\n\n* Fixed Dashboard requeue and reconsume failed bug.  (#482 )\n* Fixed Azure service bus null reference exception. (#483 )\n* Fixed type cast exception from storage. (#473 )\n* Fixed SqlServer  connection undisponse bug. (#477 )\n\n## Version 3.0.0 (2019-12-30)\n\n**Breaking Changes:**\n\nIn this version, we have made major improvements to the code structure, which have introduced some destructive changes.\n\n* Publisher and Consumer are not compatible with older versions\nThis version is not compatible with older versions of the message protocol because we have improved the format in which messages are published and stored.\n\n* Interface changes\nWe have done a lot of refactoring of the code, and some of the interfaces may be incompatible with older versions\n\n* Detach the dashboard project\n\n**Features:**\n\n* Supports .NET Core 3.1.\n* Upgrade dependent packages.\n* New serialization interface `ISerializer` to support serialization of message body sent to MQ.\n* Add new api for `ICapPublisher` to publish message with headers.\n* Diagnostics event structure and names improved. #378\n* Support consumer method to read the message headers. #472\n* Support rename message storage tables. #435\n* Support for Kafka to write such as Offset and Partition to the header. #374\n* Improved the processor retry interval time. #444\n\n**Bug Fixed:**\n\n* Fixed SqlServer dashboard sql query bug. #470\n* Fixed Kafka health check bug. #436\n* Fixed dashboard bugs. #412 #404\n* Fixed transaction bug for sql server when using EF. #402\n\n\n## Version 2.6.0 (2019-08-29)\n\n**Features:**\n\n* Improvement Diagnostic support. Thanks [@gfx687](https://github.com/gfx687) \n* Improvement documention. https://cap.dotnetcore.xyz\n* Improvement `ConsumerInvoker` implementation. Thanks [@hetaoos](https://github.com/hetaoos)\n* Support multiple consumer threads. (#295)\n* Change DashboardMiddleware to async. (#390) Thanks [@liuzhenyulive](https://github.com/liuzhenyulive) \n\n**Bug Fixed:**\n\n* SQL Server Options Bug.\n* Fix transaction scope disposed bug. (#365)\n* Fix thread safe issue of ICapPublisher bug. (#371)\n* Improved Ctrl+C action raised exception issue.\n* Fixed asynchronous exception catching bug of sending.\n* Fix MatchPoundUsingRegex \".\" not escaped bug (#373)\n\n## Version 2.5.1 (2019-06-21)\n\n**Features:**\n\n* Improved logs record.\n* Upgrade dependent nuget packages version. (MySqlConnector, confluent-kafka-dotnet-1.0 )\n* NodeId type change to string of DiscoveryOptions for Consul. (#314)\n* Change the IConsumerServiceSelector interface access modifier to public. (#333)\n* Improved RabbitMQOptions to provide extensions option to configure the client original configuration. (#350)\n* Add index for MongoDB CAP collections. (#353)\n\n**Bugs Fixed:**\n\n* Fixed consumer re-register transport bug. (#329)\n* Handle messages retrieval failure. (#324)\n* Fixed DiagnosticListener  null reference exception bug. (#335)\n* Add subscription name validation for the AzureServerBus. (#344)\n* Fixed thread safety issues of publisher. (#331)\n\n## Version 2.5.0 (2019-03-30)\n\n**Features:**\n\n* Support Azure Service Bus. (#307)\n* Support In-Memory Storage. (#296)\n* Upgrade Dapper to version 1.60.1\n* Support read environment variables CAP_WORKERID and CAP_DATACENTERID as the snowflake algorithm workerid and datacenterid.\n\n**Bug Fixed:**\n\n* Modify MySQL cap table encoding to utf8mb4. (#305)\n* Move CapSubscribeAttribute class to DotNetCore.CAP project.\n* Fixed multiple instance snowflake algorithm generating primary key conflicts. (#294)\n\n## Version 2.4.2 (2019-01-08)\n\n**Features:**\n\n* Startup the CAP with the .NET Core 2.1 BackgroundService. (#265)\n* Improved message delivery performance. #261\n\n**Bug Fixed:**\n\n* Fixed PostgreSql version isolation feature bug. (#256)\n* Fixed SQL Server sql bug for dashboard search. (#266)\n\n## Version 2.4.1 (2018-12-19)\n\n**Bug Fixed:**\n\n* Fixed MongoDB version isolation feature bug. (#253)\n\n## Version 2.4.0 (2018-12-08)\n\n**Features:**\n\n* Supported version options. (#220)\n* Upgrade nuget package to .net core 2.2.\n\n**Breaking Changes:**\n\nIn order to support the \"version isolation\" feature, we introduced a new version field in version 2.4.0 to isolate different versions of the message, so this requires some adjustments to the database table structure. You can use the following SQL to add a version field to your database CAP related table.\n\n**MySQL**\n```sql\nALTER TABLE `cap.published` ADD Version VARCHAR(20) NULL;\nALTER TABLE `cap.received` ADD Version VARCHAR(20) NULL;\n```\n\n**SQL Server**\n```sql\nALTER TABLE Cap.[Published] ADD Version VARCHAR(20) NULL;\nALTER TABLE Cap.[Received] ADD Version VARCHAR(20) NULL;\n```\n\n**PostgreSQL**\n```sql\nALTER TABLE cap.published ADD  \"Version\" VARCHAR(20) NULL;\nALTER TABLE cap.received ADD \"Version\" VARCHAR(20) NULL;\n```\n\n**MongoDb**\n```\ndb.CapPublishedMessage.update({},{\"$set\" : {\"Version\" : \"1\"}});\ndb.CapReceivedMessage.update({},{\"$set\" : {\"Version\" : \"1\"}});\n```\n\n**Bug Fixed:**\n\n- Fixed different groups of the same topic name in one instance will cause routing bug. (#235)\n- Fixed message presistence bug. (#240)\n- Fixed RabbitMQ topic name contains numbers will cause exception bug. (#181)\n\n## Version 2.3.1 (2018-10-29)\n\n**Features:**\n\n- Add Source Link Support\n- Upgrade dependent NuGet packages.\n\n**Bug Fixed:**\n\n- Fixed dashboard messages requeue error. (#205)\n- Adjustment snowflake workerId to random id.\n- Fixed flush unclaer data bug.\n\n## Version 2.3.0 (2018-08-30)\n\nIn this version, we made some breaking changes for the publisher API, you can see this blog to understand the story behind.\n\nIf you have any migration question, please comment in issue (#190).\n\n**Breaking Changes:**\n\n- Removed app.UseCap() from Startup.cs\n- Message table primary key data type has been modified to Bigint and non auto-Increment. (#180)\n- New publisher Api. (#188)\n\n**Features:**\n\n- MongoDb supported. (#143)\n- Automatic commit transaction. (#191)\n\n**Bug Fixed:**\n\n- Fix message still sent if transaction faild bug. (#118)\n- Multiple events in one transaction. (#171)\n\n## Version 2.2.5 (2018-07-19)\n\n**Features:**\n- Performance improvement\n\n**Bug Fixed:**\n\n- Fixed message enqueue exception.\n- Fixed Retry processor bugs.\n- Fixed Kafka producer exception log without logging when publish message.\n- Fixed Incorrect local IP address judgment of IPv6. (#140)\n- Fixed DateTime localization format conversion error to sql. (#139)\n- Fixed dashboard message page re-requeue and re-executed operate bug. (#158)\n- Fixed SendAsync or ExecuteAsync recursion retries bug. (#160)\n- Fixed configuration options of FailedThresholdCallback could not be invoke when the value less then three. (#161)\n\n## Version 2.2.4 (2018-06-05)\n\nBecause version 2.2.3 was not released to nuget, so released 2.2.4.\n\n## Version 2.2.3 (2018-06-05)\n\n**Features:**\n\n- Improved log output.\n- Upgrade nuget packages.\n- Support pattern matching for consumer. (#132)\n\n**Bug Fixed:**\n\n- Fixed exception thrown when terminate the program with Ctrl+C. (#130)\n\n## Version 2.2.2 (2018-04-28)\n\n**Features:**\n\n- Improved log output. #114\n- Add default timeout configuration for kafka client.\n- Rename configuration options FailedCallback to FailedThresholdCallback.\n\n**Bug Fixed:**\n\n- Fixed message enqueue exception.\n- Fixed retry processor bugs.\n- Fixed kafka producer exception log without logging when publish message.\n\n## Version 2.2.1 (2018-04-18)\n\n**Bug Fixed:**\n\n- Fixed message enqueue bug in v2.2\n\n\n## Version 2.2.0 (2018-04-17)\n\n**Features:**\n\n- Remove database queue mode. (#102)\n- Support for Diagnostics. (#112)\n- Upgrade dependent nuget packages.\n\n**Bug Fixed:**\n\n- Fixed bug of the FailedRetryCount does not increase when raised SubscribeNotFoundException. (#90)\n\n## Version 2.1.4 (2018-03-16)\n\n**Features:**\n\n- Remove TableNamePrefix option from MySqlOptions to EFOptions.\n- Upgrade nuget package\n\n**Bug Fixed:**\n\n- Fixed the connection bug of getting message from table. (#83)\n- Fixed entityframework rename table name prefix bug. (#84)\n- Fixed sql server scripts bug of create table scheme. (#85)\n- Fixed thread safety issue about KafkaOptions.(#89)\n\n## Version 2.1.3 (2018-01-24)\n\n**Features:**\n\n- Upgrade dependent nuget packages version.\n- NuGet package include xml doc now.\n- NuGet now contains the CAP symbol files.\n\n**Bug Fixed:**\n\n- Fixed thread conflict issue when sending messages with PublishAsync. (#80)\n- Fixed kafka received message sava failed may caused the mssage loss bug. (#78)\n- Fixed dashboard js syntax issue. (#77)\n\n## Version 2.1.2 (2017-12-18)\n\n**Bug Fixed:**\n\n- Fixed and improve the performance of mysql processing messages. (#68) (#36)\n- Fixed dashboard manually trigger reconsumption bug. (#67)\n- Fixed mysql 5.5 table initialization bug. (#65)\n- Fixed mysql message queue executor bug. (#66)\n\n## Version 2.1.1 (2017-11-28)\n\n**Bug Fixed:**\n\n- Fixed 'dotnet.exe' process incomplete quit when shutdown application (Ctrl+C). (#64)\n- Fixed failure to issue as expected of RabbitMQ SubscriberNotFoundException. (#63)\n- Fixed Sent async message in the loop causes an exception. (#62)\n\n## Version 2.1.0 (2017-11-17)\n\n**Features:**\n\n- Interface display optimization of dashboard.\n- Adds a more friendly display when looks at the message content.\n- Now you can see the exception infomation in the message conent filed when message send or executed failed.\n- Optimize LAN to see Dashboard without authentication.\n- Add IContentSerializer interface, you can customize the serialized message content.\n- Add IMessagePacker interface, you can customize wapper of the message.\n- Upgrade the dependent package.\n\n**Bug Fixed:**\n\n- Fixed dashboard query bugs.\n- Fixed dashboard multilanguage display bugs.\n- Fixed RabbitMQ connection pool bug.\n- Fixed dashboard display bugs on mobile.\n\n## Version 2.0.2 (2017-09-29)\n\n**Bug Fixed:**\n\n- Fixed asp.net core 2.0 startup error of MySql and PostgreSql. (#44\n\n## Version 2.0.1 (2017-09-16)\n\n**Bug Fixed:**\n\n- DbContext services bug. (#44)\n- Dependency injection bug. (#45)\n\n## Version 2.0.0 (2017-09-01)\n\n**Features:**\n\n* Supported .net standard 2.0.\n* Supported PostgreSQL 9.5+.\n* Supported asynchronous function subscriptions.\n* `ICapPublisher` api supported callback subsrciber.\n\n**Bug Fixed:**\n\n* Fixed multiple subscriber subscribe bug. (#38)\n* Fixed model binde bug. (#17) (#18)\n* Fixed database connection disposed bug. (#25)\n* Fixed consumer method injection context bug. (#34)\n\n## Version 1.1.0 (2017-08-04)\n\n**Features:**\n\n- Support MySQL database persistent message.\n- Add message failed call-back in CapOptions.\n- Remove publish messages API of string name at `ICapPublisher`.\n\n**Bug Fixed:**\n\n- Fixed can not send message for string type. (#17)\n- Fixed model bind for type like datetime guid always failed. (#18)\n\n## Version 1.0.1 (2017-07-25)\n\n**Features:**\n\n- ICapPublisher interface added synchronous publish API.\n- Add infinity retry failed processor.\n\n## Version 1.0.0 (2017-07-19)\n\n- Project published"
  },
  {
    "path": "docs/content/index.md",
    "content": "---\nhide:\n  - feedback\n---\n\nTitle: CAP - A distributed transaction solution in micro-service base on eventually consistency, also an eventbus with Outbox pattern\n\n# CAP\n\n<img width=\"140\" align=\"right\" src=\"img/logo.svg\">\n[![Docs&Dashboard](https://github.com/dotnetcore/CAP/actions/workflows/deploy-docs-and-dashboard.yml/badge.svg?branch=master)](https://github.com/dotnetcore/CAP/actions/workflows/deploy-docs-and-dashboard.yml)\n[![AppVeyor](https://ci.appveyor.com/api/projects/status/v8gfh6pe2u2laqoa/branch/master?svg=true)](https://ci.appveyor.com/project/yuleyule66/cap/branch/master)\n[![NuGet](https://img.shields.io/nuget/v/DotNetCore.CAP.svg)](https://www.nuget.org/packages/DotNetCore.CAP/)\n[![NuGet Preview](https://img.shields.io/nuget/vpre/DotNetCore.CAP.svg?label=nuget-pre)](https://www.nuget.org/packages/DotNetCore.CAP/)\n[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/dotnetcore/CAP/master/LICENSE.txt)\n[![Member project of .NET Core Community](https://img.shields.io/badge/member%20project%20of-NCC-9e20c9.svg)](https://github.com/dotnetcore)\n\nCAP is a library based on .net standard, which is a solution to deal with distributed transactions, also has the function of EventBus, it is lightweight, easy to use, and efficient.\n\n## Introduction\n\nIn the process of building an SOA or MicroService system, we usually need to use the event to integrate each service. In the process, simple use of message queue does not guarantee reliability. CAP adopts local message table program integrated with the current database to solve exceptions that may occur in the process of the distributed system calling each other. It can ensure that the event messages are not lost in any case.\n\nYou can also use CAP as an EventBus. CAP provides a simpler way to implement event publishing and subscriptions. You do not need to inherit or implement any interface during subscription and sending process.\n\n!!! Tip \"CAP implements the Outbox Pattern described in the [eShop ebook](https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/multi-container-microservice-net-applications/subscribe-events#designing-atomicity-and-resiliency-when-publishing-to-the-event-bus)\"\n    <img src=\"img/architecture-eshop.png\">\n\n    > Atomicity when publishing events to the event bus with a worker microservice\n\n\nFor detailed instructions see the [Getting Started Guide][1].\n\n  [1]: user-guide/en/getting-started/quick-start.md\n\n## Contributing\n\nOne of the easiest ways to contribute is to participate in discussions and discuss issues. You can also contribute by submitting pull requests with code changes.\n\nIf you have any question or problems, please report them on the CAP repository:\n\n<a href=\"https://github.com/dotnetcore/cap/issues/new\"><button data-md-color-primary=\"purple\"><i class=\"fa fa-github fa-2x\"></i> Report Issue</button></a>\n<a href=\"https://github.com/dotnetcore/cap/issues\"><button data-md-color-primary=\"purple\" type=\"submit\"> Active Issues <i class=\"fa fa-github fa-2x\"></i></button></a>\n\n## License\n\nCAP is licensed under the [MIT license](about/license.md).\n"
  },
  {
    "path": "docs/content/user-guide/en/cap/configuration.md",
    "content": "# Configuration\n\nBy default, you specify configurations when registering CAP services in the DI container for an ASP.NET Core project.\n\n```c#\nservices.AddCap(config =>\n{\n    // config.XXX\n});\n```\n\n`services` is an `IServiceCollection` interface, which can be found in the `Microsoft.Extensions.DependencyInjection` package.\n\n## Minimum Configuration Required\n\nYou must configure at least one transport and one storage. If you want to get started quickly, you can use the following configuration:\n\n```C#\nservices.AddCap(capOptions => \n{\n     capOptions.UseInMemoryQueue();  // Requires the Savorboard.CAP.InMemoryMessageQueue NuGet package.\n     capOptions.UseInMemoryStorage();\n});\n```\n\nFor transport and storage configuration options provided by specific components, see the [Transports](../transport/general.md) and [Storage](../storage/general.md) sections.\n\n## Configuration in Subscribers\n\nSubscribers use the `[CapSubscribe]` attribute to mark themselves as subscribers. They can be located in an ASP.NET Core Controller or Service.\n\nWhen you declare `[CapSubscribe]`, you can change the behavior of the subscriber by specifying the following parameters.\n\n### Name\n\n> string, required\n\nSubscribe to messages by specifying the `Name` parameter. This corresponds to the name specified when publishing the message through `_cap.Publish(\"Name\")`.\n\nThis name corresponds to different items in different message brokers:\n\n- In RabbitMQ, it corresponds to the Routing Key.\n- In Kafka, it corresponds to the Topic.\n- In Azure Service Bus, it corresponds to the Subject.\n- In NATS, it corresponds to the Subject.\n- In Redis Streams, it corresponds to the Stream.\n\n### Group\n\n> string, optional\n\nSpecify the `Group` parameter to place subscribers within a separate consumer group, a concept similar to consumer groups in Kafka. If this parameter is not specified, the current assembly name (`DefaultGroupName`) is used as the default.\n\nSubscribers with the same `Name` but set to **different** groups will all receive messages. Conversely, if subscribers with the same `Name` are set to the **same** group, only one will receive the message.\n\nIt also makes sense for subscribers with different `Names` to be set to **different** groups; they can have independent threads for execution. Conversely, if subscribers with different `Names` are set to the **same** group, they will share consumption threads.\n\nGroup corresponds to different items in different message brokers:\n\n- In RabbitMQ, it corresponds to Queue.\n- In Kafka, it corresponds to Consumer Group.\n- In Azure Service Bus, it corresponds to Subscription Name.\n- In NATS, it corresponds to Queue Group.\n- In Redis Streams, it corresponds to Consumer Group.\n\n###  GroupConcurrent\n\n> byte, optional\n\nSet the parallelism of concurrent execution for subscribers by specifying the value of the `GroupConcurrent` parameter. Concurrent execution means that it needs to run on an independent thread, so if you do not specify the `Group` parameter, CAP will automatically create a Group using the value of `Name`.\n\n!!! Note\n    If you have multiple subscribers configured with the same Group and have also set the `GroupConcurrent` value for them, the degree of parallelism is the sum of the values in the group.  \n    This setting applies only to new messages; retried messages are not subject to the concurrency limit.\n\n## Custom Configuration\n\nThe `CapOptions` class is used to store configuration information. By default, all options have default values. Sometimes you may need to customize them.\n\n#### DefaultGroupName\n\n> Default: cap.queue.{assembly name}\n\nThe default consumer group name. It corresponds to different names in different transports. You can customize this value to customize the names in different transports for easy viewing.\n\n!!! info \"Mapping\"\n    Maps to [Queue Names](https://www.rabbitmq.com/queues.html#names) in RabbitMQ.  \n    Maps to [Consumer Group Id](http://kafka.apache.org/documentation/#group.id) in Apache Kafka.  \n    Maps to Subscription Name in Azure Service Bus.  \n    Maps to [Queue Group Name](https://docs.nats.io/nats-concepts/queue) in NATS.\n    Maps to [Consumer Group](https://redis.io/topics/streams-intro#creating-a-consumer-group) in Redis Streams.\n\n#### GroupNamePrefix\n\n> Default: Null\n\nAdd unified prefixes to consumer group names. https://github.com/dotnetcore/CAP/pull/780\n\n#### TopicNamePrefix\n\n> Default: Null\n\nAdd unified prefixes to topic/queue names. https://github.com/dotnetcore/CAP/pull/780\n\n#### Version\n\n> Default: v1\n\nUsed to specify a version for a message to isolate messages of different versions across services. This is useful for A/B testing or multi-service version scenarios. The following are application scenarios that require versioning:\n\n!!! info \"Business Iteration and Backward Compatibility\"\n    Due to rapid iteration of business logic, the message data structure may change during service integration. Sometimes we add or modify data structures to accommodate new requirements. If you have a brand new system, this is not a problem. However, if your system is already deployed to production and serving customers, new features can become incompatible with old data structures when released online, which can cause serious issues. To work around this problem, you would need to clear all message queues and persistent messages before restarting the application, which is obviously unacceptable for production environments.\n\n!!! info \"Multiple Server Versions\"\n    Sometimes, the server needs to provide multiple sets of interfaces to support different versions of the client application. The data structures for the same interface interactions between different app versions and the server may differ, so the server typically provides different routing addresses to accommodate different client versions.\n\n!!! info \"Different Instances Using the Same Storage Table/Collection\"\n    If you want multiple service instances to share the same database, you can isolate database tables for different instances by specifying different table names. This can be achieved through CAP configuration by setting different table name prefixes.\n\n> Check out the blog to learn more about the Version feature: https://www.cnblogs.com/savorboard/p/cap-2-4.html\n\n#### FailedRetryInterval\n\n> Default: 60 sec\n\nDuring the message sending process, if message transmission fails, CAP will retry sending. This configuration option specifies the interval between each retry attempt.\n\nDuring the message consumption process, if the consumer method fails, CAP will retry execution. This configuration option specifies the interval between each retry attempt.\n\n!!! WARNING \"Retry & Interval\"\n    By default, if a failure occurs during send or consume operations, retry will begin after **4 minutes** (FallbackWindowLookbackSeconds) to avoid potential issues caused by message state delays.    \n    Send and consume failures are retried 3 times immediately. After the initial 3 attempts, retries follow a polling schedule, at which point the FailedRetryInterval configuration takes effect.\n\n!!! WARNING \"Multi-instance Concurrent Retries\"\n    Version 7.1.0 introduced database-based distributed locks to solve the problem of concurrent database fetches during retry operations across multiple instances. You must explicitly set `UseStorageLock` to true to enable this.\n\n#### UseStorageLock\n\n> Default: false\n\nIf set to true, we will use a database-based distributed lock to handle concurrent data fetches by retry processes across multiple instances. This will generate the cap.lock table in the database.\n\n#### CollectorCleaningInterval\n\n> Default: 300 sec\n\nThe interval at which the collector deletes expired messages.\n\n#### SchedulerBatchSize\n\n> Default: 1000\n\nMaximum number of delayed or queued messages fetched per scheduler cycle.\n\n#### ConsumerThreadCount\n\n> Default: 1\n\nNumber of consumer threads. When this value is greater than 1, the order of message execution cannot be guaranteed.\n\n#### FailedRetryCount\n\n> Default: 50\n\nMaximum number of retries. When this count is reached, retries will stop. You can modify this parameter to set the maximum retry attempts.\n\n#### FallbackWindowLookbackSeconds\n\n> Default: 240 sec\n\nConfigures the retry processor to pick up messages with `Scheduled` or `Failed` status within the lookback time window.\n\n#### FailedThresholdCallback\n\n> Default: NULL\n\nType: `Action<FailedInfo>`\n\nFailure threshold callback. This action is invoked when retry attempts reach the value set by `FailedRetryCount`. You can use this callback to receive notifications and take manual intervention. For example, send an email or notification. \n\n#### SucceedMessageExpiredAfter\n\n> Default: 24*3600 sec (1 day)\n\nExpiration time (in seconds) for successfully sent or consumed messages. When a message is sent or consumed successfully, it will be removed from the database after `SucceedMessageExpiredAfter` seconds. You can set the expiration time by modifying this value.\n\n#### FailedMessageExpiredAfter\n\n> Default: 15*24*3600 sec (15 days)\n\nExpiration time (in seconds) for failed messages. When a message fails to send or consume, it will be removed from the database after `FailedMessageExpiredAfter` seconds. You can set the expiration time by modifying this value.\n\n#### [Removed] UseDispatchingPerGroup \n\n> Default: false\n\n> Removed in version 8.2, now default behavior\n\nIf multiple consumers are within the same group, each consumer group pushes received messages to its own dispatching pipeline channel. Each channel has a thread count set to the `ConsumerThreadCount` value.\n\n#### [Obsolete] EnableConsumerPrefetch\n\n> Default: false (Before version 7.0, the default was true)\n\nThis option has been renamed to `EnableSubscriberParallelExecute`. Please use the new option instead.\n\n#### EnableSubscriberParallelExecute\n\n> Default: false\n\nIf set to `true`, CAP will prefetch a batch of messages from the broker and buffer them, then execute the subscriber method. After execution completes, it fetches the next batch for processing.\n\n!!! note \"Precautions\"\n    Setting this to true may cause issues. If the subscriber method executes slowly and takes a long time, the retry thread may pick up messages that have not yet been executed. The retry thread picks up messages from 4 minutes ago (FallbackWindowLookbackSeconds) by default. If the consumer side has more than 4 minutes (FallbackWindowLookbackSeconds) of message backlog, those messages will be picked up again and executed again.\n\n#### SubscriberParallelExecuteThreadCount\n\n> Default: `Environment.ProcessorCount`\n\nSpecifies the number of threads for parallel task execution when `EnableSubscriberParallelExecute` is enabled.\n\n#### SubscriberParallelExecuteBufferFactor\n\n> Default: 1\n\nMultiplier used to determine the buffered capacity size during parallel subscriber execution when `EnableSubscriberParallelExecute` is enabled. The buffer capacity is calculated by multiplying this factor with `SubscriberParallelExecuteThreadCount`, which represents the number of threads allocated for parallel processing.\n\n#### EnablePublishParallelSend\n\n> Default: false (In versions 7.2 <= Version < 8.1, the default is true)\n\nBy default, sent messages are placed into a single in-memory channel and then processed linearly.\nIf set to true, message sending tasks will be processed in parallel by the .NET thread pool, which will greatly improve sending performance.\n"
  },
  {
    "path": "docs/content/user-guide/en/cap/filter.md",
    "content": "# Filter\n\nSubscriber filters are similar to ASP.NET MVC filters and are mainly used to perform additional work before and after the subscriber method executes, such as transaction management or logging.\n\n## Creating a Subscriber Filter\n\n### Create Filter\n\nCreate a new filter class that inherits from the `SubscribeFilter` abstract class.\n\n```C#\npublic class MyCapFilter : SubscribeFilter\n{\n    public override Task OnSubscribeExecutingAsync(ExecutingContext context)\n    {\n        // Execute before the subscriber method runs\n    }\n\n    public override Task OnSubscribeExecutedAsync(ExecutedContext context)\n    {\n        // Execute after the subscriber method completes\n    }\n\n    public override Task OnSubscribeExceptionAsync(ExceptionContext context)\n    {\n        // Handle exceptions during subscriber method execution\n    }\n}\n```\n\nIn some scenarios, if you want to terminate the subscriber method execution, you can throw an exception in `OnSubscribeExecutingAsync`, and choose to handle the exception in `OnSubscribeExceptionAsync`.\n\nTo ignore exceptions, set `context.ExceptionHandled = true` in `ExceptionContext`:\n\n```C#\npublic override Task OnSubscribeExceptionAsync(ExceptionContext context)\n{\n    context.ExceptionHandled = true;\n}\n```\n\n### Registering a Filter\n\nUse `AddSubscribeFilter<>` to register a filter.\n\n```C#\nservices.AddCap(opt =>\n{\n    // ...\n}).AddSubscribeFilter<MyCapFilter>();\n```\n\nCurrently, multiple filters are not supported.\n"
  },
  {
    "path": "docs/content/user-guide/en/cap/idempotence.md",
    "content": "# Idempotence\n\nIdempotence (which you can read a formal definition of on [Wikipedia](https://en.wikipedia.org/wiki/Idempotence)) in messaging systems means that a message redelivery can be handled without resulting in an unintended state.\n\n## Delivery Guarantees[^1]\n\n[^1]: The chapter refers to the [Delivery guarantees](https://github.com/rebus-org/Rebus/wiki/Delivery-guarantees) of rebus, which I think is described very good.\n\nBefore discussing idempotency, let's discuss message delivery guarantees on the consumer side.\n\nSince CAP doesn't use MS DTC or other 2PC (Two-Phase Commit) distributed transaction mechanisms, there is an inherent limitation: messages are delivered at least once. Specifically, in a message-based system, there are three possibilities:\n\n* Exactly Once (*)  \n* At Most Once \n* At Least Once  \n\nExactly Once has a (*) next to it because, in the general case, it is simply not possible.\n\n### At Most Once\n\nThe At Most Once delivery guarantee ensures that you receive all messages either once or not at all.\n\nThis type of delivery guarantee can arise from your messaging system and your code performing actions in the following order:\n\n```\n1. Remove message from queue\n2. Start work transaction\n3. Handle message (your code)\n4. Success?\n    Yes:\n        1. Commit work transaction\n    No: \n        1. Roll back work transaction\n        2. Put message back into the queue\n```\n\nIn the best case scenario, this works well – your messages will be received, work transactions will be committed, and you will be happy.\n\nHowever, things can fail – especially if you do a lot of work. For example, consider what happens if anything fails after step (1), and then – when you try to execute step (4)/(2) (i.e., put the message back into the queue) – the network becomes temporarily unavailable, the message broker restarts, or the host machine reboots due to a system update.\n\nThis might be acceptable if that's what you want, but most things in CAP revolve around the concept of DURABLE messages – messages whose contents are as important as the data in your database.\n\n### At Least Once\n\nThe At Least Once delivery guarantee ensures that you receive all messages one or more times if something fails.\n\nThis requires a slight change in the order of execution and requires that the message queue system supports transactions, either through the traditional begin-commit-rollback protocol (MSMQ does this) or through a receive-ack-nack protocol (RabbitMQ, Azure Service Bus, etc. do this).\n\nConsider this approach:\n\n```\n1. Grab lease on message in queue\n2. Start work transaction\n3. Handle message (your code)\n4. Success?\n    Yes: \n        1. Commit work transaction\n        2. Delete message from queue\n    No: \n        1. Roll back work transaction\n        2. Release lease on message\n```\n\nIf the \"lease\" grabbed in step (1) has an appropriate timeout associated with it, then we are guaranteed that no matter how wrong things go, we will only actually remove the message from the queue (step 4/2) if we have successfully committed our \"work transaction\".\n\n### What is a \"Work Transaction\"?\n\nIt depends on what you're doing 😄 Maybe it's a transaction in a relational database (which traditionally have good support for this), maybe it's a transaction in a document database that supports transactions (like RavenDB or PostgreSQL), or maybe it's a conceptual transaction representing the work you perform as a consequence of handling a message, e.g., updating documents in MongoDB, moving files in the file system, or modifying in-memory data structures.\n\nThe fact that the \"work transaction\" is conceptual makes it impossible to support Exactly Once delivery – it's simply not generally possible to commit or roll back a \"work transaction\" and a \"queue transaction\" (the protocol with the message queue system) atomically and consistently.\n\n## Idempotence in CAP\n\nIn CAP, the **At Least Once** delivery guarantee is used.\n\nSince CAP uses a temporary storage medium (database table), At Most Once could theoretically be achieved, but to strictly guarantee that messages are not lost, we do not provide related functions or configurations.\n\n### Why We Don't Provide (Achieve) Idempotency\n\n1. Message successfully written, but Consumer method execution failed.  \n\n    There are many reasons why the Consumer method might fail. Without knowing the specific scenario, it's unclear whether retrying blindly or not retrying is the correct choice.\n    For example, if the consumer is a debit service and the debit execution succeeds but fails to write the debit log, CAP will consider the consumer failed and retry. If the client doesn't guarantee idempotency, the framework will retry, inevitably leading to serious consequences like multiple debits.\n\n2. Consumer method execution succeeded, but the same message is received again.  \n\n    This scenario is also possible. If the Consumer has already executed successfully but for some reason (e.g., broker recovery), the same message is received again, CAP will treat it as a new message. Message will be executed again by the Consumer. Because it is a new message, CAP cannot ensure idempotency at this point.\n\n3. Current data storage mode cannot guarantee idempotency.  \n\n    Since the CAP message table for successfully consumed messages is deleted after 1 hour, historical messages cannot be verified for idempotency. If the broker has been maintained or manually processed some messages for some reason, there's no way to verify if they were already processed.\n\n4. Industry practices.\n\n    Many event-driven frameworks require users to ensure idempotent operations, such as ENode, RocketMQ, etc.\n\nFrom an implementation perspective, CAP could provide some less stringent idempotency, but strict idempotency cannot be guaranteed.\n\n### Naturally Idempotent Message Processing\n\nGenerally, the best way to handle message redeliveries is to make the processing of each message naturally idempotent.\n\nNatural idempotence occurs when processing a message consists of calling an idempotent method on a domain object, like:\n\n```\nobj.MarkAsDeleted();\n```\n\nor\n\n```\nobj.UpdatePeriod(message.NewPeriod);\n```\n\nYou can use `INSERT ON DUPLICATE KEY UPDATE` provided by the database to achieve this easily.\n\n### Explicitly Handling Redeliveries\n\nAnother way to make message processing idempotent is to explicitly track IDs of processed messages and then handle redeliveries in your code.\n\nAssuming you track message IDs using an `IMessageTracker` that uses the same transactional data store as the rest of your work, your code might look like this:\n\n```c#\nreadonly IMessageTracker _messageTracker;\n\npublic SomeMessageHandler(IMessageTracker messageTracker)\n{\n    _messageTracker = messageTracker;\n}\n\n[CapSubscribe]\npublic async Task Handle(SomeMessage message) \n{\n    if (await _messageTracker.HasProcessed(message.Id))\n    {\n        return;\n    }\n\n    // Do the actual work here\n    // ...\n\n    // Record that this message has been processed\n    await _messageTracker.MarkAsProcessed(message.Id);\n}\n```\n\nFor the `IMessageTracker` implementation, you can use a message ID storage system like Redis or a database with a corresponding processing state."
  },
  {
    "path": "docs/content/user-guide/en/cap/messaging.md",
    "content": "# Message\n\nThe data sent using the `ICapPublisher` interface is called a `Message`.\n\n!!! WARNING \"TimeoutException thrown in consumer using HTTPClient\"\n    By default, if the consumer throws an `OperationCanceledException` (including `TaskCanceledException`), it is considered normal user behavior, and the exception is ignored. However, if you use `HttpClient` in the consumer method and configure a request timeout, you may need to handle exceptions separately and re-throw non-`OperationCanceledException` exceptions due to a [design issue](https://github.com/dotnet/runtime/issues/21965) in `HttpClient`. Refer to issue #1368 for more details.\n\n## Compensating Transaction\n\nWiki: [Compensating Transaction](https://en.wikipedia.org/wiki/Compensating_transaction)\n\nIn some cases, consumers need to return an execution result to notify the publisher, allowing the publisher to perform compensation actions. This process is called message compensation.\n\nTypically, you can notify the upstream system by publishing a new message in the consumer code. CAP simplifies this by allowing you to specify the `callbackName` parameter when publishing a message. This feature is generally applicable to point-to-point consumption. Here is an example:\n\nFor instance, in an e-commerce application, an order's initial status is \"pending.\" The status is updated to \"succeeded\" when the product quantity is successfully deducted; otherwise, it is marked as \"failed.\"\n\n```C#\n// =============  Publisher =================\n\n_capBus.Publish(\"place.order.qty.deducted\", \n    contentObj: new { OrderId = 1234, ProductId = 23255, Qty = 1 }, \n    callbackName: \"place.order.mark.status\");    \n\n// publisher using `callbackName` to subscribe consumer result\n\n[CapSubscribe(\"place.order.mark.status\")]\npublic void MarkOrderStatus(JsonElement param)\n{\n    var orderId = param.GetProperty(\"OrderId\").GetInt32();\n    var isSuccess = param.GetProperty(\"IsSuccess\").GetBoolean();\n    \n    if(isSuccess){\n        // mark order status to succeeded\n    }\n    else{\n       // mark order status to failed\n    }\n}\n\n// =============  Consumer ===================\n\n[CapSubscribe(\"place.order.qty.deducted\")]\npublic object DeductProductQty(JsonElement param)\n{\n    var orderId = param.GetProperty(\"OrderId\").GetInt32();\n    var productId = param.GetProperty(\"ProductId\").GetInt32();\n    var qty = param.GetProperty(\"Qty\").GetInt32();\n\n    //business logic \n\n    return new { OrderId = orderId, IsSuccess = true };\n}\n```\n\n### Controlling Callback Response\n\nYou can inject the `CapHeader` parameter in the subscription method using the `[FromCap]` attribute and use its methods to add extra headers to the callback context or terminate the callback.\n\nExample:\n\n```cs\n[CapSubscribe(\"place.order.qty.deducted\")]\npublic object DeductProductQty(JsonElement param, [FromCap] CapHeader header)\n{\n    var orderId = param.GetProperty(\"OrderId\").GetInt32();\n    var productId = param.GetProperty(\"ProductId\").GetInt32();\n    var qty = param.GetProperty(\"Qty\").GetInt32();\n\n    // Add additional headers to the response message\n    header.AddResponseHeader(\"some-message-info\", \"this is the test\");\n    // Or add a callback to the response\n    header.AddResponseHeader(DotNetCore.CAP.Messages.Headers.CallbackName, \"place.order.qty.deducted-callback\");\n\n    // If you no longer want to follow the sender's specified callback and want to modify it, use the RewriteCallback method.\n    header.RewriteCallback(\"new-callback-name\");\n\n    // If you want to terminate/stop, or no longer respond to the sender, call RemoveCallback to remove the callback.\n    header.RemoveCallback();\n\n    return new { OrderId = orderId, IsSuccess = true };\n}\n```\n\n## Heterogeneous system integration\n\nIn version 3.0+, we reconstructed the message structure. We used the Header in the message protocol in the message queue to transmit some additional information, so that we can do it in the Body without modifying or packaging the user’s original The message data format and content are sent.\n\nThis approach facilitates better integration with heterogeneous systems. Compared to previous versions, users no longer need to understand the internal message structure used by CAP to complete integration tasks.\n\nNow we divide the message into Header and Body for transmission.\n\nThe data in the body is the content of the original message sent by the user, that is, the content sent by calling the Publish method. We do not perform any packaging, but send it to the message queue after serialization.\n\nIn the Header, we need to pass some additional information so that the CAP can extract the key features for operation when the message is received.\n\nThe following is the content that needs to be written into the header of the message when sending a message in a heterogeneous system:\n\n | Key           | DataType | Description                                                    |\n | ------------- | -------- | -------------------------------------------------------------- |\n | cap-msg-id    | long     | Message Id, Generated by snowflake algorithm                   |\n | cap-msg-name  | string   | The name of the message                                        |\n | cap-msg-type  | string   | The type of message, `typeof(T).FullName`(not required)        |\n | cap-senttime  | string   | sending time (not required)                                    |\n | cap-kafka-key | string   | Partitioning by Kafka Key                                      |\n\n### Custom headers\n\nTo consume messages sent without CAP headers, Azure Service Bus, Kafka, and RabbitMQ consumers can inject a minimal set of headers using the `CustomHeadersBuilder` property as shown below (RabbitMQ example):\n```C#\ncontainer.AddCap(x =>\n{\n    x.UseRabbitMQ(z =>\n    {\n        z.ExchangeName = \"TestExchange\";\n        z.CustomHeadersBuilder = (msg, sp) =>\n        [\n            new(DotNetCore.CAP.Messages.Headers.MessageId, sp.GetRequiredService<ISnowflakeId>().NextId().ToString()),\n            new(DotNetCore.CAP.Messages.Headers.MessageName, msg.RoutingKey)\n        ];\n    });\n});\n```\n\nAfter adding `cap-msg-id` and `cap-msg-name`, CAP consumers can receive messages sent directly from external systems, such as the RabbitMQ management tool when using RabbitMQ as a transport.\n\nTo publish messages with CAP headers:\n\n```C#\nvar headers = new Dictionary<string, string?>()\n{\n    { \"cap-kafka-key\", request.OrderId }\n};\n_publisher.Publish<OrderRequest>(\"OrderRequest\", request, headers);\n```\n\n## Scheduling\n\nAfter CAP receives a message, it sends the message to Transport (RabbitMQ, Kafka...), which handles the transportation.\n \nWhen you send a message using the `ICapPublisher` interface, CAP dispatches it to the corresponding Transport. Currently, bulk messaging is not supported.\n\nFor more information on transports, see the [Transports](../transport/general.md) section.\n\n## Storage \n\nCAP stores messages after receiving them. For more information on storage, see the [Storage](../storage/general.md) section.\n\n## Retry\n\nRetrying is a crucial aspect of the CAP architecture. CAP retries messages that fail to send or consume, employing several retry strategies throughout its design.\n\n### Send Retry\n\nWhen the broker crashes, connection fails, or an abnormality occurs during message sending, CAP retries the send. It performs 3 immediate retries, then after 4 minutes (FallbackWindowLookbackSeconds), it retries every minute with a +1 increment. When the total number of retries reaches 50, CAP stops retrying.\n\nYou can adjust the total number of retries by setting [FailedRetryCount](configuration.md#failedretrycount) in CapOptions or use [FailedThresholdCallback](configuration.md#failedthresholdcallback) to receive notifications when the maximum retry count is reached.\n\nRetries will stop when the maximum is reached. You can see the failure reason in Dashboard and choose whether to manually retry.\n\n### Consumption Retry\n\nWhen the Consumer receives a message, the consumer method is executed and will retry if an exception occurs. This retry strategy is the same as the send retry.\n\nVersion 7.1.0 introduced database-based distributed locks to handle concurrent database fetches during retry operations across multiple instances. You need to explicitly configure the `UseStorageLock` option to true.\n\nWhether sending or consumption fails, the exception message is stored in the cap-exception field within the message header. You can find it in the Content field's JSON in the database table.\n\n## Data Cleanup\n\nThe database message table has an `ExpiresAt` field indicating the message expiration time. When a message is sent successfully, its status changes to `Successed`, and `ExpiresAt` is set to **1 day** later. \n\nWhen consumption fails, the message status changes to `Failed` and `ExpiresAt` is set to **15 days** later (you can customize this using the [FailedMessageExpiredAfter](configuration.md#failedmessageexpiredafter) configuration option).\n\nBy default, messages in the table are deleted every **5 minutes** to prevent performance degradation from excessive data. The cleanup process is performed when the `ExpiresAt` field is not empty and is less than the current time. \n\nThat is, messages with `Failed` status (by default, they have been retried 50 times) will also be cleaned up after **15 days** if you do not manually intervene.\n\nYou can customize the cleanup interval time using the [CollectorCleaningInterval](configuration.md#collectorcleaninginterval) configuration option.\n"
  },
  {
    "path": "docs/content/user-guide/en/cap/serialization.md",
    "content": "# Serialization\n\nWe provide the `ISerializer` interface to support message serialization. By default, JSON is used to serialize messages and store them in the database.\n\n## Custom Serialization\n\n```C#\npublic class YourSerializer : ISerializer\n{\n    Task<TransportMessage> SerializeAsync(Message message)\n    {\n\n    }\n \n    Task<Message> DeserializeAsync(TransportMessage transportMessage, Type valueType)\n    {\n\n    }\n}\n```\n\nThen register your serializer implementation in the container:\n\n```C#\nservices.AddSingleton<ISerializer, YourSerializer>();\n\nservices.AddCap( /* ... */ );\n```\n"
  },
  {
    "path": "docs/content/user-guide/en/cap/transactions.md",
    "content": "# Transaction\n\n## Distributed Transactions?\n\nCAP does not provide out-of-the-box MS DTC or 2PC (Two-Phase Commit) based distributed transactions. Instead, we provide a solution to handle problems encountered in distributed transactions.\n\nIn a distributed environment, using 2PC or DTC-based distributed transactions can be expensive due to communication overhead, which affects performance. Additionally, distributed transactions based on 2PC or DTC are subject to the **CAP theorem** – when network partitioning occurs, you must sacrifice availability (the A in CAP).\n\n> A distributed transaction is a very complex process with many moving parts that can fail. Moreover, if these parts run on different machines or in different data centers, the process of committing a transaction can become very long and unreliable.\n\n> This can seriously affect user experience and overall system bandwidth. So **one of the best ways to solve distributed transaction problems is to avoid them completely**.[^1]\n\nFor handling distributed transactions, CAP uses the \"Eventual Consistency and Compensation\" approach.\n\n### Eventual Consistency and Compensation [^1]\n\n[^1]: This chapter is quoted from: https://www.baeldung.com/transactions-across-microservices\n\nBy far, one of the most feasible models of handling consistency across microservices is [eventual consistency](https://en.wikipedia.org/wiki/Eventual_consistency).\n\nThis model doesn’t enforce distributed ACID transactions across microservices. Instead, it proposes to use some mechanisms of ensuring that the system would be eventually consistent at some point in the future.\n\n#### A Case for Eventual Consistency\n\nFor example, suppose we need to solve the following task:\n\n* register a user profile  \n* do some automated background check that the user can actually access the system\n\nSecond task is to ensure, for example, that this user wasn’t banned from our servers for some reason.\n\nBut it could take time, and we’d like to extract it to a separate microservice. It wouldn’t be reasonable to keep the user waiting for so long just to know that he was registered successfully.\n\n**One way to solve it would be with a message-driven approach including compensation**. Let’s consider the following architecture:\n\n* the user microservice tasked with registering a user profile  \n* the validation microservice tasked with doing a background check  \n* the messaging platform that supports persistent queues  \n\nThe messaging platform could ensure that the messages sent by the microservices are persisted. Then they would be delivered at a later time if the receiver wasn't currently available\n\n#### Best case scenario\n\nIn this architecture, best case scenario would be:\n\n* the user microservice registers a user, saving information about him in its local database\n* the user microservice marks this user with a flag. It could signify that this user hasn’t yet been validated and doesn’t have access to full system functionality\n* a confirmation of registration is sent to the user with a warning that not all functionality of the system is accessible right away\n* the user microservice sends a message to the validation microservice to do the background check of a user\n* the validation microservice runs the background check and sends a message to the user microservice with the results of the check\n* if the results are positive, the user microservice unblocks the user\n* if the results are negative, the user microservice deletes the user account\n\nAfter we’ve gone through all these steps, the system should be in a consistent state. However, for some period of time, user entity appeared to be in an incomplete state.\n\nThe last step, when the user microservice removes the invalid account, is a compensation phase.\n\n#### Failure Scenarios\n\nNow let’s consider some failure scenarios:\n\n* if the validation microservice is not accessible, then the messaging platform with its persistent queue functionality ensures that the validation microservice would receive this message at some later time\n* suppose the messaging platform fails, then the user microservice tries to send the message again at some later time, for example, by scheduled batch-processing of all users that were not yet validated\n* if the validation microservice receives the message, validates the user but can’t send the answer back due to the messaging platform failure, the validation microservice also retries sending the message at some later time\n* if one of the messages got lost, or some other failure happened, the user microservice finds all non-validated users by scheduled batch-processing and sends requests for validation again\n\nEven if some of the messages were issued multiple times, this wouldn’t affect the consistency of the data in the microservices’ databases.\n\n**By carefully considering all possible failure scenarios, we can ensure that our system would satisfy the conditions of eventual consistency. At the same time, we wouldn’t need to deal with the costly distributed transactions.**\n\nBut we have to be aware that ensuring eventual consistency is a complex task. It doesn’t have a single solution for all cases."
  },
  {
    "path": "docs/content/user-guide/en/getting-started/contributing.md",
    "content": "# Contributing\n\nOne of the easiest ways to contribute is to participate in discussions and address issues. \n\nIf you have any questions or problems, please report them on the CAP repository:\n\n<a href=\"https://github.com/dotnetcore/cap/issues/new\"><button data-md-color-primary=\"purple\"><i class=\"fa fa-github fa-2x\"></i> Report Issue</button></a>\n<a href=\"https://github.com/dotnetcore/cap/issues\"><button data-md-color-primary=\"purple\" type=\"submit\"> Active Issues <i class=\"fa fa-github fa-2x\"></i></button></a>\n\n## Submitting Changes\n\nYou can also contribute by submitting pull requests with code changes.\n\n> Pull requests let you tell others about changes you've pushed to a GitHub repository. Once a pull request is opened, you can discuss and review the potential changes with collaborators and add follow-up commits before the changes are merged into the repository.\n\n## Additional Resources\n\n* [Filtering issues and pull requests](https://help.github.com/articles/filtering-issues-and-pull-requests/)\n\n* [Using search to filter issues and pull requests](https://help.github.com/articles/using-search-to-filter-issues-and-pull-requests/)"
  },
  {
    "path": "docs/content/user-guide/en/getting-started/introduction.md",
    "content": "# Introduction\n\nCAP is an EventBus and a solution for solving distributed transaction problems in microservices or SOA systems. It helps you create a microservices system that is scalable, reliable, and easy to modify.\n\nIn Microsoft's [eShop](https://github.com/dotnet/eShop) microservices sample project, CAP is recommended as the EventBus for production environments.\n\n!!! question \"What is EventBus?\"\n\n    An EventBus is a mechanism that allows different components to communicate with each other without knowing each other. A component can send an Event to the EventBus without knowing who will pick it up or how many others will. Components can also listen to Events on an EventBus without knowing who sent them. This way, components can communicate without depending on each other. Also, it's very easy to substitute a component – as long as the new component understands the events being sent and received, other components will never know about the substitution.\n\nCompared to other service buses or event buses, CAP has its own characteristics. It does not require users to implement or inherit any interface when sending or processing messages, providing very high flexibility. We believe that convention is greater than configuration, so CAP is very simple to use, very friendly to beginners, and lightweight.\n\nCAP is modular in design and highly scalable. You have many options to choose from, including message queues, storage, serialization, and more. Many system elements can be replaced with custom implementations.\n\n## Related videos\n\n[Video: bilibili Tutorial](https://www.bilibili.com/video/av31582401/)\n\n[Video: Youtube Tutorial](https://youtu.be/K1e4e0eddNE)\n\n[Video: Youtube Tutorial - @CodeOpinion](https://www.youtube.com/watch?v=dnhPzILvgeo) \n\n[Video: Tencent Tutorial](https://www.cnblogs.com/savorboard/p/7243609.html)\n\n## Related articles\n\n[Article: Introduction and how to use](http://www.cnblogs.com/savorboard/p/cap.html)\n\n[Article: New features in version 7.0](https://www.cnblogs.com/savorboard/p/cap-7-0.html)\n\n[Article: New features in version 6.0](https://www.cnblogs.com/savorboard/p/cap-6-0.html)\n\n[Article: New features in version 5.0](https://www.cnblogs.com/savorboard/p/cap-5-0.html)\n\n[Article: New features in version 3.0](https://www.cnblogs.com/savorboard/p/cap-3-0.html)\n\n[Article: New features in version 2.6](https://www.cnblogs.com/savorboard/p/cap-2-6.html)\n\n[Article: New features in version 2.5](https://www.cnblogs.com/savorboard/p/cap-2-5.html)\n\n[Article: New features in version 2.4](http://www.cnblogs.com/savorboard/p/cap-2-4.html)\n\n[Article: New features in version 2.3](http://www.cnblogs.com/savorboard/p/cap-2-3.html)\n\n[Article: .NET Core Community The first thousand-star project was born: CAP](https://www.cnblogs.com/forerunner/p/ncc-cap-with-over-thousand-stars.html)\n"
  },
  {
    "path": "docs/content/user-guide/en/getting-started/quick-start.md",
    "content": "# Quick Start\n\nLearn how to build a microservices event bus architecture using CAP. This offers advantages over directly integrating message queues and provides many out-of-the-box features.\n\n## Installation\n\n```powershell\nPM> Install-Package DotNetCore.CAP\n```\n\n## Integrated in ASP.NET Core\n\nFor a quick start, we use memory-based event storage and message transport.\n\n```powershell\nPM> Install-Package DotNetCore.CAP.InMemoryStorage\nPM> Install-Package Savorboard.CAP.InMemoryMessageQueue\n```\n\nIn `Startup.cs`, add the following configuration:\n\n```c#\npublic void ConfigureServices(IServiceCollection services)\n{\n    services.AddCap(x =>\n    {\n        x.UseInMemoryStorage();\n        x.UseInMemoryMessageQueue();\n    });\n}\n```\n\n## Publishing a Message\n\n```c#\npublic class PublishController : Controller\n{\n    [Route(\"~/send\")]\n    public IActionResult SendMessage([FromServices] ICapPublisher capBus)\n    {\n        capBus.Publish(\"test.show.time\", DateTime.Now);\n\n        return Ok();\n    }\n}\n```\n\n### Publishing a Delayed Message\n\n```c#\npublic class PublishController : Controller\n{\n    [Route(\"~/send/delay\")]\n    public IActionResult SendDelayMessage([FromServices] ICapPublisher capBus)\n    {\n        capBus.PublishDelay(TimeSpan.FromSeconds(100), \"test.show.time\", DateTime.Now);\n\n        return Ok();\n    }\n}\n```\n\n### Publishing with Extra Headers\n\n```c#\nvar header = new Dictionary<string, string>()\n{\n    [\"my.header.first\"] = \"first\",\n    [\"my.header.second\"] = \"second\"\n};\n\ncapBus.Publish(\"test.show.time\", DateTime.Now, header);\n```\n\n## Processing a Message\n\n```C#\npublic class ConsumerController : Controller\n{\n    [NonAction]\n    [CapSubscribe(\"test.show.time\")]\n    public void ReceiveMessage(DateTime time)\n    {\n        Console.WriteLine(\"message time is: \" + time);\n    }\n}\n```\n\n### Processing with Extra Headers\n\n```c#\n[CapSubscribe(\"test.show.time\")]\npublic void ReceiveMessage(DateTime time, [FromCap] CapHeader header)\n{\n    Console.WriteLine(\"message time is: \" + time);\n    Console.WriteLine(\"message first header: \" + header[\"my.header.first\"]);\n    Console.WriteLine(\"message second header: \" + header[\"my.header.second\"]);\n}\n```\n\n## Summary\n\nOne of the most powerful advantages of asynchronous messaging over direct message queue integration is reliability. Failures in one part of the system don't propagate or cause the entire system to crash. Messages are stored inside CAP to ensure message reliability, and strategies such as retries are used to achieve eventual consistency of data between services."
  },
  {
    "path": "docs/content/user-guide/en/monitoring/consul.md",
    "content": "# Consul\n\n[Consul](https://www.consul.io/) is a distributed service mesh tool to connect, secure, and configure services across any runtime platform and public or private cloud.\n\n## Consul Configuration for Dashboard\n\nCAP's Dashboard uses Consul for service discovery to retrieve data from other nodes. You can switch to the Servers page to view other nodes.\n\n![](https://camo.githubusercontent.com/54c00c6ae65ce1d7b9109ed8cbcdca703a050c47/687474703a2f2f696d61676573323031372e636e626c6f67732e636f6d2f626c6f672f3235303431372f3230313731302f3235303431372d32303137313030343232313030313838302d313136323931383336322e706e67)\n\nClick the `Switch` button to switch to a different node. CAP will use a proxy to retrieve the data from that node.\n\nThe following is a configuration example that you need to configure on each node:\n\n```C#\nservices.AddCap(x =>\n{\n    x.UseMySql(Configuration.GetValue<string>(\"ConnectionString\"));\n    x.UseRabbitMQ(\"localhost\");\n    x.UseDashboard();\n    x.UseConsulDiscovery(_ =>\n    {\n        _.DiscoveryServerHostName = \"localhost\";\n        _.DiscoveryServerPort = 8500;\n        _.CurrentNodeHostName = Configuration.GetValue<string>(\"ASPNETCORE_HOSTNAME\");\n        _.CurrentNodePort = Configuration.GetValue<int>(\"ASPNETCORE_PORT\");\n        _.NodeId = Configuration.GetValue<string>(\"NodeId\");\n        _.NodeName = Configuration.GetValue<string>(\"NodeName\");\n    });\n});\n```\n\nRunning Consul 1.6.2:\n\n```\nconsul agent -dev\n```\n\nWindows 10 with ASP.NET Core 3.1:\n\n```sh\nset ASPNETCORE_HOSTNAME=localhost&& set ASPNETCORE_PORT=5001&& dotnet run --urls=http://localhost:5001 NodeId=1 NodeName=CAP-1 ConnectionString=\"Server=localhost;Database=aaa;UserId=xxx;Password=xxx;\"\nset ASPNETCORE_HOSTNAME=localhost&& set ASPNETCORE_PORT=5002&& dotnet run --urls=http://localhost:5002 NodeId=2 NodeName=CAP-2 ConnectionString=\"Server=localhost;Database=bbb;UserId=xxx;Password=xxx;\"\n```"
  },
  {
    "path": "docs/content/user-guide/en/monitoring/dashboard.md",
    "content": "# Dashboard\n\nCAP provides a Dashboard for viewing messages. The features provided by the Dashboard make it easy to view and manage messages.\n\n!!! WARNING \"Usage Limit\"\n    The Dashboard is only supported for ASP.NET Core. Console applications are not supported.\n    \n## Enable Dashboard\n\nBy default, the Dashboard middleware is not launched. To enable Dashboard functionality, add the following code to your configuration:\n\n```C#\nservices.AddCap(x =>\n{\n    // ...\n\n    // Register Dashboard\n    x.UseDashboard();\n});\n```\n\nBy default, you can access the Dashboard at the URL `http://localhost:xxx/cap`.\n\n### Dashboard Configuration\n\n* **PathMatch**\n\n> Default: '/cap'\n\nChange the path of the Dashboard by modifying this configuration option.\n\n* **StatsPollingInterval**\n\n> Default: 2000ms\n\nConfigures the polling interval for the Dashboard frontend to get the status from the /stats interface.\n\n* **AllowAnonymousExplicit**\n\n> Default: true\n\nExplicitly allows anonymous access for the CAP dashboard API by passing AllowAnonymous to the ASP.NET Core global authorization filter.\n\n* **AuthorizationPolicy**\n\n> Default: null\n\nAuthorization policy for the Dashboard. Required if `AllowAnonymousExplicit` is false.\n\n### Custom Authentication\n\nFrom version 8.0.0, the CAP Dashboard leverages ASP.NET Core authentication mechanisms, allowing extensibility through custom authorization policies and ASP.NET Core authentication and authorization middlewares. For more details on ASP.NET Core authentication, see [the official documentation](https://learn.microsoft.com/en-us/aspnet/core/security/authentication/?view=aspnetcore-8.0).\n\nYou can view the examples below in the `Sample.Dashboard.Auth` sample project.\n\n#### Example: Anonymous Access\n\n```csharp\nservices.AddCap(cap =>\n    {\n        cap.UseDashboard(d =>\n        {\n            d.AllowAnonymousExplicit = true;\n        });\n        cap.UseInMemoryStorage();\n        cap.UseInMemoryMessageQueue();\n    });\n```\n\n#### Example: Open ID Connect\n\n```csharp\nservices\n    .AddAuthorization(options =>\n        { \n            options.AddPolicy(DashboardAuthorizationPolicy, policy => policy\n                .AddAuthenticationSchemes(OpenIdConnectDefaults.AuthenticationScheme)\n                .RequireAuthenticatedUser());\n        })\n        .AddAuthentication(opt => opt.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme)\n        .AddCookie()\n        .AddOpenIdConnect(options =>\n        {\n            ...\n        });\n    \n    services.AddCap(cap =>\n    {\n        cap.UseDashboard(d =>\n        {\n            d.AuthorizationPolicy = DashboardAuthorizationPolicy;\n        });\n        cap.UseInMemoryStorage();\n        cap.UseInMemoryMessageQueue();\n    });\n```\n\n#### Example: Custom Authentication Scheme\n\n```csharp\nconst string MyDashboardAuthenticationPolicy = \"MyDashboardAuthenticationPolicy\";\n    \nservices.AddAuthorization(options =>\n    { \n        options.AddPolicy(MyDashboardAuthenticationPolicy, policy => policy\n            .AddAuthenticationSchemes(MyDashboardAuthenticationSchemeDefaults.Scheme)\n            .RequireAuthenticatedUser());\n    })\n    .AddAuthentication()\n    .AddScheme<MyDashboardAuthenticationSchemeOptions, MyDashboardAuthenticationHandler>(MyDashboardAuthenticationSchemeDefaults.Scheme, null);\n    \nservices.AddCap(cap =>\n    {\n        cap.UseDashboard(d =>\n        {\n            d.AuthorizationPolicy = MyDashboardAuthenticationPolicy;\n        });\n        cap.UseInMemoryStorage();\n        cap.UseInMemoryMessageQueue();\n    });\n```\n"
  },
  {
    "path": "docs/content/user-guide/en/monitoring/diagnostics.md",
    "content": "# Diagnostics\n\nDiagnostics provides a set of features that make it easy to document critical operations that occur during application execution, their execution time, etc., allowing administrators to find the root cause of problems, especially in production environments.\n\n## Tracing\n\nCAP provides support for `DiagnosticSource` with a listener name of `CapDiagnosticListener`.\n\nDiagnostics provides the following tracing event information:\n\n* Before the message is persisted\n* After the message is persisted\n* Message persistence exception\n* Before the message is sent to the message queue\n* After the message is sent to the message queue\n* Message sending exception to the message queue\n* Messages saved from message queue consumption before persistence\n* After messages are saved from message queue consumption\n* Before the subscriber method is executed\n* After the subscriber method is executed\n* Subscriber method execution exception\n\nRelated objects can be found in the `DotNetCore.CAP.Diagnostics` namespace.\n\n### Tracing with Apache Skywalking\n\nSkywalking's C# client provides support for CAP Diagnostics. You can use [SkyAPM-dotnet](https://github.com/SkyAPM/SkyAPM-dotnet) for tracking.\n\nRead the [README](https://github.com/SkyAPM/SkyAPM-dotnet/blob/master/README.md) to integrate it into your project.\n\nExample tracking images:\n\n![](https://user-images.githubusercontent.com/8205994/71006463-51025980-2120-11ea-82dc-bffa5530d515.png)\n\n![](https://user-images.githubusercontent.com/8205994/71006589-7b541700-2120-11ea-910b-7e0f2dfddce8.png)\n\n### Other APM Support\n\nCurrently, we only support Skywalking. If you want to support CAP diagnostic events in other APMs, you can refer to the code [here](https://github.com/SkyAPM/SkyAPM-dotnet/tree/master/src/SkyApm.Diagnostics.CAP) for implementation. We also welcome Pull Requests.\n\n## Metrics\n\nMetrics are numerical measurements reported over time. They are typically used to monitor application health and generate alerts. For example, a web service might track the number of requests it receives each second, how many milliseconds it takes to respond, and how many responses return an error to the user.\n\nCAP 7.0 is support for `EventSource`, and the counters name is `DotNetCore.CAP.EventCounter`.\n\nCAP provides the following metrics:\n\n* Publish rate pre seconds\n* Consume rate pre seconds\n* Invoke Subscriber rate pre seconds\n* Subscriber elpased time mean pre seconds \n\n### Monitor with dotnet-counters\n\n[dotnet-counters](https://learn.microsoft.com/zh-cn/dotnet/core/diagnostics/dotnet-counters) is a performance monitoring tool for ad-hoc health monitoring and first-level performance investigation. It can observe performance counter values that are published via the EventCounter API or the Meter API. \n\nUse the following commands to monitor metrics in CAP:\n\n```ps\ndotnet-counters ps\ndotnet-counters monitor --process-id=25496 --counters=DotNetCore.CAP.EventCounter\n```\n\nprocess-id： The ID of the CAP process to collect counter data from.\n\n![img](../../../img/dotnet-counters.gif)\n\n### Monitor with dashboard\n\nYou can configure `x.UseDashboard()` to open the dashboard to view Metrics graph charts.\n\n![img](../../../img/dashboard-metrics.gif)\n\nIn the Realtime Metric Graph, the time axis will scroll in real time over time so that you can see the rate of publishing and consuming messages per second, And the consumer execution time is \"dotted\" on the Y1 axis (Y0 axis is the rates, and the Y1 axis is the execution elpsed time).\n \n\n"
  },
  {
    "path": "docs/content/user-guide/en/monitoring/kubernetes.md",
    "content": "# Kubernetes\n\n[Kubernetes](https://kubernetes.io), also known as K8s, is an open-source system for automating deployment, scaling, and management of containerized applications.\n\n## Kubernetes in the Dashboard\n\nThe Dashboard has supported Kubernetes as a service discovery mechanism since version 7.2.0. You can navigate to the Nodes page, select a Kubernetes namespace, and CAP will list all Services within that namespace. After clicking the Switch button, the Dashboard will check if the CAP service of that node is available. If it is, the Dashboard will proxy to the switched node to display data.\n\nHere is a configuration example:\n\n```cs\nservices.AddCap(x =>\n{\n    // ...\n    x.UseDashboard();\n    x.UseK8sDiscovery();\n});\n```\n\n## UseK8sDiscovery Configuration\n\nThis configuration option controls whether the Dashboard/Nodes page lists every K8s `Service` by default. If set to `True`, only services with the `dotnetcore.cap.visibility: show` label will be listed. See the **Kubernetes Labels Configuration** section for more information about labels.\n\n* **ShowOnlyExplicitVisibleNodes** \n\n> Default: false\n\n```cs\nservices.AddCap(x =>\n{\n    // ...\n    x.UseK8sDiscovery(opt =>\n    {\n        opt.ShowOnlyExplicitVisibleNodes = true;\n    });\n});\n```\n\nThe component automatically detects whether it is running inside a Kubernetes cluster. If it is, the Pod must be granted Kubernetes API permissions. Refer to the next section.\n\n## Assigning Pod Access to Kubernetes API \n\nIf the ServiceAccount associated with your Deployment does not have access to the Kubernetes API, you must grant `namespaces` and `services` resources with `get` and `list` permissions.\n\nHere is an example YAML. First, create a ServiceAccount and ClusterRole with the appropriate permissions, then bind them using ClusterRoleBinding. Finally, use `serviceAccountName: api-access` in your Deployment.\n\n```\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: api-access\n\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  name: ns-svc-reader\nrules:\n- apiGroups: [\"\"]\n  resources: [\"namespaces\", \"services\"]\n  verbs: [\"get\", \"watch\", \"list\"]\n\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: read-pods\nsubjects:\n- kind: ServiceAccount\n  name: api-access\n  namespace: default\nroleRef:\n  kind: ClusterRole\n  name: ns-svc-reader\n  apiGroup: rbac.authorization.k8s.io\n  \n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: api-access-deployment\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: api-access-app\n  template:\n    metadata:\n      labels:\n        app: api-access-app\n    spec:\n      serviceAccountName: api-access\n      containers:\n      - name: api-access-container\n        image: your_image\n        \n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: api-access-service\nspec:\n  selector:\n    app: api-access-app\n  ports:\n    - protocol: TCP\n      port: 80\n      targetPort: 80\n```\n\nFrom version `8.3.0` and onwards you can use a `Role` instead of `ClusterRole` to allow discovery of services only inside the namespace that the dashboard is running. Kubernetes Roles has limited jurisdiction inside the namespace. In the above example just remove ClusterRole and ClusterRoleBinding and instead use the following: \n\n```\napiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  name: ns-svc-reader\nrules:\n- apiGroups: [\"\"]\n  resources: [\"services\"]\n  verbs: [\"get\", \"watch\", \"list\"]\n\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: read-pods\nsubjects:\n- kind: ServiceAccount\n  name: api-access\n  namespace: default\nroleRef:\n  kind: ClusterRole\n  name: ns-svc-reader\n  apiGroup: rbac.authorization.k8s.io\n\n```\n\n## Kubernetes Labels Configuration\n\nThe list of Nodes showed in the dashboard can be controlled by adding labels to the to your kubernetes services. \n\n\n- `dotnetcore.cap.visibility` label is used to show or hide a service from the list. \n\n    > Allowed Values: show | hide\n\n    > Examples: `dotnetcore.cap.visibility: show` or `dotnetcore.cap.visibility: hide`\n\nBy default every k8s service is listed with the first port found in the service. However if more ports are present on the service you can select the wanted by using the following labels: \n\n- `dotnetcore.cap.portName` label is used to filter the wanted port of the service. \n\n    > Allowed Values: string\n\n    > Examples: `dotnetcore.cap.portName: grpc` or `dotnetcore.cap.portName: http`\n\nIf not found any port with the given name, it will try to match the next label portIndex\n\n- `dotnetcore.cap.portIndex` label is used to filter the wanted port of the service. This filter is taken into consideration only if no label portName is set or a non matching portName is set.\n\n    > Allowed Values: number represented as string ex: '2' or '14'\n\n    > Examples: `dotnetcore.cap.portIndex: '1'` or `dotnetcore.cap.portIndex: '3'`\n\n  If the provided index is outside of bounds then it will fallback to the first port (index:0)\n\n\n\n\n\n## Using Dashboard Standalone\n\nYou can use the Dashboard standalone without configuring CAP, in this case, the Dashboard can be deployed as a separate Pod in the Kubernetes cluster just for data viewing. The service to be viewed no longer needs to configure the `cap.UseK8sDiscovery()` option.\n\n```\nservices.AddCapDashboardStandalone();\n```\n\nSimilarly, you need to configure the access for the ServiceAccount for this Pod."
  },
  {
    "path": "docs/content/user-guide/en/monitoring/opentelemetry.md",
    "content": "# OpenTelemetry\n\n[https://opentelemetry.io/](https://opentelemetry.io/)\n\nOpenTelemetry is a collection of tools, APIs, and SDKs that helps you instrument, generate, collect, and export telemetry data (metrics, logs, and traces). This data helps you analyze your software's performance and behavior.nTelemetry \n\nhttps://opentelemetry.io/\n\nOpenTelemetry is a collection of tools, APIs, and SDKs. Use it to instrument, generate, collect, and export telemetry data (metrics, logs, and traces) to help you analyze your software’s performance and behavior.\n\n## Integration\n\nYou can find information about using OpenTelemetry in console applications or ASP.NET Core [here](https://opentelemetry.io/docs/instrumentation/net/getting-started/). Here we mainly describe how to trace CAP data to OpenTelemetry.\n\n### Configuration\n\nInstall the CAP OpenTelemetry package into your project:\n\n```C#\ndotnet add package DotNetCore.CAP.OpenTelemetry\n```\n\nOpenTelemetry data comes from [Diagnostics](diagnostics.md). Add the CAP instrumentation to your OpenTelemetry configuration:\n\n```C#\nservices.AddOpenTelemetryTracing((builder) => builder\n    .AddAspNetCoreInstrumentation()\n    .AddCapInstrumentation()    // <-- Add this line\n    .AddZipkinExporter()\n);\n```\n\nIf you don't use a framework that handles this automatically (like ASP.NET Core), make sure you enable a listener. For example:\n\n```C#\nActivitySource.AddActivityListener(new ActivityListener()\n{\n    ShouldListenTo = _ => true,\n    Sample = (ref ActivityCreationOptions<ActivityContext> _) => ActivitySamplingResult.AllData,\n    ActivityStarted = activity => Console.WriteLine($\"{activity.ParentId}:{activity.Id} - Start\"),\n    ActivityStopped = activity => Console.WriteLine($\"{activity.ParentId}:{activity.Id} - Stop\")\n});\n```\nHere is a diagram of CAP's tracking data in Zipkin:\n\n<img src=\"/img/opentelemetry.png\">\n\n### Context Propagation\n\nCAP supports [Context Propagation](https://opentelemetry.io/docs/instrumentation/js/propagation/) by injecting `traceparent` and `baggage` headers when sending messages and restoring the context from those headers when receiving messages.\n\nCAP uses the configured `Propagators.DefaultTextMapPropagator` propagator, which is usually set to both `TraceContextPropagator` and `BaggagePropagator` by the [dotnet OpenTelemetry SDK](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry/Sdk.cs#L21), but can be configured in your client program. For example, to opt out of Baggage propagation, you can call:\n\n```C#\nOpenTelemetry.Sdk.SetDefaultTextMapPropagator(\n    new TraceContextPropagator());\n```\n\nFor more details, see the [dotnet OpenTelemetry.Api README](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Api/README.md?plain=1#L455)."
  },
  {
    "path": "docs/content/user-guide/en/samples/eshoponcontainers.md",
    "content": "# eShopOnContainers\n\neShopOnContainers is a sample application written in C# running on .NET Core that uses a microservice architecture and Domain Driven Design.\n\n> A .NET Core reference application powered by Microsoft, based on a simplified microservices architecture with Docker containers.\n\n> This reference application is cross-platform on both server and client sides, thanks to .NET Core services that can run on Linux or Windows containers depending on your Docker host, and Xamarin for mobile apps running on Android, iOS, or Windows/UWP, plus any browser for client web apps.\n\n> The architecture demonstrates a microservice-oriented implementation with multiple autonomous microservices (each owning its own data/database) and implementing different approaches within each microservice (simple CRUD vs. DDD/CQRS patterns). It uses HTTP as the communication protocol between client apps and microservices, and supports asynchronous communication for data propagation across services based on Integration Events and an Event Bus (a lightweight message broker that you can choose between RabbitMQ or Azure Service Bus) plus other features in the roadmap.\n\n## eShopOnContainers with CAP\n\nYou can see how to use CAP in eShopOnContainers in the GitHub repository:\n\nhttps://github.com/yang-xiaodong/eShopOnContainers"
  },
  {
    "path": "docs/content/user-guide/en/samples/faq.md",
    "content": "# FAQ\n\n!!! faq \"Is there an IM group (e.g., Tencent QQ group) to learn and chat about CAP?\"\n\n    There is not. Instead of spending time in IM groups, I encourage developers to develop independent thinking skills and solve problems using the documentation. You can also create issues or send emails if problems persist.\n\n!!! faq \"Does each application need a separate database for producer and consumer in CAP?\"\n\n    Not necessarily. A recommendation is to use a dedicated database for each application. However, see the Q&A below for alternatives.\n\n!!! faq \"How can I use the same database for different applications?\"\n    \n    Define a table prefix name in the `ConfigureServices` method.\n    \n    Code example:\n\n    ```c#\n    public void ConfigureServices(IServiceCollection services)\n    {\n        services.AddCap(x =>\n        {\n            x.UseKafka(\"\");\n            x.UseMySql(opt =>\n            {\n                opt.ConnectionString = \"connection string\";\n                opt.TableNamePrefix = \"appone\"; // Use different table name prefix here\n            });\n        });\n    }\n    ```\n\n!!! faq \"Can CAP avoid using the database for event storage? I just want to send messages.\"\n\n    Not yet. CAP's purpose is to ensure consistency in microservice or SOA architectures. The solution is based on ACID features of the database. There's no point in a simple message queue wrapper without database support.\n\n!!! faq \"If the consumer fails, can I roll back the SQL executed by the producer?\"\n\n    No, you cannot roll back. CAP provides eventual consistency, not immediate rollback.\n\n    Consider a scenario where you call a third-party payment service. If you successfully call Alipay's interface but your own code fails afterward, will Alipay roll back? If not, what should you do? The same principle applies here.\n"
  },
  {
    "path": "docs/content/user-guide/en/samples/github.md",
    "content": "# GitHub Samples\n\nYou can find sample code in the GitHub repository:\n\nhttps://github.com/dotnetcore/CAP/tree/master/samples\n\nCAP + Aspire + Azure Service Bus + Azure SQL:\n\nhttps://github.com/NikiforovAll/cap-aspire"
  },
  {
    "path": "docs/content/user-guide/en/storage/general.md",
    "content": "# General\n\nCAP requires a storage medium with persistence capabilities to store event messages in databases or other NoSQL facilities. CAP uses this approach to protect against message loss in any environment or network issues. Reliability of messages is the cornerstone of distributed transactions, so messages must never be lost.\n\n## Persistence\n\n### Before Sent\n\nBefore the message enters the message queue, CAP persists the message in a local database table. This ensures that the message is not lost when the message queue is unavailable or a network error occurs.\n\nTo ensure the reliability of this mechanism, CAP uses the same database transactions as the business code to ensure that business operations and CAP messages are consistent during persistence. If any exception occurs during message persistence, the database will roll back.\n\n### After Sent\n\nAfter the message enters the message queue, CAP starts the persistence function of the message queue. Here's how CAP messages are persisted in RabbitMQ and Kafka.\n\nFor message persistence in RabbitMQ, CAP uses a consumer queue with message persistence, though exceptions may occur.\n\n!!! info \"Ready for Production?\"\n    By default, queues registered by CAP in RabbitMQ are persistent. For production use, we recommend that you start all consumers once to create persistent queues. This ensures all queues are created before messages are sent.\n\nSince Kafka has built-in message persistence using files, it automatically ensures that messages are properly persisted without loss once they enter Kafka.\n\n## Storage\n\n### Supported storages\n\nCAP supports the following types of transaction-enabled databases for storage:\n\n* [SQL Server](sqlserver.md)\n* [MySQL](mysql.md)\n* [PostgreSql](postgresql.md)\n* [MongoDB](mongodb.md)\n* [In-Memory Storage](in-memory-storage.md)\n\nAfter CAP is started, two tables are generated in used storage, by default the name is `Cap.Published` and `Cap.Received`.\n\n### Storage Data Structure\n\nTable structure of **Published** :\n\nNAME | DESCRIPTION | TYPE\n:---|:---|:---\nId | Message Id | int\nVersion | Message Version | string\nName | Topic Name | string\nContent | Json Content | string\nAdded | Added Time | DateTime\nExpiresAt | Expire time | DateTime\nRetries | Retry times | int\nStatusName | Status Name | string\n \nTable structure of **Received** :\n\nNAME | DESCRIPTION | TYPE\n:---|:---|:---\nId | Message Id | int\nVersion | Message Version | string\nName | Topic Name | string\nGroup | Group Name | string\nContent | Json Content | string\nAdded | Added Time | DateTime\nExpiresAt | Expire time | DateTime\nRetries | Retry times | int\nStatusName | Status Name | string\n\nTable structure of **Lock** (Optional):\n\nNAME | DESCRIPTION | TYPE\n:---|:---|:---\nKey | Lock Id | string\nInstance | Acquired instance of lock | string\nLastLockTime | Last acquired lock time | DateTime\n\n### Wapper Object\n\nWhen CAP sends a message, it will store original message object in a second package in the `Content` field. \n\nThe following is the **Wapper Object** data structure of Content field.\n\nNAME | DESCRIPTION | TYPE\n:---|:---|:---\nId\t| Message Id\t| string\nTimestamp |\tMessage created time |\tstring\nContent |\tMessage content |\tstring\nCallbackName |\tConsumer callback topic name | string\n\nThe `Id` field is generate using the mongo [objectid algorithm](https://www.mongodb.com/blog/post/generating-globally-unique-identifiers-for-use-with-mongodb).\n\n\n## Community-supported extensions\n\nThanks to the community for supporting CAP, the following is the implementation of community-supported storage\n\n* SQLite ([@colinin](https://github.com/colinin)) ：https://github.com/colinin/DotNetCore.CAP.Sqlite   \n\n* LiteDB ([@maikebing](https://github.com/maikebing)) ：https://github.com/maikebing/CAP.Extensions\n\n* SQLite & Oracle ([@cocosip](https://github.com/cocosip)) ：https://github.com/cocosip/CAP-Extensions   \n"
  },
  {
    "path": "docs/content/user-guide/en/storage/in-memory-storage.md",
    "content": "# In-Memory Storage\n\nIn-memory storage is commonly used in development and test environments. However, if you use memory-based storage, you lose the reliability guarantee of local transaction messages.\n\n## Configuration\n\nTo use in-memory storage, you need to install the following package from NuGet:\n\n```powershell\nPM> Install-Package DotNetCore.CAP.InMemoryStorage\n```\n\nNext, add configuration items to the `ConfigureServices` method of `Startup.cs`.\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UseInMemoryStorage();\n        // x.UseXXX ...\n    });\n}\n\n```\n\nCAP will clean successful messages from memory every 5 minutes.\n\n## Publish with transaction\n\nIn-memory storage does **not support** transactional message publishing.\n"
  },
  {
    "path": "docs/content/user-guide/en/storage/mongodb.md",
    "content": "# MongoDB\n\nMongoDB is a cross-platform, document-oriented database program. Classified as a NoSQL database, MongoDB uses JSON-like documents with dynamic schema.\n\nCAP has supported MongoDB since version 2.3. MongoDB supports ACID transactions starting from version 4.0, so CAP requires MongoDB 4.0 or higher. Additionally, MongoDB must be deployed as a cluster because ACID transactions require a replica set.\n\nFor a quick development of the MongoDB 4.0+ cluster for the development environment, you can refer to [this article](https://www.cnblogs.com/savorboard/p/mongodb-4-cluster-install.html).\n\n## Configuration\n\nTo use MongoDB storage, you need to install the following package from NuGet:\n\n```powershell\nPM> Install-Package DotNetCore.CAP.MongoDB\n\n```\n\nNext, add configuration items to the `ConfigureServices` method of `Startup.cs`.\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UseMongoDB(opt=>{\n            //MongoDBOptions\n        });\n        // x.UseXXX ...\n    });\n}\n\n```\n\n#### MongoDB Options\n\nNAME | DESCRIPTION | TYPE | DEFAULT\n:---|:---|---|:---\nDatabaseName | Database name | string | cap \nDatabaseConnection | Database connection string | string | mongodb://localhost:27017\nReceivedCollection | Database received message collection name | string | cap.received\nPublishedCollection | Database published message collection name | string | cap.published\n\n## Publish with transaction\n\nThe following example shows how to integrate CAP with MongoDB for local transactions:\n\n```csharp\n// NOTE: Before testing, you need to create the database and collection first.\n// MongoDB cannot automatically create databases and collections within transactions,\n// so you must create them separately. For example, insert a record to auto-create the collection.\n\n// var mycollection = _client.GetDatabase(\"test\")\n//          .GetCollection<BsonDocument>(\"test.collection\");\n// mycollection.InsertOne(new BsonDocument { { \"test\", \"test\" } });\n\nusing (var session = _client.StartTransaction(_capBus, autoCommit: false))\n{\n    var collection = _client.GetDatabase(\"test\")\n            .GetCollection<BsonDocument>(\"test.collection\");\n\n    collection.InsertOne(session, new BsonDocument { { \"hello\", \"world\" } });\n\n    _capBus.Publish(\"sample.rabbitmq.mongodb\", DateTime.Now);\n\n    session.CommitTransaction();\n}\n```"
  },
  {
    "path": "docs/content/user-guide/en/storage/mysql.md",
    "content": "# MySQL\n\nMySQL is an open-source relational database management system. CAP fully supports MySQL. \n\n## Configuration\n\nTo use MySQL storage, you need to install the following package from NuGet:\n```powershell\nPM> Install-Package DotNetCore.CAP.MySql\n\n```\n\nNext, add configuration items to the `ConfigureServices` method of `Startup.cs`.\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UseMySql(opt=>{\n            //MySqlOptions\n        });\n        // x.UseXXX ...\n    });\n}\n\n```\n\n#### MySqlOptions\n\nNAME | DESCRIPTION | TYPE | DEFAULT\n:---|:---|---|:---\nTableNamePrefix | CAP table name prefix | string | cap \nConnectionString | Database connection string | string | null\n\n## Publish with transaction\n\n### ADO.NET with Transaction\n\n```csharp\nprivate readonly ICapPublisher _capBus;\n\nusing (var connection = new MySqlConnection(AppDbContext.ConnectionString))\n{\n    using (var transaction = connection.BeginTransaction(_capBus, autoCommit: false))\n    {\n        // Your business code\n        connection.Execute(\"insert into test(name) values('test')\", \n            transaction: (IDbTransaction)transaction.DbTransaction);\n        \n        _capBus.Publish(\"sample.rabbitmq.mysql\", DateTime.Now);\n\n        transaction.Commit();\n    }\n}\n```\n\n### Entity Framework with Transaction\n\n```csharp\nprivate readonly ICapPublisher _capBus;\n\nusing (var trans = dbContext.Database.BeginTransaction(_capBus, autoCommit: false))\n{\n    dbContext.Persons.Add(new Person() { Name = \"ef.transaction\" });\n    \n    _capBus.Publish(\"sample.rabbitmq.mysql\", DateTime.Now);\n\n    dbContext.SaveChanges();\n    trans.Commit();\n}\n```"
  },
  {
    "path": "docs/content/user-guide/en/storage/postgresql.md",
    "content": "# PostgreSQL\n\nPostgreSQL is an open-source relational database management system. CAP fully supports PostgreSQL. \n\n## Configuration\n\nTo use PostgreSQL storage, you need to install the following package from NuGet:\n\n```powershell\nPM> Install-Package DotNetCore.CAP.PostgreSql\n\n```\n\nNext, add configuration items to the `ConfigureServices` method of `Startup.cs`.\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UsePostgreSql(opt=>{\n            //PostgreSqlOptions\n        }); \n        // x.UseXXX ...\n    });\n}\n\n```\n\n#### PostgreSqlOptions\n\nNAME | DESCRIPTION                | TYPE                 | DEFAULT\n:---|:---------------------------|----------------------|:---\nSchema | Database schema            | string               | cap \nConnectionString | Database connection string | string               |\nDataSource | [Data source](https://www.npgsql.org/doc/basic-usage.html#data-source) | [NpgsqlDataSource](https://www.npgsql.org/doc/api/Npgsql.NpgsqlDataSource.html) |\n\n## Publish with transaction\n\n### ADO.NET with Transaction\n\n```csharp\nprivate readonly ICapPublisher _capBus;\n\nusing (var connection = new NpgsqlConnection(\"ConnectionString\"))\n{\n    using (var transaction = connection.BeginTransaction(_capBus, autoCommit: false))\n    {\n        // Your business code\n        connection.Execute(\"insert into test(name) values('test')\", \n            transaction: (IDbTransaction)transaction.DbTransaction);\n        \n        _capBus.Publish(\"sample.rabbitmq.mysql\", DateTime.Now);\n\n        transaction.Commit();\n    }\n}\n```\n\n### Entity Framework with Transaction\n\n```csharp\nprivate readonly ICapPublisher _capBus;\n\nusing (var trans = dbContext.Database.BeginTransaction(_capBus, autoCommit: false))\n{\n    dbContext.Persons.Add(new Person() { Name = \"ef.transaction\" });\n    \n    _capBus.Publish(\"sample.rabbitmq.mysql\", DateTime.Now);\n\n    dbContext.SaveChanges();\n    trans.Commit();\n}\n```"
  },
  {
    "path": "docs/content/user-guide/en/storage/sqlserver.md",
    "content": "# SQL Server\n\nSQL Server is a relational database management system developed by Microsoft. CAP fully supports SQL Server. \n\n!!! warning \"Warning\"\n    We currently use `Microsoft.Data.SqlClient` as the database driver, which is the future of SQL Server drivers. We have deprecated `System.Data.SqlClient` and recommend upgrading to the new driver.\n\n## Configuration\n\nTo use SQL Server storage, you need to install the following package from NuGet:\n\n```powershell\nPM> Install-Package DotNetCore.CAP.SqlServer\n\n```\n\nNext, add configuration items to the `ConfigureServices` method of `Startup.cs`.\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UseSqlServer(opt=>{\n            //SqlServerOptions\n        }); \n        // x.UseXXX ...\n    });\n}\n\n```\n\n#### SqlServerOptions\n\nNAME | DESCRIPTION | TYPE | DEFAULT\n:---|:---|---|:---\nSchema | Database schema | string | Cap\nConnectionString | Database connection string | string | \n\n## Publish with transaction\n\n### ADO.NET with Transaction\n\n```csharp\nprivate readonly ICapPublisher _capBus;\n\nusing (var connection = new SqlConnection(\"ConnectionString\"))\n{\n    using (var transaction = connection.BeginTransaction(_capBus, autoCommit: false))\n    {\n        // Your business code\n        connection.Execute(\"insert into test(name) values('test')\", \n            transaction: (IDbTransaction)transaction.DbTransaction);\n        \n        _capBus.Publish(\"sample.rabbitmq.mysql\", DateTime.Now);\n\n        transaction.Commit();\n    }\n}\n```\n\n### Entity Framework with Transaction\n\n```csharp\nprivate readonly ICapPublisher _capBus;\n\nusing (var trans = dbContext.Database.BeginTransaction(_capBus, autoCommit: false))\n{\n    dbContext.Persons.Add(new Person() { Name = \"ef.transaction\" });\n    \n    _capBus.Publish(\"sample.rabbitmq.mysql\", DateTime.Now);\n\n    dbContext.SaveChanges();\n    trans.Commit();\n}\n```\n"
  },
  {
    "path": "docs/content/user-guide/en/transport/aws-sqs.md",
    "content": "# Amazon SQS\n\nAWS SQS is a fully managed message queuing service that enables you to decouple and scale microservices, distributed systems, and serverless applications.\n\nAWS SNS is a highly available, durable, secure, fully managed pub/sub messaging service that enables you to decouple microservices, distributed systems, and serverless applications.\n\n## How CAP Uses AWS SNS and SQS\n\n### SNS\n\nBecause CAP works based on the topic pattern, it requires AWS SNS, which simplifies the publish-subscribe architecture for messaging.\n\nWhen CAP starts, all subscription names are registered as SNS topics. You will see a list of all registered topics in the AWS management console.\n\nSNS does not support certain characters such as `.`, `:` in topic names, so CAP replaces them. It replaces `.` with `-` and `:` with `_`.\n\n!!! note \"Precautions\"\n    Amazon SNS currently limits published messages to a maximum size of 256 KB.\n\nFor example, you have the following two subscriber methods in your current project\n\n```C#\n[CapSubscribe(\"sample.sns.foo\")]\npublic void TestFoo(DateTime value)\n{\n}\n\n[CapSubscribe(\"sample.sns.bar\")]\npublic void TestBar(DateTime value)\n{\n}\n```\nAfter CAP startups, you will see in SNS management console:\n\n![img](../../../img/aws-sns-demo.png)\n\n### SQS\n\nFor each consumer group, CAP will create a corresponding SQS queue. The queue name is the value of `DefaultGroup` in the configuration options, and the queue type is Standard.\n\nThe SQS queue will subscribe to the SNS topic as shown below:\n\n![img](../../../img/aws-sns-demo.png)\n\n!!! warning \"Precautions\"\n    Due to AWS SNS limitations, when you remove a subscription method, CAP will not automatically delete the topics or queues in AWS SNS or SQS. You need to delete them manually.\n\n\n## Configuration\n\nTo use AWS SQS as a transporter, you need to install the following package from NuGet:\n\n```shell\n\nInstall-Package DotNetCore.CAP.AmazonSQS\n\n```\n\nNext, add configuration items to the `ConfigureServices` method of `Startup.cs`:\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UseAmazonSQS(opt=>\n        {\n            //AmazonSQSOptions\n        });\n        // x.UseXXX ...\n    });\n}\n\n```\n\n#### AmazonSQS Options\n\nThe SQS configuration parameters provided directly by the CAP:\n\nNAME | DESCRIPTION | TYPE | DEFAULT\n:---|:---|---|:---\nRegion | AWS Region | Amazon.RegionEndpoint | \nCredentials | AWS AK SK Information | Amazon.Runtime.AWSCredentials | \n\nIf your application runs on AWS EC2, you don't need to set credentials. Instead, you can directly apply an IAM policy to the EC2 instance.\n\nCredentials require SNS and SQS IAM permissions."
  },
  {
    "path": "docs/content/user-guide/en/transport/azure-service-bus.md",
    "content": "# Azure Service Bus\n\nMicrosoft Azure Service Bus is a fully managed enterprise integration message broker. Service Bus is most commonly used to decouple applications and services, and is a reliable and secure platform for asynchronous data and state transfer.\n\nAzure Service Bus can be used in CAP as a message transporter.\n\n## Configuration\n\n!!! warning \"Requirement\"\n    For the Service Bus pricing tier, CAP requires \"Standard\" or \"Premium\" to support Topic functionality.\n\nTo use Azure Service Bus as a message transporter, you need to install the following package from NuGet:\n\n```powershell\nPM> Install-Package DotNetCore.CAP.AzureServiceBus\n```\n\nNext, add configuration items to the `ConfigureServices` method of `Startup.cs`:\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UseAzureServiceBus(opt=>\n        {\n            //AzureServiceBusOptions\n        });\n        // x.UseXXX ...\n    });\n}\n\n```\n\n#### Azure Service Bus Options\n\nThe Azure Service Bus configuration options provided by CAP:\n\n| NAME                                 | DESCRIPTION                                                                                                                                                           | TYPE                                                                   | DEFAULT                          |\n| :----------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | :------------------------------- |\n| ConnectionString                     | Endpoint address                                                                                                                                                      | string                                                                 |                                  |\n| TopicPath                            | Topic entity path                                                                                                                                                     | string                                                                 | cap                              |\n| EnableSessions                       | Enable [Service bus sessions](https://docs.microsoft.com/en-us/azure/service-bus-messaging/message-sessions)                                                          | bool                                                                   | false                            |\n| MaxConcurrentSessions                | The maximum number of concurrent sessions that the processor can handle. Not applicable when EnableSessions is false.                                                 | int                                                                    | 8                                |\n| SessionIdleTimeout                   | The maximum time to wait for a new message before the session is closed. If not specified, 60 seconds will be used by Azure Service Bus.                              | TimeSpan                                                               | null                             |\n| SubscriptionAutoDeleteOnIdle         | Automatically delete subscription after a certain idle interval.                                                                                                      | TimeSpan                                                               | TimeSpan.MaxValue                |\n| SubscriptionMessageLockDuration      | The amount of time the message is locked by a given receiver so that no other receiver receives the same message.                                                     | TimeSpan                                                               | 60 seconds                       |\n| SubscriptionDefaultMessageTimeToLive | The default message time to live value for a subscription. This is the duration after which the message expires.                                                      | TimeSpan                                                               | TimeSpan.MaxValue                |\n| SubscriptionMaxDeliveryCount         | The maximum number of times a message is delivered to the subscription before it is dead-lettered.                                                                    | int                                                                    | 10                               |\n| MaxAutoLockRenewalDuration           | The maximum duration within which the lock will be renewed automatically. This value should be greater than the longest message lock duration.                        | TimeSpan                                                               | 5 minutes                        |\n| ManagementTokenProvider              | Token provider                                                                                                                                                        | ITokenProvider                                                         | null                             |\n| AutoCompleteMessages                 | Gets a value that indicates whether the processor should automatically complete messages after the message handler has completed processing                           | bool                                                                   | false                            |\n| CustomHeadersBuilder                 | Adds custom and/or mandatory Headers for incoming messages from heterogeneous systems.                                                                                | `Func<Message, IServiceProvider, List<KeyValuePair<string, string>>>?` | null                             |\n| Namespace                            | Namespace of Servicebus , Needs to be set when using with TokenCredential Property                                                                                    | string                                                                 | null                             |\n| DefaultCorrelationHeaders            | Adds additional correlation properties to all [correlation filters](https://learn.microsoft.com/en-us/azure/service-bus-messaging/topic-filters#correlation-filters). | IDictionary<string, string>                                            | Dictionary<string, string>.Empty |\n| SQLFilters                           | Custom SQL Filters by name and expression on Topic Subscribtion                                                                                                       | List<KeyValuePair<string, string>>                                     | null                             |\n\n#### Sessions\n\nWhen sessions are enabled (see the `EnableSessions` option above), every message sent will have a session ID. To control the session ID, include an extra header with the name `AzureServiceBusHeaders.SessionId` when publishing events:\n\n```C#\nICapPublisher capBus = ...;\nstring yourEventName = ...;\nYourEventType yourEvent = ...;\n\nDictionary<string, string> extraHeaders = new Dictionary<string, string>();\nextraHeaders.Add(AzureServiceBusHeaders.SessionId, <your-session-id>);\n\ncapBus.Publish(yourEventName, yourEvent, extraHeaders);\n```\n\nIf no session ID header is present, the message ID will be used as the session ID.\n\n#### Heterogeneous Systems\n\nSometimes you might want to listen to a message published by an external system. In this case, you need to add a set of two mandatory headers for CAP compatibility, as shown below:\n\n```C#\nc.UseAzureServiceBus(asb =>\n{\n    asb.ConnectionString = ...\n    asb.CustomHeadersBuilder = (msg, sp) =>\n    [\n        new(DotNetCore.CAP.Messages.Headers.MessageId, sp.GetRequiredService<ISnowflakeId>().NextId().ToString()),\n        new(DotNetCore.CAP.Messages.Headers.MessageName, msg.RoutingKey)\n    ];\n});\n```\n\n#### SQL Filters\n\nYou can set SQL filters on the subscription level to get desired messages without having custom logic on the business side. For more information, see [Azure Service Bus SQL Filters](https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-messaging-sql-filter).\n\n`SQLFilters` is a list of `KeyValuePair<string, string>`, where the key is the filter name and the value is the SQL expression.\n\n```C#\nc.UseAzureServiceBus(asb =>\n{\n    asb.ConnectionString = ...\n    asb.SQLFilters = new List<KeyValuePair<string, string>> {\n            \n            new KeyValuePair<string,string>(\"IOTFilter\",\"FromIOTHub='true'\"),  // The message will be handled if ApplicationProperties contains IOTFilter and value is true\n            new KeyValuePair<string,string>(\"SequenceFilter\",\"sys.enqueuedSequenceNumber >= 300\")\n        };\n});\n```\n"
  },
  {
    "path": "docs/content/user-guide/en/transport/general.md",
    "content": "# Transports\n\nTransports move data between different parts of the system – between message producers and message brokers, between message brokers and the entity database, and even between message brokers and external systems.\n\n## Supported transports\n\nCAP supports several transport methods:\n\n* [RabbitMQ](rabbitmq.md)\n* [Kafka](kafka.md)\n* [Azure Service Bus](azure-service-bus.md)\n* [Amazon SQS](aws-sqs.md)\n* [NATS](nats.md)\n* [In-Memory Queue](in-memory-queue.md)\n* [Redis Streams](redis-streams.md)\n* [Apache Pulsar](pulsar.md)\n\n## Selecting a Transport\n\n Feature | RabbitMQ | Kafka | Azure Service Bus | In-Memory\n:--   |   :--:    | :--: | :--:               | :--  :\n**Use Case** | Reliable message transmission | Real-time data processing | Cloud integration | Testing and development\n**Distributed**   | ✔   | ✔    | ✔ |❌\n**Persistence** | ✔ | ✔ | ✔ | ❌\n**Performance**  |  Medium  |  High | Medium | High\n\n\nFor more comparisons:\n\n- [Azure Service Bus vs RabbitMQ](http://geekswithblogs.net/michaelstephenson/archive/2012/08/12/150399.aspx)\n- [Kafka vs RabbitMQ](https://stackoverflow.com/questions/42151544/is-there-any-reason-to-use-rabbitmq-over-kafka)\n\nThanks to the community for contributing to CAP! The following transport extensions are community-supported:\n\n* ActiveMQ ([@Lukas Zhang](https://github.com/lukazh/Lukaz.CAP.ActiveMQ)): https://github.com/lukazh\n\n* RedisMQ ([@木木](https://github.com/difudotnet)): https://github.com/difudotnet/CAP.RedisMQ.Extensions\n\n* ZeroMQ ([@maikebing](https://github.com/maikebing)): https://github.com/maikebing/CAP.Extensions\n\n* MQTT ([@john jiang](https://github.com/jinzaz)): https://github.com/jinzaz/jinzaz.CAP.MQTT\n\n\n\n"
  },
  {
    "path": "docs/content/user-guide/en/transport/in-memory-queue.md",
    "content": "# In-Memory Queue\n\nIn-Memory Queue is a memory-based message queue provided by the [community](https://github.com/yang-xiaodong/Savorboard.CAP.InMemoryMessageQueue).\n\n## Configuration\n\nTo use in-memory queue as a message transporter, you need to install the following package from NuGet:\n\n```powershell\nPM> Install-Package Savorboard.CAP.InMemoryMessageQueue\n\n```\n\nNext, add configuration options to the `ConfigureServices` method of `Startup.cs`:\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UseInMemoryMessageQueue();\n        // x.UseXXX ...\n    });\n}\n\n```"
  },
  {
    "path": "docs/content/user-guide/en/transport/kafka.md",
    "content": "# Apache Kafka\n\n[Apache Kafka](https://kafka.apache.org/) is an open-source event streaming platform developed by LinkedIn and donated to the Apache Software Foundation. It is written in Scala and Java.\n\nKafka can be used in CAP as a message transporter. \n\n## Configuration\n\nTo use Kafka as a transporter, you need to install the following package from NuGet:\n\n```powershell\nPM> Install-Package DotNetCore.CAP.Kafka\n\n```\n\nThen you can add configuration items to the `ConfigureServices` method of `Startup.cs`.\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UseKafka(opt=>{\n            //KafkaOptions\n        });\n        // x.UseXXX ...\n    });\n}\n\n```\n\n#### Kafka Options\n\nThe Kafka configuration parameters provided directly by the CAP:\n\nNAME | DESCRIPTION | TYPE | DEFAULT\n:---|:---|---|:---\nServers | Broker server address | string | \nMainConfig | librdkafka configuration parameters | Dictionary<string, string> | See below\nConnectionPoolSize | connection pool size | int | 10\nCustomHeadersBuilder | Custom subscribe headers |  Func<> |  N/A\nRetriableErrorCodes | Retriable error codes when ConsumeException  | IList<ErrorCode> |  See code\nTopicOptions | The configuraiton of NumPartitions and ReplicationFactor | KafkaTopicOptions |  -1\n\n#### Kafka Main Configuration Options\n\nIf you need additional native Kafka configuration options, you can set them in the `MainConfig` configuration option:\n\n```csharp\nservices.AddCap(capOptions => \n{\n    capOptions.UseKafka(kafkaOption=>\n    {\n        // kafka options.\n        // kafkaOptions.MainConfig.Add(\"\", \"\");\n    });\n});\n```\n\n`MainConfig` is a configuration dictionary. You can find a list of supported configuration options at the following link:\n\n[https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md](https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md)\n\nTo prevent CAP from creating topics automatically, disable topic auto creation:\n\n```csharp\nservices.AddCap(capOptions =>\n{\n    capOptions.UseKafka(kafkaOption =>\n    {\n        kafkaOption.MainConfig.Add(\"allow.auto.create.topics\", \"false\");\n    });\n});\n```\n\n#### Custom Headers Builder Options\n\nWhen messages are sent from a heterogeneous system, CAP requires additional headers to be defined. By providing this parameter, you can set custom headers to ensure the subscriber works correctly.\n\nYou can find the description of heterogeneous system integration [here](../cap/messaging.md#heterogeneous-system-integration).\n\nSometimes, if you want to add additional context information from the broker to messages, you can also do this through this option. For example, you can add information such as offset or partition.\n\nExample:\n\n```C#\nx.UseKafka(opt =>\n{\n    //...\n\n    opt.CustomHeadersBuilder = (kafkaResult, sp) => new List<KeyValuePair<string, string>>\n    {\n        new KeyValuePair<string, string>(\"my.kafka.offset\", kafkaResult.Offset.ToString()),\n        new KeyValuePair<string, string>(\"my.kafka.partition\", kafkaResult.Partition.ToString())\n    };\n});\n```\n\nThen you can retrieve the headers you added like this:\n\n```C#\n[CapSubscribe(\"sample.kafka.postgrsql\")]\npublic void HeadersTest(DateTime value, [FromCap]CapHeader header)\n{\n    var offset = header[\"my.kafka.offset\"];\n    var partition = header[\"my.kafka.partition\"];\n}\n```\n\n"
  },
  {
    "path": "docs/content/user-guide/en/transport/nats.md",
    "content": "# NATS\n\n[NATS](https://nats.io/) is a simple, secure and performant communications system for digital systems, services and devices. NATS is part of the Cloud Native Computing Foundation (CNCF).\n\n!!! warning\n    Since version 5.2+, CAP features are implemented based on [JetStream](https://docs.nats.io/nats-concepts/jetstream), so JetStream must be explicitly enabled on the server.\n\n    **You must enable JetStream by specifying the `--jetstream` parameter when starting the NATS server to use CAP properly.**\n\n## Configuration\n\nTo use NATS as a transporter, you need to install the following package from NuGet:\n\n```powershell\n\nPM> Install-Package DotNetCore.CAP.NATS\n\n```\n\nThen you can add configuration items to the `ConfigureServices` method of `Startup.cs`.\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    services.AddCap(capOptions =>\n    {\n        capOptions.UseNATS(natsOptions=>{\n            //NATS Options\n        });\n    });\n}\n\n```\n\n#### NATS Options\n\nNATS configuration parameters provided directly by the CAP:\n\nNAME | DESCRIPTION | TYPE | DEFAULT\n:---|:---|---|:---\nOptions | NATS client configuration | Options | Options\nServers | Server url/urls used to connect to the NATs server. | string | NULL\nConnectionPoolSize  | number of connections pool | uint | 10\nDeliverPolicy | The point in the stream to receive messages from (⚠️ Removed from version 8.1.0, use `ConsumerOptions` instead.) | enum | DeliverPolicy.New\nStreamOptions | 🆕 Stream configuration |  Action | NULL\nConsumerOptions | 🆕 Consumer configuration | Action | NULL\nCustomHeadersBuilder | Custom subscribe headers |  See the blow | NULL\n\n#### NATS Configuration Options\n\nIf you need additional native NATS configuration options, you can set them in the `Options` option:\n\n```csharp\nservices.AddCap(capOptions => \n{\n    capOptions.UseNATS(natsOptions=>\n    {\n        // NATS options.\n        natsOptions.Options.Url=\"\";\n    });\n});\n```\n\n`Options` is a NATS.Client `ConfigurationOptions`. You can find more details at this [link](http://nats-io.github.io/nats.net/class_n_a_t_s_1_1_client_1_1_options.html).\n\n#### Custom Headers Builder Option\n\nWhen messages are sent from a heterogeneous system, CAP requires additional headers to be defined. By providing this parameter, you can set custom headers to ensure the subscriber works correctly.\n\nYou can find the description of [Header Information](../cap/messaging.md#heterogeneous-system-integration) here.\n\nExample:\n\n```cs\nx.UseNATS(aa =>\n{\n    aa.CustomHeadersBuilder = (e, sp) =>\n    [\n        new(DotNetCore.CAP.Messages.Headers.MessageId, sp.GetRequiredService<ISnowflakeId>().NextId().ToString()),\n        new(DotNetCore.CAP.Messages.Headers.MessageName, e.Message.Subject)\n    ];\n});\n```\n"
  },
  {
    "path": "docs/content/user-guide/en/transport/pulsar.md",
    "content": "# Apache Pulsar\n\n[Apache Pulsar](https://pulsar.apache.org/) is a cloud-native, distributed messaging and streaming platform originally created at Yahoo! and now a top-level Apache Software Foundation project.\n\nPulsar can be used in CAP as a message transporter. \n\n## Configuration\n\nTo use Pulsar as a transporter, you need to install the following package from NuGet:\n\n```powershell\nPM> Install-Package DotNetCore.CAP.Pulsar\n\n```\n\nThen you can add configuration items to the `ConfigureServices` method of `Startup.cs`.\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UsePulsar(opt => {\n            //Pulsar options\n        });\n        // x.UseXXX ...\n    });\n}\n\n```\n\n#### Pulsar Options\n\nThe Pulsar configuration parameters provided directly by the CAP:\n\nNAME | DESCRIPTION | TYPE | DEFAULT\n:---|:---|---|:---\nServiceUrl | Broker server address | string | \nTlsOptions | Tls configuration | object | "
  },
  {
    "path": "docs/content/user-guide/en/transport/rabbitmq.md",
    "content": "# RabbitMQ\n\nRabbitMQ is an open-source message broker software that implements the Advanced Message Queuing Protocol (AMQP) and has been extended with a plug-in architecture to support additional protocols such as Streaming Text Oriented Messaging Protocol (STOMP), Message Queuing Telemetry Transport (MQTT), and others.\n\nRabbitMQ can be used in CAP as a message transporter. \n\n!!! warning \"Important Notes\"\n    When using RabbitMQ, the consumer integrated with the CAP application will automatically create a persistent queue after it starts for the first time. Subsequent messages will be normally transmitted to the queue and consumed.\n    \n    However, if you have never started the consumer, the queue will not be created. In this case, if you publish messages first, the RabbitMQ exchange will discard the messages until the consumer is started and the queue is created.\n\n## Configuration\n\nTo use RabbitMQ as a transporter, you need to install the following package from NuGet:\n\n```powershell\nPM> Install-Package DotNetCore.CAP.RabbitMQ\n\n```\n\nNext, add configuration items to the `ConfigureServices` method of `Startup.cs`.\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UseRabbitMQ(opt=>\n        {\n            //RabbitMQOptions\n        });\n        // x.UseXXX ...\n    });\n}\n\n```\n\n#### RabbitMQ Options\n\nThe RabbitMQ configuration parameters provided directly by CAP:\n\nNAME | DESCRIPTION | TYPE | DEFAULT\n:---|:---|---|:---\nHostName | Broker host address | string | localhost\nUserName | Broker user name | string | guest\nPassword | Broker password | string | guest\nVirtualHost | Broker virtual host | string | /\nPort | Port | int | -1\nExchangeName | Default exchange name | string | cap.default.topic\nQueueArguments  | Extra queue `x-arguments` | QueueArgumentsOptions  |  N/A\nQueueOptions  | Change Options for created queue | QueueRabbitOptions  |  { Durable=true, Exclusive=false, AutoDelete=false }\nConnectionFactoryOptions  |  RabbitMQClient native connection options | ConnectionFactory | N/A\nCustomHeadersBuilder  | Custom subscribe headers |  See the blow |  N/A\nPublishConfirms | Enable [publish confirms](https://www.rabbitmq.com/confirms.html#publisher-confirms) | bool | false\nBasicQosOptions | Specify [Qos](https://www.rabbitmq.com/consumer-prefetch.html) of message prefetch | BasicQos | N/A\n\n#### ConnectionFactory Option\n\nIf you need **more** native `ConnectionFactory` configuration options, you can set it by 'ConnectionFactoryOptions' option:\n\n```csharp\n\nservices.AddCap(x =>\n{\n    x.UseRabbitMQ(o =>\n    {\n        o.HostName = \"localhost\";\n        o.ConnectionFactoryOptions = opt => { \n            //rabbitmq client ConnectionFactory config\n        };\n    });\n});\n\n```\n\n#### CustomHeadersBuilder Option\n\nWhen the message is sent from the RabbitMQ management console or a heterogeneous system, CAP requires additional headers to be defined. By providing this parameter, you can set custom headers to ensure the subscriber works correctly.\n\nYou can find the description of [Header Information](../cap/messaging.md#heterogeneous-system-integration) here.\n\nExample：\n\n```cs\nx.UseRabbitMQ(aa =>\n{\n    aa.CustomHeadersBuilder = (msg, sp) =>\n    [\n        new(DotNetCore.CAP.Messages.Headers.MessageId, sp.GetRequiredService<ISnowflakeId>().NextId().ToString()),\n        new(DotNetCore.CAP.Messages.Headers.MessageName, msg.RoutingKey)\n    ];\n});\n```\n\n#### How to Connect to a Cluster\n\nUse a comma-separated connection string like this:\n\n```\nx=> x.UseRabbitMQ(\"localhost:5672,localhost:5673,localhost:5674\")\n```"
  },
  {
    "path": "docs/content/user-guide/en/transport/redis-streams.md",
    "content": "# Redis Streams\n\n[Redis](https://redis.io/) is an open-source, BSD-licensed, in-memory data structure store used as a database, cache, and message broker.\n\n[Redis Streams](https://redis.io/topics/streams-intro) is a new data type introduced in Redis 5.0 that models a log data structure in an abstract way using an append-only data structure.\n\nRedis Streams can be used in CAP as a message transporter. \n\n## Configuration\n\nTo use Redis Streams as a transporter, you need to install the following package from NuGet:\n\n```powershell\nPM> Install-Package DotNetCore.CAP.RedisStreams\n\n```\n\nThen you can add configuration items to the `ConfigureServices` method of `Startup.cs`.\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    services.AddCap(capOptions =>\n    {\n        capOptions.UseRedis(redisOptions=>{\n            //redisOptions\n        });\n    });\n}\n\n```\n\n#### Redis Streams Options\n\nRedis Streams configuration parameters provided by CAP:\n\nNAME | DESCRIPTION | TYPE | DEFAULT\n:---|:---|---|:---\nConfiguration | redis connection configuration (StackExchange.Redis) | ConfigurationOptions | ConfigurationOptions\nStreamEntriesCount | number of entries returned from a stream while reading | uint | 10\nConnectionPoolSize  | number of connections pool | uint | 10\nOnConsumeError      | callback function that will be invoked when an error occurred during message consumption. | Func<ConsumeErrorContext, Task> | null\n#### Redis Configuration Options\n\nIf you need additional native Redis configuration options, you can set them in the `Configuration` option:\n\n```csharp\nservices.AddCap(capOptions => \n{\n    capOptions.UseRedis(redisOptions=>\n    {\n        // redis options.\n        redisOptions.Configuration.EndPoints.Add(IPAddress.Loopback, 0);\n    });\n});\n```\n\n`Configuration` is a StackExchange.Redis `ConfigurationOptions`. You can find more details at this [link](https://stackexchange.github.io/StackExchange.Redis/Configuration).\n\n### Streams Cleanup Notes\n\nSince Redis Streams does not support deleting all messages that have been acknowledged by all groups (see [Redis issue](https://github.com/redis/redis/issues/5774)), you should consider using a script to periodically delete old messages.\n"
  },
  {
    "path": "docs/content/user-guide/zh/cap/configuration.md",
    "content": "# 配置\n\n默认情况下，你在向DI容器中注册CAP服务的时候指定此配置。\n\n```c#\nservices.AddCap(config=> {\n    // config.XXX \n});\n```\n\n其中 `services` 代表的是 `IServiceCollection` 接口对象，它位于 `Microsoft.Extensions.DependencyInjection` 下面。 \n\n## 什么是最低配置？\n\n最简单的回答就是，至少你要配置一个传输器和一个存储，如果你想快速开始你可以使用下面的配置：\n\n```C#\nservices.AddCap(config => \n{\n     config.UseInMemoryMessageQueue(); //需要引用 Savorboard.CAP.InMemoryMessageQueue 包\n     config.UseInMemoryStorage();\n});\n```\n\n有关具体的传输器配置和存储配置，你可以查看 Transports 章节和 Persistent 章节中具体组件提供的配置项。\n\n## 订阅者中的配置\n\n订阅者使用 `[CapSubscribe]` 这个Attribute来标记成为一个订阅者，订阅者可以位于 ASP.NET Core 的 Controller 或 Service 中。\n\n当你在声明 `[CapSubscribe]` 时候，可以通过指定以下参数来改变订阅者的行为。\n\n### Name\n\n> string, 必须项\n\n通过指定 `Name` 参数来订阅消息，其对应发布消息时通过 Publish(\"Name\") 指定的名称。\n\n该名称在不同的 Broker 有不同的对应项。\n\n- 在 RabbitMQ 中对应 Routing Key。\n- 在 Kafka 中对应 Topic。\n- 在 AzureServiceBus 中对应 Subject。\n- 在 NATS 中对应 Subject。\n- 在 RedisStrems 中对应 Stream.\n\n###  Group\n\n> string, 可选项\n\n通过指定 `Group` 参数来使订阅者位于单独的消费者组中，消费者组的概念类似于 Kafka 中的消费者组。如果不指定此参数将使用当前程序集名称(`DefaultGroupName`)作为默认值。\n\n相同 `Name` 的订阅者设置为**不同的**组时，他们都会收到消息。相反如果相同 `Name` 的订阅者设置**相同的**组时，只有一个会收到消息。\n\n不同 `Name` 的订阅者设置为**不同的**组时，也是有意义的，他们可以拥有独立的线程来执行。相反如果不同 `Name` 的订阅者设置**相同的**组时，他们将共享消费线程。\n\nGroup 在不同的 Broker 有不同的对应项。\n\n- 在 RabbitMQ 中对应 Queue。\n- 在 Kafka 中对应 Consumer Group。\n- 在 AzureServiceBus 中对应 Subscription Name。\n- 在 NATS 中对应 Queue Group。\n- 在 RedisStrems 中对应 Consuemr Group.\n\n### GroupConcurrent\n\n> byte, 可选项\n\n通过指定 `GroupConcurrent` 参数的值来设置订阅者并行执行的并行度。并行执行意味着其需要位于独立线程中，因此如果你没有指定 `Group` 参数，则 CAP 将会以 `Name` 的值自动创建一个 Group。\n\n!!! Note \"注意\"\n    如果你有多个订阅者都设置为了相同的 Group，并且也给订阅者都设置了 `GroupConcurrent` 的值，则并行度为组内值的和。  \n    本设置只对新消息生效，重试的消息不受并行度限制。\n\n## 自定义配置项\n\n在 `AddCap` 中 `CapOptions` 对象是用来存储配置相关信息，默认情况下它们都具有一些默认值，有些时候你可能需要自定义。\n\n#### DefaultGroupName\n\n默认值：cap.queue.{程序集名称}\n\n默认的消费者组的名字，在不同的 Transports 中对应不同的名字，可以通过自定义此值来自定义不同 Transports 中的名字，以便于查看。\n\n!!! info \"映射\"\n    在 RabbitMQ 中映射到 [Queue Names](https://www.rabbitmq.com/queues.html#names)。  \n    在 Apache Kafka 中映射到 [Consumer Group Id](http://kafka.apache.org/documentation/#group.id)。  \n    在 Azure Service Bus 中映射到 Subscription Name。  \n    在 NATS 中映射到 [Queue Group Name](https://docs.nats.io/nats-concepts/queue).\n    在 Redis Streams 中映射到 [Consumer Group](https://redis.io/topics/streams-intro#creating-a-consumer-group).\n\n#### GroupNamePrefix\n\n默认值：Null\n\n为订阅 Group 统一添加前缀。 https://github.com/dotnetcore/CAP/pull/780\n\n#### TopicNamePrefix\n\n默认值： Null\n\n为 Topic 统一添加前缀。 https://github.com/dotnetcore/CAP/pull/780\n\n#### Version\n\n默认值：v1\n\n用于给消息指定版本来隔离不同版本服务的消息，常用于A/B测试或者多服务版本的场景。以下是其应用场景：\n\n!!! info \"业务快速迭代，需要向前兼容\"\n    由于业务的快速迭代，在各个服务集成的过程中，消息的数据结构并不是固定不变的，有些时候我们为了适应新引入的需求，会添加或者修改一些数据结构。如果你是一套全新的系统这没有什么问题，但是如果你的系统已经部署到生产环境了并且正在服务客户，这就会导致新的功能在上线的时候和旧的数据结构发生不兼容，那么这些改变可能会导致出现严重的问题，要想解决这个问题，只能把消息队列和持久化的消息全部清空，然后才能启动应用程序，这对于生产环境来说显然是致命的。\n\n!!! info \"多个版本的服务端\"\n    有些时候，App的服务端需要提供多套接口，来支持不同版本的App，这些不同版本的App相同的接口和服务端交互的数据结构可能是不一样的，所以通常情况下服务端提供不用的路由地址来适配不同版本的App调用。\n\n!!! info \"不同实例，使用相同的持久化表/集合\"\n    希望多个不同实例的程序可以公用相同的数据库，在 2.4 之前的版本，我们可以通过指定不同的表名来隔离不同实例的数据库表，即在CAP配置的时候通过配置不同的表名前缀来实现。\n\n> 查看博客来了解更多关于 Version 的信息： https://www.cnblogs.com/savorboard/p/cap-2-4.html\n\n\n#### FailedRetryInterval\n\n默认值：60 秒\n\n在消息发送的时候，如果发送失败，CAP将会对消息进行重试，此配置项用来配置每次重试的间隔时间。\n\n在消息消费的过程中，如果消费失败，CAP将会对消息进行重试消费，此配置项用来配置每次重试的间隔时间。\n\n!!! WARNING \"重试 & 间隔\"\n    在默认情况下，重试将在发送和消费消息失败的 **FallbackWindowLookbackSeconds（4分钟后）** 开始，这是为了避免设置消息状态延迟导致可能出现的问题。  \n    发送和消费消息的过程中失败会立即重试 3 次，在 3 次以后将进入重试轮询，此时 FailedRetryInterval 配置才会生效。\n\n!!! WARNING \"多实例并发重试\"\n    我们在7.1.0版本中引入了基于数据库的分布式锁以应对在多个实例下对数据库重试的并发数据获取问题，你需要显式配置 `UseStorageLock` 为 true。\n\n#### UseStorageLock\n\n> 默认值: false\n\n如果设置为true，我们将使用基于数据库的分布式锁以应对重试进程在多个实例下对数据库数据的并发获取问题。这将会在数据库生成 cap.lock 表。\n\n#### ConsumerThreadCount \n\n> 默认值：1\n\n消费者线程并行处理消息的线程数，当这个值大于1时，将不能保证消息执行的顺序。\n\n#### CollectorCleaningInterval\n\n> 默认值：300 秒\n\n收集器删除已经过期消息的时间间隔。\n\n#### SchedulerBatchSize\n\n> 默认值：1000\n\n调度器每次循环获取的延迟或排队消息的最大数量。\n\n#### FailedRetryCount\n\n> 默认值：50\n\n重试的最大次数。当达到此设置值时，将不会再继续重试，通过改变此参数来设置重试的最大次数。\n\n#### FallbackWindowLookbackSeconds\n\n> 默认值：240 秒\n\n配置重试处理器拾取 `Scheduled` 或 `Failed` 状态消息的回退时间窗。\n\n#### FailedThresholdCallback\n\n> 默认值：NULL\n\n类型：`Action<FailedInfo>`\n\n重试阈值的失败回调。当重试达到 FailedRetryCount 设置的值的时候，将调用此 Action 回调，你可以通过指定此回调来接收失败达到最大的通知，以做出人工介入。例如发送邮件或者短信。\n\n#### SucceedMessageExpiredAfter\n\n> 默认值：24*3600 秒（1天后）\n\n成功消息的过期时间（秒）。 当消息发送或者消费成功时候，在时间达到 `SucceedMessageExpiredAfter` 秒时候将会从 Persistent 中删除，你可以通过指定此值来设置过期的时间。\n\n#### FailedMessageExpiredAfter\n\n> 默认值：15*24*3600 秒（15天后）\n\n失败消息的过期时间（秒）。 当消息发送或者消费失败时候，在时间达到 `FailedMessageExpiredAfter` 秒时候将会从 Persistent 中删除，你可以通过指定此值来设置过期的时间。\n\n#### [已移除] UseDispatchingPerGroup \n\n> 默认值: false\n\n> 版本 8.2.0 中移除，已是默认行为。\n\n默认情况下，CAP会将所有消费者组的消息都先放置到内存同一个Channel中，然后线性处理。\n如果设置为 true，则每个消费者组都会根据 `ConsumerThreadCount` 设置的值创建单独的线程进行处理。\n\n在同时配合使用 `EnableConsumerPrefetch` 时，请参考 issue [#1399](https://github.com/dotnetcore/CAP/issues/1399) 以清晰其预期行为。\n\n#### [已过时] EnableConsumerPrefetch\n\n> 默认值: false， 在 7.0 版本之前默认行为 true\n\n 该配置项已被重命名为 `EnableSubscriberParallelExecute`，请使用新选项。\n\n#### EnableSubscriberParallelExecute\n\n> 默认值: false\n\n如果设置为 `true`，CAP将提前从Broker拉取一批消息置于内存缓冲区，然后执行订阅方法；当订阅方法执行完成后，拉取下一批消息至于缓冲区然后执行。\n\n!!! note \"注意事项\"\n    设置为 true 可能会产生一些问题，当订阅方法执行过慢耗时太久时，会导致重试线程拾取到还未执行的的消息。重试线程默认拾取4分钟前（FallbackWindowLookbackSeconds 配置项）的消息，也就是说如果消费端积压了超过4分钟（FallbackWindowLookbackSeconds 配置项）的消息就会被重新拾取到再次执行\n\n#### SubscriberParallelExecuteThreadCount\n\n> Default: `Environment.ProcessorCount`\n\n当启用 `EnableSubscriberParallelExecute` 时, 可通过此参数执行并行处理的线程数，默认值为处理器个数。\n\n#### SubscriberParallelExecuteBufferFactor\n\n> Default: 1\n\n当启用 `EnableSubscriberParallelExecute` 时, 通过此参数设置缓冲区和线程数的因子系数，也就是缓冲区大小等于 `SubscriberParallelExecuteThreadCount` 乘 `SubscriberParallelExecuteBufferFactor`.\n\n#### EnablePublishParallelSend\n\n> 默认值: false\n\n默认情况下，发送的消息都先放置到内存同一个Channel中，然后线性处理。\n如果设置为 true，则发送消息的任务将由.NET线程池并行处理，这会大大提高发送的速度。"
  },
  {
    "path": "docs/content/user-guide/zh/cap/filter.md",
    "content": "# 过滤器\n\n从 5.1.0 版本后，我们引入了对订阅者过滤器的支持，以使在某些场景（如事务处理，日志记录等）中变得容易。\n\n## 自定义过滤器\n\n### 添加过滤器\n\n创建一个过滤器类，并继承 `SubscribeFilter` 抽象类。\n\n```C#\npublic class MyCapFilter: SubscribeFilter\n{\n    public override Task OnSubscribeExecutingAsync(ExecutingContext context)\n    {\n        // 订阅方法执行前\n    }\n\n    public override Task OnSubscribeExecutedAsync(ExecutedContext context)\n    {\n        // 订阅方法执行后\n    }\n\n    public override Task OnSubscribeExceptionAsync(ExceptionContext context)\n    {\n        // 订阅方法执行异常\n    }\n}\n```\n\n在一些场景中，如果想终止订阅者方法执行，可以在 `OnSubscribeExecutingAsync` 中抛出异常，并且在 `OnSubscribeExceptionAsync` 中选择忽略该异常。\n\n通过在 `ExceptionContext` 中设置 `context.ExceptionHandled = true` 来忽略异常。\n\n```C#\npublic override Task OnSubscribeExceptionAsync(ExceptionContext context)\n{\n    context.ExceptionHandled = true;\n}\n```\n\n### 配置过滤器\n\n```C#\nservices.AddCap(opt =>\n{\n    // ***\n}.AddSubscribeFilter<MyCapFilter>();\n```\n\n目前， 我们还不支持同时添加多个过滤器。\n\n!!! WARNING \"过滤器中使用 AsyncLocal 的问题\"\n    我们不建议在过滤器中使用AsyncLocal，因为过滤器的生命周期为Scoped，所以直接定义临时变量即可在整个执行周期内共享变量值。\n    然后，如果由于一些你无法控制的原因要使用，由于AsyncLocal的设计问题，则可将异步过滤器作为同步使用，也就是继承的方法构造中不添加 async 关键字。\n"
  },
  {
    "path": "docs/content/user-guide/zh/cap/idempotence.md",
    "content": "# 幂等性\n\n幂等性（你可以在[Wikipedia](https://en.wikipedia.org/wiki/Idempotence)读到关于幂等性的定义），当我们谈论幂等时，一般是指可以重复处理传递的消息，而不会产生意外的结果。\n\n## 交付保证\n\n在说幂等性之前，我们先来说下关于消费端的消息交付。\n\n由于CAP不是使用的 MS DTC 或其他类型的2PC分布式事务机制，所以存在至少消息严格交付一次的问题，具体的说在基于消息的系统中，存在以下三种可能：\n\n* Exactly Once(*) （仅有一次）\n* At Most Once （最多一次）\n* At Least Once （最少一次）\n\n带 * 号表示在实际场景中，很难达到。\n\n### At Most Once\n\n最多一次交付保证，涵盖了保证一次或根本不接收所有消息的情况。\n\n这种类型的传递保证可能来自你的消息系统，你的代码按以下顺序执行其操作：\n\n```\n1. 从队列移除消息\n2. 开始一个工作事务\n3. 处理消息 ( 你的代码 )\n4. 是否成功 ?\n    Yes:\n        1. 提交工作事务\n    No: \n        1. 回滚工作事务\n        2. 将消息发回到队列。\n```\n\n正常情况下，他们工作的很好，工作事务将被提交。\n\n然而，有些时候并不能总是成功，比如在 1 之后出现异常，或者是你在将消息放回到队列中出现网络问题由或者宕机重启等情况。\n\n使用这个协议，你将冒着丢失消息的风险，如果可以接受，那就没有关系。\n\n### At Least Once\n\n这个交付保证包含你收到至少一次的消息，当出现故障时，可能会收到多次消息。\n\n它需要稍微改变我们执行步骤的顺序，它要求消息队列系统支持事务或ACK机制，比如传统的 begin-commit-rollback 协议（MSMQ是这样），或者是 receive-ack-nack 协议（RabbitMQ，Azure Service Bus等是这样的）。\n\n大致步骤如下:\n\n```\n1. 抢占队列中的消息。\n2. 开始一个工作事务\n3. 处理消息 ( 你的代码 )\n4. 是否成功 ?\n    Yes: \n        1. 提交工作事务\n        2. 从队列删除消息\n    No: \n        1. 回滚工作事务\n        2. 从队列释放抢占的消息\n```\n\n当出现失败或者抢占消息超时的时候，我们总是能够再次接收到消息以保证我们工作事务提交成功。\n\n### 什么是 “工作事务” ?\n\n上面所说的“工作事务”并不是特指关系型数据库中的事务，这里的工作事务是一个概念，也就是说执行代码的原子性。\n\n比如它可以是传统的RDMS事务，也或者是 MongoDB 事务或者是一个交易等。\n\n在这里它代表一个执行单元，这个执行单元是一个概念性的事实以支持前面提到的仅交付一次的这种问题。\n\n通常，不可能做到消息的事务和工作事务来形成原子性进行提交或者回滚。\n\n## CAP 中的幂等性\n\n在CAP中，我们采用的交付保证为 At Least Once。\n\n由于我们具有临时存储介质（数据库表），也许可以做到 At Most Once, 但是为了严格保证消息不会丢失，我们没有提供相关功能或配置。\n\n### 为什么没有实现幂等？\n\n1、消息写入成功了，但是此时执行Consumer方法失败了\n\n执行Consumer方法失败的原因有非常多，我如果不知道具体的场景盲目进行重试或者不进行重试都是不正确的选择。\n举个例子：假如消费者为扣款服务，如果是执行扣款成功了，但是在写扣款日志的时候失败了，此时CAP会判断为消费者执行失败，进行重试。如果客户端自己没有保证幂等性，框架对其进行重试，这里势必会造成多次扣款出现严重后果。\n\n2、执行Consumer方法成功了，但是又收到了同样的消息\n\n此处场景也是可能存在的，假如开始的时候Consumer已经执行成功了，但是由于某种原因如 Broker 宕机恢复等，又收到了相同的消息，CAP 在收到Broker消息后会认为这个是一个新的消息，会对 Consumer再次执行，由于是新消息，此时 CAP 也是无法做到幂等的。\n\n3、目前的数据存储模式无法做到幂等\n\n由于CAP存消息的表对于成功消费的消息会于1个小时后删除，所以如果对于一些历史性消息无法做到幂等操作。 历史性指的是，假如 Broker由于某种原因维护了或者是人工处理的一些消息。\n\n4、业界做法\n\n许多基于事件驱动的框架都是要求 用户 来保证幂等性操作的，比如 ENode, RocketMQ 等等...\n\n从实现的角度来说，CAP可以做一些比较不严格的幂等，但是严格的幂等无法做到的。\n\n### 以自然的方式处理幂等消息\n\n通常情况下，保证消息被执行多次而不会产生意外结果是很自然的一种方式是采用操作对象自带的一些幂等功能。比如：\n\n数据库提供的 `INSERT ON DUPLICATE KEY UPDATE` 或者是采取类型的程序判断行为。\n\n### 显式处理幂等消息\n\n另外一种处理幂等性的方式就是在消息传递的过程中传递ID，然后由单独的消息跟踪器来处理。 \n\n比如你使用具有事务数据存储的 IMessageTracker 来跟踪消息ID，你的代码可能看起来像这样：\n\n```c#\nreadonly IMessageTracker _messageTracker;\n\npublic SomeMessageHandler(IMessageTracker messageTracker)\n{\n    _messageTracker = messageTracker;\n}\n\n[CapSubscribe]\npublic async Task Handle(SomeMessage message) \n{\n    if (await _messageTracker.HasProcessed(message.Id))\n    {\n        return;\n    }\n\n    // do the work here\n    // ...\n\n    // remember that this message has been processed\n    await _messageTracker.MarkAsProcessed(messageId);\n}\n```\n\n至于 `IMessageTracker` 的实现，可以使用诸如Redis或者数据库等存储消息Id和对应的处理状态。"
  },
  {
    "path": "docs/content/user-guide/zh/cap/messaging.md",
    "content": "# 消息\n\n使用 `ICapPublisher` 接口发送出去的数据称之为 Message (`消息`)。\n\n## 发送 & 处理消息\n\n你可以阅读 [quick-start](../getting-started/quick-start.md#_3) 来学习如何发送和处理消息。\n\n!!! WARNING \"消费者中使用 HTTPClient 引发的 TimeoutException\"\n    默认情况下，如果消费者抛出 `OperationCanceledException`（包括 `TaskCanceledException`），我们会认为这是用户的正常行为而对异常进行忽略。如果你在消费者方法中使用 HTTPClient 并且进行了配置了Timeout配置，由于HTTP Client的[设计问题](https://github.com/dotnet/runtime/issues/21965)，你可能需要单独对异常进行处理并重新引发非OperationCanceledException，参考 #1368\n\n## 补偿事务\n\n[Compensating transaction](https://en.wikipedia.org/wiki/Compensating_transaction)\n\n某些情况下，消费者需要返回值以告诉发布者执行结果，以便于发布者实施一些动作，通常情况下这属于补偿范围。\n\n你可以在消费者执行的代码中通过重新发布一个新消息来通知上游，CAP 提供了一种简单的方式来做到这一点。 你可以在发送的时候指定 `callbackName` 来得到消费者的执行结果，通常这仅适用于点对点的消费。以下是一个示例。\n\n例如，在一个电商程序中，订单初始状态为 pending，当商品数量成功扣除时将状态标记为 succeeded ，否则为 failed。\n\n```C#\n// =============  Publisher =================\n\n_capBus.Publish(\"place.order.qty.deducted\", \n    contentObj: new { OrderId = 1234, ProductId = 23255, Qty = 1 }, \n    callbackName: \"place.order.mark.status\");    \n\n// publisher using `callbackName` to subscribe consumer result\n\n[CapSubscribe(\"place.order.mark.status\")]\npublic void MarkOrderStatus(JsonElement param)\n{\n    var orderId = param.GetProperty(\"OrderId\").GetInt32();\n    var isSuccess = param.GetProperty(\"IsSuccess\").GetBoolean();\n    \n    if(isSuccess){\n        // mark order status to succeeded\n    }\n    else{\n       // mark order status to failed\n    }\n}\n\n// =============  Consumer ===================\n\n[CapSubscribe(\"place.order.qty.deducted\")]\npublic object DeductProductQty(JsonElement param)\n{\n    var orderId = param.GetProperty(\"OrderId\").GetInt32();\n    var productId = param.GetProperty(\"ProductId\").GetInt32();\n    var qty = param.GetProperty(\"Qty\").GetInt32();\n\n    //business logic \n\n    return new { OrderId = orderId, IsSuccess = true };\n}\n```\n\n### 控制回调响应\n\n你可以通过 `[FromCap]` 标记在订阅方法中注入 `CapHeader` 参数，并利用其提供的方法来向回调上下文中添加额外的头信息或者终止回调。\n\n示例如下：\n\n```cs\n[CapSubscribe(\"place.order.qty.deducted\")]\npublic object DeductProductQty(JsonElement param, [FromCap] CapHeader header)\n{\n    var orderId = param.GetProperty(\"OrderId\").GetInt32();\n    var productId = param.GetProperty(\"ProductId\").GetInt32();\n    var qty = param.GetProperty(\"Qty\").GetInt32();\n\n    // 添加额外的头信息到响应消息中\n    header.AddResponseHeader(\"some-message-info\", \"this is the test\");\n    // 或再次添加回调的回调\n    header.AddResponseHeader(DotNetCore.CAP.Messages.Headers.CallbackName, \"place.order.qty.deducted-callback\");\n\n    // 如果你不再遵从发送着指定的回调，想修改回调，可通过 RewriteCallback 方法修改。\n    header.RewriteCallback(\"new-callback-name\");\n\n    // 如果你想终止/停止，或不再给发送方响应，调用 RemoveCallback 来移除回调。\n    header.RemoveCallback();\n\n    return new { OrderId = orderId, IsSuccess = true };\n}\n```\n\n## 异构系统集成\n\n在 3.0+ 版本中，我们对消息结构进行了重构，我们利用了消息队列中消息协议中的 Header 来传输一些额外信息，以便于在 Body 中我们可以做到不需要修改或包装使用者的原始消息数据格式和内容进行发送。\n\n这样的做法是合理的，它有助于在异构系统中进行更好的集成，相对于以前的版本使用者不需要知道CAP内部使用的消息结构就可以完成集成工作。\n\n现在我们将消息划分为 Header 和 Body 来进行传输。\n\nBody 中的数据为用户发送的原始消息内容，也就是调用 Publish 方法发送的内容，我们不进行任何包装仅仅是序列化后传递到消息队列。\n\n在 Header 中，我们需要传递一些额外信息以便于CAP在收到消息时能够提取到关键特征进行操作。\n\n以下是在异构系统中，需要在发消息的时候向消息的Header 中写入的内容：\n\n 键 | 类型 | 说明\n-- | --| --\ncap-msg-id |  long | 消息Id， 由雪花算法生成\ncap-msg-name | string | 消息名称，即 Topic 名字\ncap-msg-type | string | 消息的类型, 即 typeof(T).FullName (非必须)\ncap-senttime | string | 发送的时间 (非必须)\n\n以 Java 系统发送 RabbitMQ 为例：\n\n```java\n\nMap<String, Object> headers = new HashMap<String, Object>();\nheaders.put(\"cap-msg-id\",  UUID.randomUUID().toString());\nheaders.put(\"cap-msg-name\", routingKey);\n\nchannel.basicPublish(exchangeName, routingKey,\n             new AMQP.BasicProperties.Builder()\n               .headers(headers)\n               .build(),\n               messageBodyBytes);\n// messageBodyBytes = \"发送的json\".getBytes(Charset.forName(\"UTF-8\"))\n// 注意 messageBody 默认为 json 的 byte[]，如果采用其他系列化，需要在CAP侧自定义反序列化器\n\n```\n\n## 消息调度\n\nCAP 接收到消息之后会将消息发送到 Transport, 由 Transport 进行运输。\n\n当你使用 `ICapPublisher` 接口发送时，CAP将会将消息调度到相应的 Transport中去，目前还不支持批量发送消息。\n\n有关 Transports 的更多信息，可以查看 [Transports](../transport/general.md) 章节。\n\n## 消息存储\n\nCAP 接收到消息之后会将消息进行 Persistent（持久化）， 有关 Persistent 的更多信息，可以查看 [Persistent](../storage/general.md) 章节。\n\n## 消息重试\n\n重试在整个CAP架构设计中具有重要作用，CAP 中会针对发送失败或者执行失败的消息进行重试。在整个 CAP 的设计过程中有以下几处采用的重试策略。\n\n1、 发送重试\n\n在消息发送过程中，当出现 Broker 宕机或者连接失败的情况亦或者出现异常的情况下，这个时候 CAP 会对发送的重试，第一次重试次数为 3，4分钟后以后每分钟重试一次，进行次数 +1，当总次数达到50次后，CAP将不对其进行重试。\n\n你可以在 CapOptions 中设置 [FailedRetryCount](configuration.md#failedretrycount) 来调整默认重试的总次数，或使用 [FailedThresholdCallback](configuration.md#FailedThresholdCallback) 在达到最大重试次数时收到通知。\n\n当失败总次数达到默认失败总次数后，就不会进行重试了，你可以在 Dashboard 中查看消息失败的原因，然后进行人工重试处理。\n\n2、 消费重试\n\n当 Consumer 接收到消息时，会执行消费者方法，在执行消费者方法出现异常时，会进行重试。这个重试策略和上面的 发送重试 是相同的。\n\n无论发送失败或者消费失败，我们会将异常消息同时存储到消息 header 中的 cap-exception 字段中，你可以在数据库表的 Content 字段的json中找到。\n\n## 消息数据清理\n\n数据库消息表中具有一个 ExpiresAt 字段表示消息的过期时间，当消息发送成功或者消费成功后，CAP 会将消息状态为 Successed 的 ExpiresAt 设置为 1天 后过期，会将消息状态为 Failed 的 ExpiresAt 设置为 15天 后过期（可通过 [FailedMessageExpiredAfter](configuration.md#failedmessageexpiredafter) 配置)。\n\nCAP 默认情况下会每隔**5分钟**将消息表的数据进行清理删除，避免数据量过多导致性能的降低。清理规则为 ExpiresAt 不为空并且小于当前时间的数据。 也就是说状态为Failed的消息（正常情况他们已经被重试了 50 次），如果你15天没有人工介入处理，同样会被清理掉。你可以通过 [CollectorCleaningInterval](configuration.md#collectorcleaninginterval) 配置项来自定义间隔时间。\n\n"
  },
  {
    "path": "docs/content/user-guide/zh/cap/serialization.md",
    "content": "# 序列化\n\nCAP 提供了 `ISerializer` 接口来支持对消息进行序列化，默认情况下我们使用 json 来对消息进行序列化处理并存储到数据库中。\n\n## 自定义序列化\n\n```C#\npublic class YourSerializer: ISerializer\n{\n    Task<TransportMessage> SerializeAsync(Message message)\n    {\n\n    }\n \n    Task<Message> DeserializeAsync(TransportMessage transportMessage, Type valueType)\n    {\n\n    }\n}\n```\n\n然后将你的实现注册到容器中:\n\n```\n\n//注册你的自定义实现\nservices.AddSingleton<ISerializer, YourSerializer>();\n\n// ---\nservices.AddCap \n\n```"
  },
  {
    "path": "docs/content/user-guide/zh/cap/transactions.md",
    "content": "# 事务\n\n## 分布式事务?\n\nCAP 不直接提供开箱即用的基于 DTC 或者 2PC 的分布式事务，相反我们提供一种可以用于解决在分布式事务遇到的问题的一种解决方案。\n\n在分布式环境中，由于涉及通讯的开销，使用基于2PC或DTC的分布式事务将非常昂贵，在性能方面也同样如此。另外由于基于2PC或DTC的分布式事务同样受**CAP定理**的约束，当发生网络分区时它将不得不放弃可用性(CAP中的A)。\n\n针对于分布式事务的处理，CAP 采用的是“异步确保”这种方案。\n\n### 异步确保\n\n异步确保这种方案又叫做本地消息表，这是一种经典的方案，方案最初来源于 eBay，参考资料见段末链接。这种方案目前也是企业中使用最多的方案之一。\n\n相对于 TCC 或者 2PC/3PC 来说，这个方案对于分布式事务来说是最简单的，而且它是去中心化的。在TCC 或者 2PC 的方案中，必须具有事务协调器来处理每个不同服务之间的状态，而此种方案不需要事务协调器。\n另外 2PC/TCC 这种方案如果服务依赖过多，会带来管理复杂性增加和稳定性风险增大的问题。试想如果我们强依赖 10 个服务，9 个都执行成功了，最后一个执行失败了，那么是不是前面 9 个都要回滚掉？这个成本还是非常高的。\n\n但是，并不是说 2PC 或者 TCC 这种方案不好，因为每一种方案都有其相对优势的使用场景和优缺点，这里就不做过多介绍了。\n\n> 中文：[http://www.cnblogs.com/savorboard/p/base-an-acid-alternative.html](http://www.cnblogs.com/savorboard/p/base-an-acid-alternative.html)  \n> 英文：[http://queue.acm.org/detail.cfm?id=1394128](http://queue.acm.org/detail.cfm?id=1394128)\n"
  },
  {
    "path": "docs/content/user-guide/zh/getting-started/contributing.md",
    "content": "# 贡献\n\n贡献最简单的方式之一就是参与讨论和issue讨论。\n\n如果您有任何疑问或问题，请在CAP仓库中报告：\n\n<a href=\"https://github.com/dotnetcore/cap/issues/new\"><button data-md-color-primary=\"purple\"><i class=\"fa fa-github fa-2x\"></i> Report Issue</button></a>\n<a href=\"https://github.com/dotnetcore/cap/issues\"><button data-md-color-primary=\"purple\" type=\"submit\"> Active Issues <i class=\"fa fa-github fa-2x\"></i></button></a>\n\n## 提交更改\n\n您还可以通过提交代码更改PR来做出贡献。\n\n>\nPull requests 可让您告诉其他人已推送到GitHub上存储库的更改。 打开 Pull requests 后，您可以与协作者讨论和审查做出的更改，并在更改合并到存储库之前添加后续提交。\n\n## 其他资源\n\n* [issue 和 pull requests](https://help.github.com/articles/filtering-issues-and-pull-requests/)\n\n* [使用搜索过滤 issue 和 pull requests](https://help.github.com/articles/using-search-to-filter-issues-and-pull-requests/)"
  },
  {
    "path": "docs/content/user-guide/zh/getting-started/introduction.md",
    "content": "# 介绍\n\nCAP 是一个EventBus，同时也是一个在微服务或者SOA系统中解决分布式事务问题的一个框架。它有助于创建可扩展，可靠并且易于更改的微服务系统。\n\n在微软的 [eShop](https://github.com/dotnet/eShop) 微服务示例项目中，推荐使用 CAP 作为生产环境可用的 EventBus。\n\n!!! question \"什么是 EventBus？\"\n\n    事件总线是一种机制，它允许不同的组件彼此通信而不彼此了解。 组件可以将事件发送到Eventbus，而无需知道是谁来接听或有多少其他人来接听。 组件也可以侦听Eventbus上的事件，而无需知道谁发送了事件。 这样，组件可以相互通信而无需相互依赖。 同样，很容易替换一个组件。 只要新组件了解正在发送和接收的事件，其他组件就永远不会知道.\n\n相对于其他的 Service Bus 或者 Event Bus， CAP 拥有自己的特色，它不要求使用者发送消息或者处理消息的时候实现或者继承任何接口，拥有非常高的灵活性。我们一直坚信约定大于配置，所以CAP使用起来非常简单，对于新手非常友好，并且拥有轻量级。\n\nCAP 采用模块化设计，具有高度的可扩展性。你有许多选项可以选择，包括消息队列，存储，序列化方式等，系统的许多元素内容可以替换为自定义实现。\n\n\n## 相关视频\n\n[Video: bilibili 教程](https://www.bilibili.com/video/av31582401/)\n\n[Video: Youtube 教程](https://youtu.be/K1e4e0eddNE)\n\n[Video: 腾讯视频教程](https://www.cnblogs.com/savorboard/p/7243609.html)\n\n## 相关文章\n\n[Article: CAP 介绍及使用](http://www.cnblogs.com/savorboard/p/cap.html)\n\n[Article: CAP 7.0 版本中的新特性](https://www.cnblogs.com/savorboard/p/cap-7-0.html)\n\n[Article: CAP 6.0 版本中的新特性](https://www.cnblogs.com/savorboard/p/cap-6-0.html)\n\n[Article: CAP 5.0 版本中的新特性](https://www.cnblogs.com/savorboard/p/cap-5-0.html)\n\n[Article: CAP 3.0 版本中的新特性](https://www.cnblogs.com/savorboard/p/cap-3-0.html)\n\n[Article: CAP 2.6 版本中的新特性](https://www.cnblogs.com/savorboard/p/cap-2-6.html)\n\n[Article: CAP 2.5 版本中的新特性](https://www.cnblogs.com/savorboard/p/cap-2-5.html)\n\n[Article: CAP 2.4 版本中的新特性](http://www.cnblogs.com/savorboard/p/cap-2-4.html)\n\n[Article: CAP 2.3 版本中的新特性用](http://www.cnblogs.com/savorboard/p/cap-2-3.html)\n\n[Article: .NET Core Community 首个千星项目诞生：CAP](https://www.cnblogs.com/forerunner/p/ncc-cap-with-over-thousand-stars.html)\n"
  },
  {
    "path": "docs/content/user-guide/zh/getting-started/quick-start.md",
    "content": "# 快速开始\n\n了解如何使用 CAP 构建微服务事件总线架构，它比直接集成消息队列提供了哪些优势，它提供了哪些开箱即用的功能。\n\n## 安装\n\n```powershell\nPM> Install-Package DotNetCore.CAP\n```\n\n## 在 Asp.Net Core 中集成\n\n以便于快速启动，我们使用基于内存的事件存储和消息队列。\n\n```powershell\nPM> Install-Package DotNetCore.CAP.InMemoryStorage\nPM> Install-Package Savorboard.CAP.InMemoryMessageQueue\n```\n\n在 `Startup.cs` 中，添加以下配置：\n\n```c#\npublic void ConfigureServices(IServiceCollection services)\n{\n    services.AddCap(x =>\n    {\n        x.UseInMemoryStorage();\n        x.UseInMemoryMessageQueue();\n    });\n}\n```\n\n## 发送消息\n\n```c#\npublic class PublishController : Controller\n{\n    [Route(\"~/send\")]\n    public IActionResult SendMessage([FromServices]ICapPublisher capBus)\n    {\n        capBus.Publish(\"test.show.time\", DateTime.Now);\n\n        return Ok();\n    }\n}\n```\n\n### 发送延迟消息\n\n```c#\npublic class PublishController : Controller\n{\n    [Route(\"~/send/delay\")]\n    public IActionResult SendDelayMessage([FromServices]ICapPublisher capBus)\n    {\n        capBus.PublishDelay(TimeSpan.FromSeconds(100),\"test.show.time\", DateTime.Now);\n\n        return Ok();\n    }\n}\n```\n\n### 发送包含头信息的消息\n\n```c#\nvar header = new Dictionary<string, string>()\n{\n    [\"my.header.first\"] = \"first\",\n    [\"my.header.second\"] = \"second\"\n};\n\ncapBus.Publish(\"test.show.time\", DateTime.Now, header);\n\n```\n\n## 处理消息\n\n```C#\npublic class ConsumerController : Controller\n{\n    [NonAction]\n    [CapSubscribe(\"test.show.time\")]\n    public void ReceiveMessage(DateTime time)\n    {\n        Console.WriteLine(\"message time is:\" + time);\n    }\n}\n```\n\n\n### 处理包含头信息的消息\n\n```c#\n[CapSubscribe(\"test.show.time\")]\npublic void ReceiveMessage(DateTime time, [FromCap]CapHeader header)\n{\n    Console.WriteLine(\"message time is:\" + time);\n    Console.WriteLine(\"message firset header :\" + header[\"my.header.first\"]);\n    Console.WriteLine(\"message second header :\" + header[\"my.header.second\"]);\n}\n\n```\n\n## 摘要\n\n相对于直接集成消息队列，异步消息传递最强大的优势之一是可靠性，系统的一个部分中的故障不会传播，也不会导致整个系统崩溃。 在 CAP 内部会将消息进行存储，以保证消息的可靠性，并配合重试等策略以达到各个服务之间的数据最终一致性。"
  },
  {
    "path": "docs/content/user-guide/zh/monitoring/consul.md",
    "content": "# Consul\n\n[Consul](https://www.consul.io/) 是一个分布式服务网格，用于跨任何运行时平台和公共或私有云连接，保护和配置服务。\n\n## Dashboard 中的 Consul 配置\n\nCAP的 Dashboard 使用 Consul 作为服务发现来显示其他节点的数据，然后你就在任意节点的 Dashboard 中切换到 Servers 页面看到其他的节点。\n\n![](https://camo.githubusercontent.com/54c00c6ae65ce1d7b9109ed8cbcdca703a050c47/687474703a2f2f696d61676573323031372e636e626c6f67732e636f6d2f626c6f672f3235303431372f3230313731302f3235303431372d32303137313030343232313030313838302d313136323931383336322e706e67)\n\n通过点击 Switch 按钮来切换到其他的节点看到其他节点的数据，而不必访问很多地址来分别查看。\n \n以下是一个配置示例, 你需要在每个节点分别配置：\n\n```C#\nservices.AddCap(x =>\n{\n    x.UseMySql(Configuration.GetValue<string>(\"ConnectionString\"));\n    x.UseRabbitMQ(\"localhost\");\n    x.UseDashboard();\n    x.UseConsulDiscovery(_ =>\n    {\n        _.DiscoveryServerHostName = \"localhost\";\n        _.DiscoveryServerPort = 8500;\n        _.CurrentNodeHostName = Configuration.GetValue<string>(\"ASPNETCORE_HOSTNAME\");\n        _.CurrentNodePort = Configuration.GetValue<int>(\"ASPNETCORE_PORT\");\n        _.NodeId = Configuration.GetValue<string>(\"NodeId\");\n        _.NodeName = Configuration.GetValue<string>(\"NodeName\");\n    });\n});\n```\n\nConsul 1.6.2:\n\n```\nconsul agent -dev\n```\n\nWindows 10, ASP.NET Core 3.1:\n\n```sh\nset ASPNETCORE_HOSTNAME=localhost&& set ASPNETCORE_PORT=5001&& dotnet run --urls=http://localhost:5001 NodeId=1 NodeName=CAP-1 ConnectionString=\"Server=localhost;Database=aaa;UserId=xxx;Password=xxx;\"\nset ASPNETCORE_HOSTNAME=localhost&& set ASPNETCORE_PORT=5002&& dotnet run --urls=http://localhost:5002 NodeId=2 NodeName=CAP-2 ConnectionString=\"Server=localhost;Database=bbb;UserId=xxx;Password=xxx;\"\n```"
  },
  {
    "path": "docs/content/user-guide/zh/monitoring/dashboard.md",
    "content": "# Dashboard\n\nCAP 原生提供了 Dashboard 供查看消息，利用 Dashboard 提供的功能可以很方便的查看和管理消息。\n\n!!! WARNING \"使用限制\"\n    Dashboard 只支持在 ASP.NET Core 中使用，不支持控制台应用(Console App)\n\n## 启用 Dashboard\n\n首先，你需要安装Dashboard的 NuGet 包。\n\n```powershell\nPM> Install-Package DotNetCore.CAP.Dashboard\n```\n\n然后，在配置中添加如下代码：\n\n```C#\nservices.AddCap(x =>\n{\n    //...\n\n    // Register Dashboard\n    x.UseDashboard();\n});\n```\n\n默认情况下，你可以访问 `http://localhost:xxx/cap` 这个地址打开Dashboard。 \n\n### Dashboard 配置项\n\n* PathBase\n\n默认值：N/A\n\n当位于代理后时，通过配置此参数可以指定代理请求前缀。\n\n* PathMatch\n\n默认值：'/cap'\n\n你可以通过修改此配置项来更改Dashboard的访问路径。\n\n* StatsPollingInterval\n\n默认值：2000 毫秒\n\n此配置项用来配置Dashboard 前端 获取状态接口(/stats)的轮询时间\n\n* AllowAnonymousExplicit\n\n> Default: true\n\n显式允许对 CAP 仪表板 API 进行匿名访问，当启用ASP.NET Core 全局授权筛选器请启用 AllowAnonymous。\n\n* AuthorizationPolicy\n\n> Default: null.\n\nDashboard 的授权策略。 需设置 `AllowAnonymousExplicit`为 false。\n\n###  自定义认证\n\n从版本 8.0.0 开始，CAP 仪表板利用 ASP.NET Core 身份验证机制，允许通过自定义授权策略和 ASP.NET Core 身份验证和授权中间件进行扩展，以授权仪表板访问。 有关 ASP.NET Core 身份验证内部结构的更多详细信息，请查看[官方文档](https://learn.microsoft.com/en-us/aspnet/core/security/authentication/?view=aspnetcore-8.0).\n\n您可以在示例项目 `Sample.Dashboard.Auth`中查看示例代码。\n\n#### Example: 匿名访问\n\n```csharp\nservices.AddCap(cap =>\n    {\n        cap.UseDashboard(d =>\n        {\n            d.AllowAnonymousExplicit = true;\n        });\n        cap.UseInMemoryStorage();\n        cap.UseInMemoryMessageQueue();\n    });\n```\n\n#### Example: Open Id\n\n```csharp\nservices\n    .AddAuthorization(options =>\n        { \n            options.AddPolicy(DashboardAuthorizationPolicy, policy => policy\n                .AddAuthenticationSchemes(OpenIdConnectDefaults.AuthenticationScheme)\n                .RequireAuthenticatedUser());\n        })\n        .AddAuthentication(opt => opt.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme)\n        .AddCookie()\n        .AddOpenIdConnect(options =>\n        {\n            ...\n        });\n    \n    services.AddCap(cap =>\n    {\n        cap.UseDashboard(d =>\n        {\n            d.AuthorizationPolicy = DashboardAuthorizationPolicy;\n        });\n        cap.UseInMemoryStorage();\n        cap.UseInMemoryMessageQueue();\n    });\n```\n\n### 自定义认证\n\n从 8.0.0 版开始，CAP 控制面板利用 ASP.NET Core 身份验证机制，允许通过自定义授权策略和 ASP.NET Core 身份验证与授权中间件进行扩展。有关 ASP.NET Core 身份验证内部机制的更多详情，请查阅 [官方文档](https://learn.microsoft.com/en-us/aspnet/core/security/authentication/?view=aspnetcore-8.0)。\n\n您可以在示例项目 `Sample.Dashboard.Auth` 中查看以下示例。\n\n#### 例子：Anonymous Access 匿名访问\n\n```csharp\nservices.AddCap(cap =>\n    {\n        cap.UseDashboard(d =>\n        {\n            d.AllowAnonymousExplicit = true;\n        });\n        cap.UseInMemoryStorage();\n        cap.UseInMemoryMessageQueue();\n    });\n```\n\n#### 例子：使用 Open Id\n\n```csharp\nservices\n    .AddAuthorization(options =>\n        { \n            options.AddPolicy(DashboardAuthorizationPolicy, policy => policy\n                .AddAuthenticationSchemes(OpenIdConnectDefaults.AuthenticationScheme)\n                .RequireAuthenticatedUser());\n        })\n        .AddAuthentication(opt => opt.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme)\n        .AddCookie()\n        .AddOpenIdConnect(options =>\n        {\n            ...\n        });\n    \n    services.AddCap(cap =>\n    {\n        cap.UseDashboard(d =>\n        {\n            d.AuthorizationPolicy = DashboardAuthorizationPolicy;\n        });\n        cap.UseInMemoryStorage();\n        cap.UseInMemoryMessageQueue();\n    });\n```\n\n#### 例子：自定义 Authentication Scheme\n\n```csharp\nconst string MyDashboardAuthenticationPolicy = \"MyDashboardAuthenticationPolicy\";\n    \nservices.AddAuthorization(options =>\n    { \n        options.AddPolicy(MyDashboardAuthenticationPolicy, policy => policy\n        .AddAuthenticationSchemes(MyDashboardAuthenticationSchemeDefaults.Scheme)\n        .RequireAuthenticatedUser());\n    })\n    .AddAuthentication()\n    .AddScheme<MyDashboardAuthenticationSchemeOptions, MyDashboardAuthenticationHandler>(MyDashboardAuthenticationSchemeDefaults.Scheme,null);\n    \nservices.AddCap(cap =>\n    {\n        cap.UseDashboard(d =>\n        {\n            d.AuthorizationPolicy = MyDashboardAuthenticationPolicy;\n        });\n        cap.UseInMemoryStorage();\n        cap.UseInMemoryMessageQueue();\n    });\n```\n"
  },
  {
    "path": "docs/content/user-guide/zh/monitoring/diagnostics.md",
    "content": "# 诊断(Diagnostics)\n\nDiagnostics 提供一组功能使我们能够很方便的可以记录在应用程序运行期间发生的关键性操作以及他们的执行时间等，使管理员可以查找特别是生产环境中出现问题所在的根本原因。\n\n## 跟踪(Tracing)\n\nCAP 对 .NET `DiagnosticSource` 提供了支持，监听器名称为 `CapDiagnosticListener`。\n\n你可以在 `DotNetCore.CAP.Diagnostics.CapDiagnosticListenerNames` 类下面找到CAP已经定义的事件名称。\n\nDiagnostics 提供对外提供的事件信息有：\n\n* 消息持久化之前\n* 消息持久化之后\n* 消息持久化异常\n* 消息向MQ发送之前\n* 消息向MQ发送之后\n* 消息向MQ发送异常\n* 消息从MQ消费保存之前\n* 消息从MQ消费保存之后\n* 订阅者方法执行之前\n* 订阅者方法执行之后\n* 订阅者方法执行异常\n\n### 在 Skywalking APM 中追踪 CAP 事件\n\nSkywalking 的 C# 客户端提供了对 CAP Diagnostics 的支持，你可以利用 [SkyAPM-dotnet](https://github.com/SkyAPM/SkyAPM-dotnet) 来实现在 Skywalking 中追踪事件。\n\n尝试阅读Readme文档来在你的项目中集成它。\n\n![](https://user-images.githubusercontent.com/8205994/71006463-51025980-2120-11ea-82dc-bffa5530d515.png)\n\n\n![](https://user-images.githubusercontent.com/8205994/71006589-7b541700-2120-11ea-910b-7e0f2dfddce8.png)\n\n### 其他 APM 的支持\n\n目前还没有实现对除了 Skywalking 的其他APM的支持，如果你想在其他 APM 中实现对 CAP 诊断事件的支持，你可以参考这里的代码来实现它：\n\nhttps://github.com/SkyAPM/SkyAPM-dotnet/tree/master/src/SkyApm.Diagnostics.CAP\n\n## 度量(Metrics)\n\n度量是指对于一个物体或是事件的某个性质给予一个数字，使其可以和其他物体或是事件的相同性质比较。度量可以是对一物理量（如长度、尺寸或容量等）的估计或测定，也可以是其他较抽象的特质。\n\nCAP 7.0 对 `EventSource` 提供了支持，计数器名称为 `DotNetCore.CAP.EventCounter`。\n\nCAP 提供了以下几个度量指标：\n\n* 每秒发布速度\n* 每秒消费速度\n* 每秒调用订阅者速度\n* 每秒执行订阅者平均耗时\n\n### 使用 dotnet-counters 查看度量\n\n[dotnet-counters](https://learn.microsoft.com/zh-cn/dotnet/core/diagnostics/dotnet-counters) 是一个性能监视工具，用于临时运行状况监视和初级性能调查。 它可以观察通过 EventCounter API 或 Meter API 发布的性能计数器值。 \n\n使用以下命令来监视CAP中的度量指标：\n\n```ps\ndotnet-counters ps\ndotnet-counters monitor --process-id=25496 --counters=DotNetCore.CAP.EventCounter\n```\n\n其中 process-id 为 CAP 所属的进程Id。\n\n![img](../../../img/dotnet-counters.gif)\n\n### 在 Dashboard 中查看度量\n\n你可以配置 `x.UseDashboard()` 来开启仪表盘以图表的形式查看 Metrics 指标。 如下图：\n\n![img](../../../img/dashboard-metrics.gif)\n\n\n在 Realtime Metric Graph 中，时间轴会随着时间实时滚动从而可以看到发布和消费消息每秒的速率，同时我们可以看到消费者执行耗时以“打点”的方式在 Y1 轴上（Y0轴为速率，Y1轴为执行耗时）。\n\n"
  },
  {
    "path": "docs/content/user-guide/zh/monitoring/kubernetes.md",
    "content": "# Kubernetes\n\n[Kubernetes](https://kubernetes.io)，也称为 K8s，是一个开源系统，用于自动部署、扩展和管理容器化应用程序。\n\n## Dashboard 中的 Kubernetes\n\n我们的 Dashboard 从 7.2.0 版本开始支持 Kubernetes 作为服务发现。你可以切换到Node节点页面，然后选择命名空间，CAP会列出该命名空间下的所有Services，点击 *切换* 按钮后Dashboard将检测该节点的CAP服务是否可用，如果可用则会代理到切换的节点进行数据查看。\n\n以下是一个配置示例\n\n```cs\nservices.AddCap(x =>\n{\n    // ...\n    x.UseDashboard();\n    x.UseK8sDiscovery();\n});\n\n```\n\n## 使用K8sDiscovery配置\n\n此配置选项用于配置仪表板/节点以默认列出每个 K8s `service` 。如果将此设置为 `true`，则只会列出带有`dotnetcore.cap.visibility: show` 标签的服务。有关标签的更多信息可以在 **Kubernetes 标签配置** 部分找到。\n\n* ShowOnlyExplicitVisibleNodes\n\n> 默认值：false\n\n\n```cs\nservices.AddCap(x =>\n{\n    // ...\n    x.UseK8sDiscovery(opt=>{\n      opt.ShowOnlyExplicitVisibleNodes = true;\n    });\n});\n```\n\n组件将会自动检测是否处于集群内部，如果处于集群内部在需要赋予Pod Kubernetes Api 的权限。参考下一章节。\n\n## 分配 Pod 访问  Kubernetes Api \n\n如果你的Deployment关联的ServiceAccount没有K8s Api访问权限的话，则需要赋予 `namespaces`, `services` 资源的 `get`, `list` 权限。\n\n这是一个实例yaml，首先创建一个 ServiceAccount 和 ClusterRole 并设置相关权限，然后使用 ClusterRoleBinding 进行绑定。最后在Deployment中使用 `serviceAccountName: api-access` 继续指定。\n\n```\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: api-access\n\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  name: ns-svc-reader\nrules:\n- apiGroups: [\"\"]\n  resources: [\"namespaces\", \"services\"]\n  verbs: [\"get\", \"watch\", \"list\"]\n\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: read-pods\nsubjects:\n- kind: ServiceAccount\n  name: api-access\n  namespace: default\nroleRef:\n  kind: ClusterRole\n  name: ns-svc-reader\n  apiGroup: rbac.authorization.k8s.io\n  \n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: api-access-deployment\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: api-access-app\n  template:\n    metadata:\n      labels:\n        app: api-access-app\n    spec:\n      serviceAccountName: api-access\n      containers:\n      - name: api-access-container\n        image: your_image\n        \n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: api-access-service\nspec:\n  selector:\n    app: api-access-app\n  ports:\n    - protocol: TCP\n      port: 80\n      targetPort: 80\n```\n\n从版本 `8.3.0` 及更高版本，您可以使用 `Role` 而不是 `ClusterRole`，以允许仅在仪表板运行的命名空间内发现服务。 Kubernetes 角色在命名空间内拥有有限的管辖权。在上面的示例中，只需删除 ClusterRole 和 ClusterRoleBinding 并改为使用以下内容\n\n```\napiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  name: ns-svc-reader\nrules:\n- apiGroups: [\"\"]\n  resources: [\"services\"]\n  verbs: [\"get\", \"watch\", \"list\"]\n\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: read-pods\nsubjects:\n- kind: ServiceAccount\n  name: api-access\n  namespace: default\nroleRef:\n  kind: ClusterRole\n  name: ns-svc-reader\n  apiGroup: rbac.authorization.k8s.io\n\n```\n\n## Kubernetes 标签配置\n\n可以通过向 kubernetes 服务添加标签来控制仪表板中显示的节点列表。\n\n\n- `dotnetcore.cap.visibility` 标签用于显示或隐藏列表中的服务。\n\n    > 可能的值: show | hide\n\n    > 示例: `dotnetcore.cap.visibility: show` or `dotnetcore.cap.visibility: hide`\n\n默认情况下，每个 k8s 服务都会列出该服务中找到的第一个端口。但是，如果服务上存在更多端口，您可以使用以下标签选择所需的端口：\n\n- `dotnetcore.cap.portName` 标签用于过滤需要的服务端口。\n\n    > 可能的值: string\n\n    > 示例: `dotnetcore.cap.portName: grpc` or `dotnetcore.cap.portName: http`\n\nIf not found any port with the given name, it will try to match the next label portIndex\n\n- `dotnetcore.cap.portIndex` 标签用于过滤需要的服务端口。 仅当未设置标签 portName 或设置不匹配的 portName 时，才会考虑此过滤器。\n\n    > 可能的值: 数字表示为字符串 ex: '2' or '14'\n\n    > 示例: `dotnetcore.cap.portIndex: '1'` or `dotnetcore.cap.portIndex: '3'`\n\n  如果提供的索引超出范围，那么它将回退到第一个端口（索引：0）\n\n\n\n## 独立使用 Dashboard \n\n你可以独立使用 Dashboard 而不需要配置CAP，此时相当于 Dashboard 可作为单独的 Pod 部署到 Kubernetes 集群中仅用作查看数据，待查看的服务不再需要配置 `cap.UseK8sDiscovery()` 配置项。\n\n```\nservices.AddCapDashboardStandalone();\n```\n\n同样，你需要为此Pod配置 ServiceAccount 的访问权限。"
  },
  {
    "path": "docs/content/user-guide/zh/monitoring/opentelemetry.md",
    "content": "# OpenTelemetry \n\nhttps://opentelemetry.io/\n\nOpenTelemetry是工具、api和sdk的集合。 使用它来检测、生成、收集和导出遥测数据(度量、日志和跟踪)，以帮助您分析软件的性能和行为。\n\n## 集成\n\n你可以在[这里](https://opentelemetry.io/docs/instrumentation/net/getting-started/)找到关于如何在控制台应用或ASP.NET Core 中使用OpenTelemetry。\n在这里我们主要描述如何将CAP集成到OpenTelemetry中。\n\n### 配置\n\n安装CAP的OpenTelemetry包到项目中。\n\n```C#\ndotnet add package DotNetCore.Cap.OpenTelemetry\n```\n\nOpenTelemetry 的跟踪数据来自于[Diagnostics](diagnostics.md)发送的诊断数据，添加 CAP Instrumentation 到 OpenTelemetry的扩展配置中会进行自动收集。\n\n```C#\nservices.AddOpenTelemetryTracing((builder) => builder\n    .AddAspNetCoreInstrumentation()\n    .AddCapInstrumentation()    // <-- 添加这行\n    .AddZipkinExporter()\n);\n```\n\n以下是CAP的跟踪数据在 Zipkin 中的一个示意图：\n\n<img src=\"/img/opentelemetry.png\">"
  },
  {
    "path": "docs/content/user-guide/zh/samples/castle.dynamicproxy.md",
    "content": "# 和 Castle DynamicProxy 集成\n\nCastle DynamicProxy 是一个用于在运行时动态生成轻量级.NET代理的库。代理对象允许在不修改类代码的情况下截取对对象成员的调用。可以代理类和接口，但是只能拦截虚拟成员。\n\nCastle.DynamicProxy 可以帮助你方便的创建代理对象，代理对象可以帮助构建灵活的应用程序体系结构，因为它允许将功能透明地添加到代码中，而无需对其进行修改。例如，可以代理一个类来添加日志记录或安全检查，而无需使代码知道已添加此功能。\n\n下面可以看到如何在 CAP 中集成使用 Castle.DynamicProxy。\n\n\n## 1、安装 NuGet 包\n\n在 集成了 CAP 的项目中安装包，有关如何集成 CAP 的文档请看[这里](https://cap.dotnetcore.xyz/)。\n\n注意，`Castle.DynamicProxy` 这个包已经被废弃，请使用最新的 `Castle.Core` 包。\n\n```xml\n<PackageReference Include=\"Castle.Core\" Version=\"4.4.1\" />\n```\n\n## 2、创建一个 Castle 切面拦截器\n\n可以在这里 [dynamicproxy.md](https://github.com/castleproject/Core/blob/master/docs/dynamicproxy.md) 找到相关的文档。\n\n下面为示例代码，继承 Castle 提供的 `IInterceptor` 接口即可：\n\n```\n[Serializable]\npublic class MyInterceptor : IInterceptor\n{\n    public void Intercept(IInvocation invocation)\n    {\n        Console.WriteLine(\"Before target call\");\n        try\n        {\n            invocation.Proceed();\n        }\n        catch (Exception)\n        {\n            Console.WriteLine(\"Target threw an exception!\");\n            throw;\n        }\n        finally\n        {\n            Console.WriteLine(\"After target call\");\n        }\n    }\n}\n\n```\n\n拦截器此处命名为 `MyInterceptor`，你可以在其中处理你的业务逻辑，比如添加日志或其他的一些行为。\n\n## 3、创建 IServiceCollection 的扩展类\n\n为 `IServiceCollection` 创建扩展，方面后续调用。\n\n```csharp\nusing Castle.DynamicProxy;\n\npublic static class ServicesExtensions\n{\n    public static void AddProxiedSingleton<TImplementation>(this IServiceCollection services)\n        where TImplementation : class\n    {\n        services.AddSingleton(serviceProvider =>\n        {\n            var proxyGenerator = serviceProvider.GetRequiredService<ProxyGenerator>();\n            var interceptors = serviceProvider.GetServices<IInterceptor>().ToArray();\n            return proxyGenerator.CreateClassProxy<TImplementation>(interceptors);\n        });\n    }\n}\n```\n\n此处我创建了一个 Singleton 声明周期的扩展方法，建议所有 CAP 的订阅者都创建为 Singleton 即可，因为在 CAP 内部实际执行的时候也会创建一个 scope 来执行，所以无需担心资源释放问题。\n\n\n## 4、创建 CAP 订阅服务\n\n创建一个 CAP 订阅类，注意不能放在 Controller 中了。\n\n**注意：方法需要为虚方法 virtual，才能被 Castle 重写，别搞忘了加！！！**  \n\n```cs\npublic class CapSubscribeService: ICapSubscribe\n{\n    [CapSubscribe(\"sample.rabbitmq.mysql\")]\n    public virtual void Subscriber(DateTime p)\n    {\n        Console.WriteLine($@\"{DateTime.Now} Subscriber invoked, Info: {p}\");\n    }\n}\n```\n\n## 5、在 Startup 中集成\n\n```cs\npublic void ConfigureServices(IServiceCollection services)\n{\n    // 添加 Castle 的代理生成器\n    services.AddSingleton(new ProxyGenerator());\n    \n    // 添加第2步的自定义的拦截类，声明周期为\n    services.AddSingleton<IInterceptor, MyInterceptor>();\n    \n    // 此处为上面的扩展方法， 添加 CAP 订阅 Service\n    services.AddProxiedSingleton<CapSubscribeService>();\n    \n    services.AddCap(x =>\n    {\n        x.UseMySql(\"\");\n        x.UseRabbitMQ(\"\");\n        x.UseDashboard();\n    });\n    \n    // ...\n}\n```\n\n以上就完成了所有的集成工作，可以开始进行测试了，有问题欢迎到 [Github issue](https://github.com/dotnetcore/CAP/issues) 反馈。\n"
  },
  {
    "path": "docs/content/user-guide/zh/samples/eshoponcontainers.md",
    "content": "# eShopOnContainers\n\neShopOnContainers is a sample application written in C# running on .NET Core using a microservice architecture, Domain Driven Design.\n\n> .NET Core reference application, powered by Microsoft, based on a simplified microservices architecture and Docker containers.\n\n> This reference application is cross-platform at the server and client side, thanks to .NET Core services capable of running on Linux or Windows containers depending on your Docker host, and to Xamarin for mobile apps running on Android, iOS or Windows/UWP plus any browser for the client web apps.\n\n> The architecture proposes a microservice oriented architecture implementation with multiple autonomous microservices (each one owning its own data/db) and implementing different approaches within each microservice (simple CRUD vs. DDD/CQRS patterns) using Http as the communication protocol between the client apps and the microservices and supports asynchronous communication for data updates propagation across multiple services based on Integration Events and an Event Bus (a light message broker, to choose between RabbitMQ or Azure Service Bus, underneath) plus other features defined at the roadmap.\n\n## eShopOnContainers with CAP\n\n你可以在下面的地址看到如何在 eShopOnContainers 中使用 CAP。\n\nhttps://github.com/yang-xiaodong/eShopOnContainers"
  },
  {
    "path": "docs/content/user-guide/zh/samples/faq.md",
    "content": "# FAQ\n\n!!! faq \"有没有学习和讨论 CAP 的即时通讯群组（例如腾讯 QQ 群）？\"\n\n回答： 暂时没有。与其浪费大量时间在即时通讯群组里，我更希望开发者能够培养独立思考能力，并通过查阅文档自行解决问题，甚至可以在遇到错误时创建issue或发送电子邮件。\n\n!!! faq \"CAP 是否需要为生产者和消费者分别使用不同的数据库？\"\n\n回答：没有必要使用完全不同的数据库，推荐为每个程序使用一个专用数据库。\n\n否则，请参阅下面的问答部分。\n\n!!! faq \"如何使用相同的数据库用于不同的应用程序？\"\n\n回答： 在 ConfigureServices 方法中定义表名前缀。\n\n代码示例：\n\n```c#\npublic void ConfigureServices(IServiceCollection services)\n{\n    services.AddCap(x =>\n    {\n        x.UseKafka(\"\");\n        x.UseMySql(opt =>\n        {\n            opt.ConnectionString = \"connection string\";\n            opt.TableNamePrefix = \"appone\"; // different table name prefix here\n        });\n    });\n}\n```\n\n!!! faq \"CAP 能否不使用数据库作为事件存储？我只是想发送消息\"\n\n回答： 完全不用是不可能的，你可以使用 InMemoryStorage 。\n\nCAP 的目的是在微服务或 SOA 架构中确保一致性原则。该解决方案基于数据库的 ACID 特性，如果没有数据库，单纯的消息队列消息传递是没有意义的。\n\n!!! faq \"如果消费者出现异常，能否回滚生产者执行的数据库语句？\"\n\n回答： 无法回滚，CAP 是最终一致性解决方案。\n\n可以想象您的场景是调用第三方支付。如果您正在进行第三方支付操作，在成功调用支付宝的接口后，您的代码出现错误，支付宝会回滚吗？如果不回滚，您该怎么办？CAP 的情况与此类似。"
  },
  {
    "path": "docs/content/user-guide/zh/samples/github.md",
    "content": "# Github 上的示例\n\n你可以在下面的地址找到相关示例代码：\n\nhttps://github.com/dotnetcore/CAP/tree/master/samples\n\nCAP + Aspire + Azure Service Bus + Azure SQL\n\nhttps://github.com/NikiforovAll/cap-aspire"
  },
  {
    "path": "docs/content/user-guide/zh/storage/general.md",
    "content": "# 基本\n\nCAP 需要使用具有持久化功能的存储介质来存储事件消息，例如通过数据库或者其他NoSql设施。CAP 使用这种方式来应对一切环境或者网络异常导致消息丢失的情况，消息的可靠性是分布式事务的基石，所以在任何情况下消息都不能丢失。\n\n## 持久化\n\n### 发送前\n\n在消息进入到消息队列之前，CAP使用本地数据库表对消息进行持久化，这样可以保证当消息队列出现异常或者网络错误时候消息是没有丢失的。\n\n为了保证这种机制的可靠性，CAP使用和业务代码相同的数据库事务来保证业务操作和CAP的消息在持久化的过程中是强一致的。也就是说在进行消息持久化的过程中，任何一方发生异常情况数据库都会进行回滚操作。\n\n###  发送后\n\n消息进入到消息队列之后，CAP会启动消息队列的持久化功能，我们需要说明一下在 RabbitMQ 和 Kafka 中CAP的消息是如何持久化的。\n\n针对于 RabbitMQ 中的消息持久化，CAP 使用的是具有消息持久化功能的消费者队列，但是这里面可能有例外情况，参加 2.2.1 章节。\n\n由于 Kafka 天生设计的就是使用文件进行的消息持久化，在所以在消息进入到Kafka之后，Kafka会保证消息能够正确被持久化而不丢失。\n\n## 消息存储\n\n### 支持的存储\n\nCAP 支持以下几种具有事务支持的数据库做为存储：\n\n* [SQL Server](sqlserver.md)\n* [MySQL](mysql.md)\n* [PostgreSql](postgresql.md)\n* [MongoDB](mongodb.md)\n* [In-Memory Storage](in-memory-storage.md)\n\n在 CAP 启动后，会向持久化介质中生成两个表，默认情况下名称为：`Cap.Published` `Cap.Received`。\n\n### 存储格式\n\n**Published** 表结构：\n\nNAME | DESCRIPTION | TYPE\n:---|:---|:---\nId | Message Id | int\nVersion | Message Version | string\nName | Topic Name | string\nContent | Json Content | string\nAdded | Added Time | DateTime\nExpiresAt | Expire time | DateTime\nRetries | Retry times | int\nStatusName | Status Name | string\n\n**Received** 表结构：\n\nNAME | DESCRIPTION | TYPE\n:---|:---|:---\nId | Message Id | int\nVersion | Message Version | string\nName | Topic Name | string\nGroup | Group Name | string\nContent | Json Content | string\nAdded | Added Time | DateTime\nExpiresAt | Expire time | DateTime\nRetries | Retry times | int\nStatusName | Status Name | string\n\n**Lock** 表结构（可选）：\n\nNAME | DESCRIPTION | TYPE\n:---|:---|:---\nKey | Lock Id | string\nInstance | Acquired instance of lock | string\nLastLockTime | Last acquired lock time | DateTime\n\n### 包装器对象\n\nCAP 在进行消息发送到时候，会对原始消息对象进行一个二次包装存储到 `Content` 字段中，以下为包装 Content 的 Message 对象数据结构：\n\nNAME | DESCRIPTION | TYPE\n:---|:---|:---\nId\t| CAP生成的消息编号\t| string\nTimestamp |\t消息创建时间 |\tstring\nContent |\t内容 |\tstring\nCallbackName |\t回调的订阅者名称 | string\n\n其中 Id 字段，CAP 采用的 MongoDB 中的 ObjectId 分布式Id生成算法生成。\n\n## 社区支持的持久化\n\n感谢社区对CAP的支持，以下是社区支持的持久化的实现\n\n* SQLite ([@colinin](https://github.com/colinin)) ：https://github.com/colinin/DotNetCore.CAP.Sqlite   \n\n* LiteDB ([@maikebing](https://github.com/maikebing)) ：https://github.com/maikebing/CAP.Extensions\n\n* SQLite & Oracle ([@cocosip](https://github.com/cocosip)) ：https://github.com/cocosip/CAP-Extensions   \n\n* SmartSql ([@xiangxiren](https://github.com/xiangxiren)) ：https://github.com/xiangxiren/SmartSql.CAP\n\n* DM（达梦数据库）([@findersky](https://github.com/findersky)) ：https://github.com/findersky/CAP\n"
  },
  {
    "path": "docs/content/user-guide/zh/storage/in-memory-storage.md",
    "content": "# In-Memory Storage\n\n内存消息的持久化存储常用于开发和测试环境，如果使用基于内存的存储则你会失去本地事务消息可靠性保证。\n\n## 配置\n\n如果要使用内存存储，你需要从 NuGet 安装以下扩展包：\n\n```\nInstall-Package DotNetCore.CAP.InMemoryStorage\n```\n\n然后，你可以在 `Startup.cs` 的 `ConfigureServices` 方法中添加基于内存的配置项。\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UseInMemoryStorage();\n        // x.UseXXX ...\n    });\n}\n\n```\n\n内存中的发送成功消息，CAP 将会每 5分钟 进行一次清理。\n\n\n## Publish with transaction\n\nIn-Memory 存储 **不支持** 事务方式发送消息。\n\n"
  },
  {
    "path": "docs/content/user-guide/zh/storage/mongodb.md",
    "content": "# MongoDB\n\nMongoDB 是一个跨平台的面向文档型的数据库程序，它被归为 NOSQL 数据库，CAP 从 2.3 版本开始支持 MongoDB 作为消息存储。 \n\nMongoDB 从 4.0 版本开始支持 ACID 事务，所以 CAP 也只支持 4.0 以上的 MongoDB，并且 MongoDB 需要部署为集群，因为 MongoDB 的 ACID 事务需要集群才可以使用。\n\n有关开发环境如何快速搭建 MongoDB 4.0+ 集群，你可以我的参考 [这篇文章](https://www.cnblogs.com/savorboard/p/mongodb-4-cluster-install.html)。\n\n## 配置\n\n要使用 MongoDB 存储，你需要从 NuGet 安装以下扩展包：\n\n```shell\n\nInstall-Package DotNetCore.CAP.MongoDB\n\n```\n\n然后，你可以在 `Startup.cs` 的 `ConfigureServices` 方法中添加基于内存的配置项。\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UseMongoDB(opt=>{\n            //MongoDBOptions\n        });\n        // x.UseXXX ...\n    });\n}\n\n```\n\n#### 配置项\n\nNAME | DESCRIPTION | TYPE | DEFAULT\n:---|:---|---|:---\nDatabaseName | 数据库名称 | string | cap \nDatabaseConnection | 数据库连接字符串 | string | mongodb://localhost:27017\nReceivedCollection | 接收消息集合名称 | string | cap.received\nPublishedCollection | 发送消息集合名称 | string | cap.published\n\n## 使用事务发布消息\n\n下面的示例展示了如何利用 CAP 和 MongoDB 进行本地事务集成。\n\n```csharp\n\n//NOTE: before your test, your need to create database and collection at first\n//注意：MongoDB 不能在事务中创建数据库和集合，所以你需要单独创建它们，模拟一条记录插入则会自动创建        \n//var mycollection = _client.GetDatabase(\"test\").GetCollection<BsonDocument>(\"test.collection\");\n//mycollection.InsertOne(new BsonDocument { { \"test\", \"test\" } });\n\nusing (var session = _client.StartTransaction(_capBus, autoCommit: false))\n{\n    var collection = _client.GetDatabase(\"test\").GetCollection<BsonDocument>(\"test.collection\");\n    collection.InsertOne(session, new BsonDocument { { \"hello\", \"world\" } });\n\n    _capBus.Publish(\"sample.rabbitmq.mongodb\", DateTime.Now);\n\n    session.CommitTransaction();\n}\n     \n```"
  },
  {
    "path": "docs/content/user-guide/zh/storage/mysql.md",
    "content": "# MySQL\n\nMySQL 是一个开源的关系型数据库，你可以使用 MySQL 来作为 CAP 消息的持久化。\n\n## 配置\n\n要使用 MySQL 存储，你需要从 NuGet 安装以下扩展包：\n\n```shell\nInstall-Package DotNetCore.CAP.MySql\n```\n\n然后，你可以在 `Startup.cs` 的 `ConfigureServices` 方法中添加基于内存的配置项。\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UseMySql(opt=>{\n            //MySqlOptions\n        });\n        // x.UseXXX ...\n    });\n}\n\n```\n\n### 配置项\n\nNAME | DESCRIPTION | TYPE | DEFAULT\n:---|:---|---|:---\nTableNamePrefix | Cap表名前缀 | string | cap \nConnectionString | 数据库连接字符串 | string | null\n\n### 自定义表名称\n\n你可以通过重写 `IStorageInitializer` 接口获取表名称的方法来做到这一点\n\n示例代码：\n\n```C#\n\npublic class MyTableInitializer : MySqlStorageInitializer\n{\n    public override string GetPublishedTableName()\n    {\n        //你的 发送消息表 名称\n    }\n\n    public override string GetReceivedTableName()\n    {\n        //你的 接收消息表 名称\n    }\n}\n```\n然后将你的实现注册到容器中\n\n```\nservices.AddSingleton<IStorageInitializer, MyTableInitializer>();\n```\n\n## 使用事务发布消息\n\n### ADO.NET \n\n```csharp\n\nprivate readonly ICapPublisher _capBus;\n\nusing (var connection = new MySqlConnection(AppDbContext.ConnectionString))\n{\n    using (var transaction = connection.BeginTransaction(_capBus, autoCommit: false))\n    {\n        //your business code\n        connection.Execute(\"insert into test(name) values('test')\", \n            transaction: (IDbTransaction)transaction.DbTransaction);\n        \n        _capBus.Publish(\"sample.rabbitmq.mysql\", DateTime.Now);\n\n        transaction.Commit();\n    }\n}\n```\n\n### EntityFramework \n\n```csharp\n\nprivate readonly ICapPublisher _capBus;\n\nusing (var trans = dbContext.Database.BeginTransaction(_capBus, autoCommit: false))\n{\n    dbContext.Persons.Add(new Person() { Name = \"ef.transaction\" });\n    \n    _capBus.Publish(\"sample.rabbitmq.mysql\", DateTime.Now);\n\n    dbContext.SaveChanges();\n    trans.Commit();\n}\n\n```"
  },
  {
    "path": "docs/content/user-guide/zh/storage/postgresql.md",
    "content": "# Postgre SQL\n\nPostgreSQL 是一个开源的关系型数据库，它已经变得越来越流行，你可以使用 Postgre SQL 来作为 CAP 消息的持久化。\n\n## 配置\n\n要使用 PostgreSQL 存储，你需要从 NuGet 安装以下扩展包：\n\n```shell\n\nInstall-Package DotNetCore.CAP.PostgreSql\n\n```\n\n然后，你可以在 `Startup.cs` 的 `ConfigureServices` 方法中添加基于内存的配置项。\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UsePostgreSql(opt=>{\n            //PostgreSqlOptions\n        }); \n        // x.UseXXX ...\n    });\n}\n\n```\n\n### 配置项\n\nNAME | DESCRIPTION | TYPE | DEFAULT\n:---|:---|---|:---\nSchema | 数据库架构 | string | cap \nConnectionString | 数据库连接字符串 | string | \nDataSource | [Data source](https://www.npgsql.org/doc/basic-usage.html#data-source) | [NpgsqlDataSource](https://www.npgsql.org/doc/api/Npgsql.NpgsqlDataSource.html) |\n\n### 自定义表名称\n\n你可以通过重写 `IStorageInitializer` 接口获取表名称的方法来做到这一点\n\n示例代码：\n\n```C#\n\npublic class MyTableInitializer : PostgreSqlStorageInitializer\n{\n    public override string GetPublishedTableName()\n    {\n        //你的 发送消息表 名称\n    }\n\n    public override string GetReceivedTableName()\n    {\n        //你的 接收消息表 名称\n    }\n}\n```\n然后将你的实现注册到容器中\n\n```\nservices.AddSingleton<IStorageInitializer, MyTableInitializer>();\n```\n\n## 使用事务发布消息\n\n### ADO.NET \n\n```csharp\n\nprivate readonly ICapPublisher _capBus;\n\nusing (var connection = new NpgsqlConnection(\"ConnectionString\"))\n{\n    using (var transaction = connection.BeginTransaction(_capBus, autoCommit: false))\n    {\n        //your business code\n        connection.Execute(\"insert into test(name) values('test')\", \n            transaction: (IDbTransaction)transaction.DbTransaction);\n        \n        _capBus.Publish(\"sample.rabbitmq.mysql\", DateTime.Now);\n\n        transaction.Commit();\n    }\n}\n```\n\n### EntityFramework\n\n```csharp\n\nprivate readonly ICapPublisher _capBus;\n\nusing (var trans = dbContext.Database.BeginTransaction(_capBus, autoCommit: false))\n{\n    dbContext.Persons.Add(new Person() { Name = \"ef.transaction\" });\n    \n    _capBus.Publish(\"sample.rabbitmq.mysql\", DateTime.Now);\n\n    dbContext.SaveChanges();\n    trans.Commit();\n}\n\n```"
  },
  {
    "path": "docs/content/user-guide/zh/storage/sqlserver.md",
    "content": "# SQL Server\n\nSQL Server 是由微软开发的一个关系型数据库，你可以使用 SQL Server 来作为 CAP 消息的持久化。\n\n!!! warning \"注意\"\n    我们目前使用 `Microsoft.Data.SqlClient` 作为数据库驱动程序，它是SQL Server 驱动的未来，并且已经放弃了 `System.Data.SqlClient`，我们建议你切换过去。\n\n## 配置\n\n要使用 SQL Server 存储，你需要从 NuGet 安装以下扩展包：\n\n```shell\n\nInstall-Package DotNetCore.CAP.SqlServer\n\n```\n\n然后，你可以在 `Startup.cs` 的 `ConfigureServices` 方法中添加基于内存的配置项。\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UseSqlServer(opt=>{\n            //SqlServerOptions\n        }); \n        // x.UseXXX ...\n    });\n}\n\n```\n\n### 配置项\n\nNAME | DESCRIPTION | TYPE | DEFAULT\n:---|:---|---|:---\nSchema | 数据库架构 | string | Cap\nConnectionString | 数据库连接字符串 | string | \n\n### 自定义表名称\n\n你可以通过重写 `IStorageInitializer` 接口获取表名称的方法来做到这一点\n\n示例代码：\n\n```C#\n\npublic class MyTableInitializer : SqlServerStorageInitializer\n{\n    public override string GetPublishedTableName()\n    {\n        //你的 发送消息表 名称\n    }\n\n    public override string GetReceivedTableName()\n    {\n        //你的 接收消息表 名称\n    }\n}\n```\n然后将你的实现注册到容器中\n\n```\nservices.AddSingleton<IStorageInitializer, MyTableInitializer>();\n```\n\n## 使用事务发布消息\n\n### ADO.NET \n\n```csharp\n\nprivate readonly ICapPublisher _capBus;\n\nusing (var connection = new SqlConnection(\"ConnectionString\"))\n{\n    using (var transaction = connection.BeginTransaction(_capBus, autoCommit: false))\n    {\n        //your business code\n        connection.Execute(\"insert into test(name) values('test')\", \n            transaction: (IDbTransaction)transaction.DbTransaction);\n        \n        _capBus.Publish(\"sample.rabbitmq.mysql\", DateTime.Now);\n\n        transaction.Commit();\n    }\n}\n```\n\n### EntityFramework\n\n```csharp\n\nprivate readonly ICapPublisher _capBus;\n\nusing (var trans = dbContext.Database.BeginTransaction(_capBus, autoCommit: false))\n{\n    dbContext.Persons.Add(new Person() { Name = \"ef.transaction\" });\n    \n    _capBus.Publish(\"sample.rabbitmq.mysql\", DateTime.Now);\n\n    dbContext.SaveChanges();\n    trans.Commit();\n}\n\n```\n"
  },
  {
    "path": "docs/content/user-guide/zh/transport/aws-sqs.md",
    "content": "# Amazon SQS\n\nAWS SQS 是一种完全托管的消息队列服务，可让您分离和扩展微服务、分布式系统和无服务器应用程序。\n\nAWS SNS 是一种高度可用、持久、安全、完全托管的发布/订阅消息收发服务，可以轻松分离微服务、分布式系统和无服务器应用程序。\n\n## CAP 如何使用 AWS SNS & SQS\n\n### SNS\n\n由于 CAP 是基于 Topic 模式工作的，所以需要使用到 AWS SNS，SNS 简化了消息的发布订阅架构。\n\n在 CAP 启动时会将所有的订阅名称注册为 SNS 的 Topic，你将会在管理控制台中看到所有已经注册的 Topic 列表。 \n\n由于 SNS 不支持使用 `.` `:` 等符号作为 Topic 的名称，所以我们进行了替换，我们将 `.` 替换为了 `-`，将 `:` 替换为了 `_`\n\n!!! note \"注意事项\"\n    Amazon SNS 当前允许发布的消息最大大小为 256KB\n\n举例，你的当前项目中有以下两个订阅者方法\n\n```C#\n[CapSubscribe(\"sample.sns.foo\")]\npublic void TestFoo(DateTime value)\n{\n}\n\n[CapSubscribe(\"sample.sns.bar\")]\npublic void TestBar(DateTime value)\n{\n}\n```\n\n在 CAP 启动后，在 AWS SNS 中你将看到\n\n![img](../../../img/aws-sns-demo.png)\n\n### SQS\n\n针对每个消费者组，CAP 将创建一个与之对应的 SQS 队列，队列的名称为配置项中 DefaultGroup 的名称，类型为 Standard Queue 。\n\n该 SQS 队列将订阅 SNS 中的 Topic ，如下图：\n\n![img](../../../img/aws-sns-demo.png)\n\n!!! warning \"注意事项\"\n    由于 AWS SNS 的限制，当你减少订阅方法时，我们不会主动删除 AWS SNS 或者 SQS 上的相关 Topic 或 Queue，你需要手动删除他们。\n\n\n## 配置\n\n要使用 AWS SQS 作为消息传输器，你需要从 NuGet 安装以下扩展包：\n\n```shell\n\nInstall-Package DotNetCore.CAP.AmazonSQS\n\n```\n\n然后，你可以在 `Startup.cs` 的 `ConfigureServices` 方法中添加基于 RabbitMQ 的配置项。\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UseAmazonSQS(opt=>\n        {\n            //AmazonSQSOptions\n        });\n        // x.UseXXX ...\n    });\n}\n\n```\n\n#### AmazonSQS Options\n\nCAP 直接对外提供的 AmazonSQSOptions 配置参数如下：\n\nNAME | DESCRIPTION | TYPE | DEFAULT\n:---|:---|---|:---\nRegion | AWS 所处的区域 | Amazon.RegionEndpoint | \nCredentials | AWS AK SK信息 | Amazon.Runtime.AWSCredentials | \n\n如果你的项目运行在 AWS EC2 中，则不需要设置 Credentials，直接对 EC2 应用 IAM 策略即可。\n\nCredentials 需要具有新增和订阅 SNS Topic，SQS Queue 等权限。"
  },
  {
    "path": "docs/content/user-guide/zh/transport/azure-service-bus.md",
    "content": "# Azure Service Bus\n\nAzure 服务总线是一种多租户云消息服务，可用于在应用程序和服务之间发送信息。 异步操作可实现灵活的中转消息传送、结构化的先进先出 (FIFO) 消息传送以及发布/订阅功能。\n\nCAP 支持使用 Azure Service Bus 作为消息传输器。\n\n## Configuration\n\n!!! warning \"必须条件\"\n    针对 Service Bus 的定价, CAP 要求使用  “标准” 或者 “高级” 以支持 Topic 功能。\n\n要使用 Azure Service Bus 作为消息传输器，你需要从 NuGet 安装以下扩展包：\n\n```shell\n\nInstall-Package DotNetCore.CAP.AzureServiceBus\n\n```\n\n然后，你可以在 `Startup.cs` 的 `ConfigureServices` 方法中添加基于内存的配置项。\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UseAzureServiceBus(opt=>\n        {\n            //AzureServiceBusOptions\n        });\n        // x.UseXXX ...\n    });\n}\n\n```\n\n#### AzureServiceBus Options\n\nCAP 直接对外提供的 Azure Service Bus 配置参数如下：\n\n| 名称                                 | 描述                                                                                                                                       | 类型                                                                   | 默认值                           |\n| :----------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | :------------------------------- |\n| ConnectionString                     | 终端地址                                                                                                                                   | string                                                                 |                                  |\n| TopicPath                            | 主题实体路径                                                                                                                               | string                                                                 | cap                              |\n| EnableSessions                       | 启用 [Service Bus 会话](https://docs.microsoft.com/zh-cn/azure/service-bus-messaging/message-sessions)                                     | bool                                                                   | false                            |\n| MaxConcurrentSessions                | 处理器可处理的最大并发会话数。当 EnableSessions 为 false 时不适用。                                                                        | int                                                                    | 8                                |\n| SessionIdleTimeout                   | 在会话关闭前等待新消息的最长时间。如果未指定，Azure Service Bus 将使用 60 秒。                                                             | TimeSpan                                                               | null                             |\n| SubscriptionAutoDeleteOnIdle         | 在特定空闲间隔后自动删除订阅。                                                                                                             | TimeSpan                                                               | TimeSpan.MaxValue                |\n| SubscriptionMessageLockDuration      | 给定接收器锁定消息的时间，以防止其他接收器接收相同的消息。                                                                                 | TimeSpan                                                               | 60 秒                            |\n| SubscriptionDefaultMessageTimeToLive | 订阅的默认消息生存时间值。这是消息到期前的持续时间。                                                                                       | TimeSpan                                                               | TimeSpan.MaxValue                |\n| SubscriptionMaxDeliveryCount         | 消息在被传递给订阅后进入死信队列之前的最大传递次数。                                                                                       | int                                                                    | 10                               |\n| MaxAutoLockRenewalDuration           | 锁自动续订的最长持续时间。该值应大于最长的消息锁定持续时间。                                                                               | TimeSpan                                                               | 5 分钟                           |\n| ManagementTokenProvider              | 令牌提供程序                                                                                                                               | ITokenProvider                                                         | null                             |\n| AutoCompleteMessages                 | 获取一个值，该值指示在消息处理程序完成处理后，处理器是否应自动完成消息。                                                                   | bool                                                                   | false                            |\n| CustomHeadersBuilder                 | 为来自异构系统的传入消息添加自定义和/或强制性标头。                                                                                        | `Func<Message, IServiceProvider, List<KeyValuePair<string, string>>>?` | null                             |\n| Namespace                            | Servicebus 的命名空间，在使用 TokenCredential 属性时需要设置。                                                                             | string                                                                 | null                             |\n| DefaultCorrelationHeaders            | 将附加的关联属性添加到所有 [关联筛选器](https://learn.microsoft.com/zh-cn/azure/service-bus-messaging/topic-filters#correlation-filters)。 | IDictionary<string, string>                                            | Dictionary<string, string>.Empty |\n| SQLFilters                           | 在主题订阅上按名称和表达式定义的自定义 SQL 筛选器。                                                                                        | List<KeyValuePair<string, string>>                                     | null                             |\n\n#### Sessions\n\n当使用 `EnableSessions` 选项启用 sessions 后，每个发送的消息都会具有一个 session id。 要控制 seesion id 你可以在发送消息时在消息头中使用 `AzureServiceBusHeaders.SessionId` 携带它。\n\n\n```C#\nICapPublisher capBus = ...;\nstring yourEventName = ...;\nYourEventType yourEvent = ...;\n\nDictionary<string, string> extraHeaders = new Dictionary<string, string>();\nextraHeaders.Add(AzureServiceBusHeaders.SessionId, <your-session-id>);\n\ncapBus.Publish(yourEventName, yourEvent, extraHeaders);\n```\n\n如果头中没有 session id , 那么消息 Id 仍然使用的 Message Id.\n\n\n#### Heterogeneous Systems\n\n有时您可能想接收由外部系统发布的消息。 在这种情况下，您需要添加一组两个强制标头以实现 CAP 兼容性，如下所示。\n\n```C#\nc.UseAzureServiceBus(asb =>\n{\n    asb.ConnectionString = ...\n    asb.CustomHeadersBuilder = (msg, sp) =>\n    [\n        new(DotNetCore.CAP.Messages.Headers.MessageId, sp.GetRequiredService<ISnowflakeId>().NextId().ToString()),\n        new(DotNetCore.CAP.Messages.Headers.MessageName, msg.RoutingKey)\n    ];\n});\n```\n\n> 重要提示：如果消息中已存在同名（Key）的标头，则不会添加自定义标头。 \n"
  },
  {
    "path": "docs/content/user-guide/zh/transport/general.md",
    "content": "# 运输器\n\n通过运输将数据从一个地方移动到另一个地方-在采集程序和管道之间，管道与实体数据库之间，甚至在管道与外部系统之间。\n\n## 支持的运输器\n\nCAP 支持以下几种运输方式：\n\n* [RabbitMQ](rabbitmq.md)\n* [Kafka](kafka.md)\n* [Azure Service Bus](azure-service-bus.md)\n* [Amazon SQS](aws-sqs.md)\n* [NATS](nats.md)\n* [In-Memory Queue](in-memory-queue.md)\n* [Redis Streams](redis-streams.md)\n* [Apache Pulsar](pulsar.md)\n\n## 怎么选择运输器\n\n 🏳‍🌈  | RabbitMQ | Kafka | Azure Service Bus | In-Memory\n:--   |   :--:    | :--: | :--:               | :--:\n**定位** | 可靠消息传输 | 实时数据处理 | 云 | 内存型，测试\n**分布式**   | ✔   | ✔    | ✔ |❌\n**持久化** | ✔ | ✔ | ✔ | ❌\n**性能**  |  Medium  |  High | Medium | High\n\n\n> `Azure Service Bus` vs `RabbitMQ` :  \n> http://geekswithblogs.net/michaelstephenson/archive/2012/08/12/150399.aspx\n\n>`Kafka` vs `RabbitMQ` :   \n> https://stackoverflow.com/questions/42151544/is-there-any-reason-to-use-rabbitmq-over-kafka\n\n## 社区支持的运输器\n\n感谢社区对CAP的支持，以下是社区支持的运输器实现\n\n* ActiveMQ (@[Lukas Zhang](https://github.com/lukazh/Lukaz.CAP.ActiveMQ)): https://github.com/lukazh\n\n* RedisMQ ([@木木](https://github.com/difudotnet)): https://github.com/difudotnet/CAP.RedisMQ.Extensions\n\n* ZeroMQ ([@maikebing](https://github.com/maikebing)): https://github.com/maikebing/CAP.Extensions/tree/master/src/DotNetCore.CAP.ZeroMQ\n\n* MQTT ([@john jiang](https://github.com/jinzaz)): https://github.com/jinzaz/jinzaz.CAP.MQTT"
  },
  {
    "path": "docs/content/user-guide/zh/transport/in-memory-queue.md",
    "content": "# In-Memory Queue\n\nIn Memory Queue 为基于内存的消息队列，该扩展由 [社区](https://github.com/yang-xiaodong/Savorboard.CAP.InMemoryMessageQueue) 进行提供。\n\n## 配置\n\n要使用 In Memory Queue 作为消息传输器，你需要从 NuGet 安装以下扩展包：\n\n```shell\n\nInstall-Package Savorboard.CAP.InMemoryMessageQueue\n\n```\n\n然后，你可以在 `Startup.cs` 的 `ConfigureServices` 方法中添加基于内存的配置项。\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UseInMemoryMessageQueue();\n        // x.UseXXX ...\n    });\n}\n\n```"
  },
  {
    "path": "docs/content/user-guide/zh/transport/kafka.md",
    "content": "# Apache Kafka®\n\n[Apache Kafka®](https://kafka.apache.org/) 是一个开源流处理软件平台，由 LinkedIn 开发并捐赠给 Apache Software Foundation，用 Scala 和 Java 编写。\n \nCAP 支持使用 Apache Kafka® 作为消息传输器。\n\n## Configuration\n\n要使用 Kafka 作为消息传输器，你需要从 NuGet 安装以下扩展包：\n\n```shell\n\nInstall-Package DotNetCore.CAP.Kafka\n\n```\n\n然后，你可以在 `Startup.cs` 的 `ConfigureServices` 方法中添加基于 Kafka 的配置项。\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UseKafka(opt=>{\n            //KafkaOptions\n        });\n        // x.UseXXX ...\n    });\n}\n\n```\n\n#### Kafka Options\n\nCAP 直接对外提供的 Kafka 配置参数如下：\n\nNAME | DESCRIPTION | TYPE | DEFAULT\n:---|:---|---|:---\nServers | Broker 地址 | string | \nMainConfig | librdkafka 的配置参数 | Dictionary<string, string> | 见下\nConnectionPoolSize | 用户名 | int | 10\nCustomHeadersBuilder | 设置自定义头 | Function | 见下\nRetriableErrorCodes |  ConsumeException 异常时的重试错误码集合  | IList<ErrorCode> |  见代码\nTopicOptions | 配置 NumPartitions 和 ReplicationFactor | KafkaTopicOptions |  -1\n\n#### Kafka MainConfig Options\n\n如果你需要 **更多** 原生 Kakfa 相关的配置项，可以通过 `MainConfig` 配置项进行设定：\n\n```csharp\nservices.AddCap(capOptions => \n{\n    capOptions.UseKafka(kafkaOption=>\n    {\n        // kafka options.\n        // kafkaOptions.MainConfig.Add(\"\", \"\");\n    });\n});\n```\n\nMainConfig 为配置字典，你可以通过以下链接找到其支持的配置项列表。\n\n[https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md](https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md)\n\n要禁止 CAP 自动创建主题，可以关闭该功能：\n\n```csharp\nservices.AddCap(capOptions =>\n{\n    capOptions.UseKafka(kafkaOption =>\n    {\n        kafkaOption.MainConfig.Add(\"allow.auto.create.topics\", \"false\");\n    });\n});\n```\n\n#### CustomHeadersBuilder Options\n\n有关 `CustomHeadersBuilder` 的说明：\n\n如果你想在消费消息的时候，通过从 `CapHeader` 获取 Kafka 中例如 Offset 或者 Partition 等信息，你可以通过自定义此函数来实现这一点。\n\n例如以下代码为你展示了如何进行设置额外的参数到 `CapHeader` 中:\n\n```C#\nx.UseKafka(opt =>\n{\n    //...\n\n    opt.CustomHeadersBuilder = (kafkaResult,sp) => new List<KeyValuePair<string, string>>\n    {\n        new KeyValuePair<string, string>(\"my.kafka.offset\", kafkaResult.Offset.ToString()),\n        new KeyValuePair<string, string>(\"my.kafka.partition\", kafkaResult.Partition.ToString())\n    };\n});\n```\n\n然后你可以通过这个方式来获取你添加的头信息:\n\n```C#\n[CapSubscribe(\"sample.kafka.postgrsql\")]\npublic void HeadersTest(DateTime value, [FromCap]CapHeader header)\n{\n    var offset = header[\"my.kafka.offset\"];\n    var partition = header[\"my.kafka.partition\"];\n}\n```\n"
  },
  {
    "path": "docs/content/user-guide/zh/transport/nats.md",
    "content": "# NATS\n\n[NATS](https://nats.io/)是一个简单、安全、高性能的数字系统、服务和设备通信系统。NATS 是 CNCF 的一部分。\n\n!!! warning\n    自 CAP 5.2+ 的版本已经基于 [JetStream](https://docs.nats.io/nats-concepts/jetstream) 实现相关功能，所以需要在服务端显式启用。\n    \n    **你需要在 NATS Server 启动时候指定 `--jetstream` 参数来启用 JetSteram 相关功能，才能正常使用CAP.**\n\n## 配置\n\n要使用NATS 传输器，你需要安装下面的NuGet包：\n\n```powershell\n\nPM> Install-Package DotNetCore.CAP.NATS\n\n```\n\n你可以通过在 `Startup.cs` 文件中配置 `ConfigureServices` 来添加配置：\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    services.AddCap(capOptions =>\n    {\n        capOptions.UseNATS(natsOptions=>{\n            //NATS Options\n        });\n    });\n}\n\n```\n\n#### NATS 配置\n\nCAP 直接提供的关于 NATS 的配置参数：\n\n\nNAME | DESCRIPTION | TYPE | DEFAULT\n:---|:---|---|:---\nOptions | NATS 客户端配置 | Options | Options\nServers | 服务器Urls地址 | string | NULL\nConnectionPoolSize  | 连接池数量 | uint | 10\nDeliverPolicy | 消费消息的策略点（⚠️在8.1.0版本移除，使用`ConsumerOptions`替代。） | enum | DeliverPolicy.New\nStreamOptions | 🆕 Stream 配置项 |  Action | NULL\nConsumerOptions | 🆕 Consumer 配置项 | Action | NULL\nCustomHeadersBuilder | 订阅者自定义头信息 |  见下文 |  N/A\n\n#### NATS ConfigurationOptions\n\n如果你需要 **更多** 原生相关的配置项，可以通过 `Options` 配置项进行设定：\n\n```csharp\nservices.AddCap(capOptions => \n{\n    capOptions.UseNATS(natsOptions=>\n    {\n        // NATS options.\n        natsOptions.Options.Url=\"\";\n    });\n});\n```\n\n`Options` 是 NATS.Client 客户端提供的配置， 你可以在这个[链接](http://nats-io.github.io/nats.net/class_n_a_t_s_1_1_client_1_1_options.html)找到更多详细信息。\n\n#### CustomHeadersBuilder Option\n\n当需要从异构系统或者直接接收从 NATS JetStream 发送的消息时，由于 CAP 需要定义额外的头信息才能正常订阅，所以此时会出现异常。通过提供此参数来进行自定义头信息的设置来使订阅者正常工作。\n\n你可以在这里找到有关 [头信息](../cap/messaging.md#异构系统集成) 的说明。\n\n用法如下：\n\n```cs\nx.UseNATS(aa =>\n{\n    aa.CustomHeadersBuilder = (e, sp) =>\n    [\n        new(DotNetCore.CAP.Messages.Headers.MessageId, sp.GetRequiredService<ISnowflakeId>().NextId().ToString()),\n        new(DotNetCore.CAP.Messages.Headers.MessageName, e.Message.Subject)\n    ];\n});\n```"
  },
  {
    "path": "docs/content/user-guide/zh/transport/pulsar.md",
    "content": "# Apache Pulsar\n\n[Apache Pulsar](https://pulsar.apache.org/) 是一个用于服务器到服务器的消息系统，具有多租户、高性能等优势。 Pulsar 最初由 Yahoo 开发，目前由 Apache 软件基金会管理。\n\nCAP 支持使用 Apache Pulsar 作为消息传输器。\n\n## Configuration\n\n要使用 Pulsar 作为消息传输器，你需要从 NuGet 安装以下扩展包：\n\n```shell\n\nInstall-Package DotNetCore.CAP.Pulsar\n\n```\n\n然后，你可以在 `Startup.cs` 的 `ConfigureServices` 方法中添加基于 Pulsar 的配置项。\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UsePulsar(opt => {\n            //Pulsar Options\n        });\n        // x.UseXXX ...\n    });\n}\n\n```\n\n#### Pulsar Options\n\nCAP 直接对外提供的 Pulsar 配置参数如下：\n\nNAME | DESCRIPTION | TYPE | DEFAULT\n:---|:---|---|:---\nServiceUrl | Broker 地址 | string | \nTlsOptions | TLS 配置项 | object | \n"
  },
  {
    "path": "docs/content/user-guide/zh/transport/rabbitmq.md",
    "content": "# RabbitMQ\n\nRabbitMQ是实现了高级消息队列协议（AMQP）的开源消息代理软件（亦称面向消息的中间件）。RabbitMQ 服务器是用 Erlang 语言编写的，而聚类和故障转移是构建在开源的通讯平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端库。\n\nCAP 支持使用 RabbitMQ 作为消息传输器。\n\n!!! warning \"注意事项\" \n    在使用RabbitMQ时，集成了CAP的消费者应用在启动过一次后会自动创建持久化的队列，后续消息会正常传递到队列中并消费。\n    如果你从来没有启动过消费者，则队列不会被自动创建，此时如果先行发布消息，在此时间段的消息 RabbitMQ Exchange 收到后会直接丢弃。\n\n## 配置\n\n要使用 RabbitMQ 作为消息传输器，你需要从 NuGet 安装以下扩展包：\n\n```shell\n\nInstall-Package DotNetCore.CAP.RabbitMQ\n\n```\n\n然后，你可以在 `Startup.cs` 的 `ConfigureServices` 方法中添加基于 RabbitMQ 的配置项。\n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    // ...\n\n    services.AddCap(x =>\n    {\n        x.UseRabbitMQ(opt=>\n        {\n            //RabbitMQOptions\n        });\n        // x.UseXXX ...\n    });\n}\n\n```\n\n#### RabbitMQ Options\n\nCAP 直接对外提供的 RabbitMQ 配置参数如下：\n\n配置项 | 描述 | 类型 | 默认值\n:---|:---|---|:---\nHostName | 宿主地址，如果要配置集群可以使用逗号分隔，例如 `192.168.1.111,192.168.1.112` | string | localhost\nUserName | 用户名 | string | guest\nPassword | 密码 | string | guest\nVirtualHost | 虚拟主机 | string | /\nPort | 端口号 | int | -1\nExchangeName | CAP默认Exchange名称 | string | cap.default.topic\nQueueArguments  | 队列额外参数 x-arguments | QueueArgumentsOptions  |  N/A\nQueueOptions  | 更改已创建队列的选项 | QueueRabbitOptions  |  { Durable=true, Exclusive=false, AutoDelete=false }\nConnectionFactoryOptions  |  RabbitMQClient原生参数 | ConnectionFactory | N/A\nCustomHeadersBuilder  | 订阅者自定义头信息 |  见下文 |  N/A\nPublishConfirms | 是否启用[发布确认](https://www.rabbitmq.com/confirms.html#publisher-confirms) | bool | false\nBasicQosOptions | 指定消费的[Qos](https://www.rabbitmq.com/consumer-prefetch.html) | BasicQos | N/A\n\n#### ConnectionFactory Option\n\n如果你需要 **更多** 原生 `ConnectionFactory` 相关的配置项，可以通过 `ConnectionFactoryOptions` 配置项进行设定：\n\n```csharp\n\nservices.AddCap(x =>\n{\n    x.UseRabbitMQ(o =>\n    {\n        o.HostName = \"localhost\";\n        o.ConnectionFactoryOptions = opt => { \n            //rabbitmq client ConnectionFactory config\n        };\n    });\n});\n\n```\n\n#### CustomHeadersBuilder Option\n\n当需要从异构系统或者直接接收从RabbitMQ 控制台发送的消息时，由于 CAP 需要定义额外的头信息才能正常订阅，所以此时会出现异常。通过提供此参数来进行自定义头信息的设置来使订阅者正常工作。\n\n你可以在这里找到有关 [头信息](../cap/messaging.md#异构系统集成) 的说明。\n\n用法如下：\n\n```cs\nx.UseRabbitMQ(aa =>\n{\n    aa.CustomHeadersBuilder = (msg, sp) =>\n    [\n        new(DotNetCore.CAP.Messages.Headers.MessageId, sp.GetRequiredService<ISnowflakeId>().NextId().ToString()),\n        new(DotNetCore.CAP.Messages.Headers.MessageName, msg.RoutingKey)\n    ];\n});\n```\n\n\n#### 如何连接 RabbitMQ 集群？\n\n使用逗号分隔连接字符串即可，如下：\n\n```\nx=> x.UseRabbitMQ(\"localhost:5672,localhost:5673,localhost:5674\")\n```\n"
  },
  {
    "path": "docs/content/user-guide/zh/transport/redis-streams.md",
    "content": "# Redis Streams\n\n[Redis](https://redis.io/) 是一个开源（BSD许可）的，内存中的数据结构存储系统，它可以用作数据库、缓存和消息中间件。\n\n[Redis Stream](https://redis.io/topics/streams-intro) 是 Redis 5.0 引入的一种新数据类型，它用一种仅附加的数据结构以更抽象的方式模拟日志数据结构。\n\nRedis Streams 可以在 CAP 中用作消息传输器。 \n\n## 配置\n\n要使用 Redis Streams 传输器，您需要从 NuGet 安装以下包：\n\n```powershell\nPM> Install-Package DotNetCore.CAP.RedisStreams\n```\n\n然后，您可以在 `Startup.cs` 的 `ConfigureServices` 方法中添加基于 Redis Stream 的配置项。 \n\n```csharp\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    services.AddCap(capOptions =>\n    {\n        capOptions.UseRedis(redisOptions=>{\n            //redisOptions\n        });\n    });\n}\n\n```\n\n#### Redis Streams Options\n\nCAP 直接对外提供的 Redis Stream 配置参数如下：\n\nNAME | DESCRIPTION | TYPE | DEFAULT\n:---|:---|---|:---\nConfiguration | redis连接配置 (StackExchange.Redis) | ConfigurationOptions | ConfigurationOptions\nStreamEntriesCount | 读取时从 stream 返回的条目数  | uint | 10\nConnectionPoolSize  | 连接池数  | uint | 10\n\n#### Redis Configuration Options\n\n如果需要**更多**原生Redis相关配置选项，您可以在 `Configuration` 选项中进行设置 :\n\n```csharp\nservices.AddCap(capOptions => \n{\n    capOptions.UseRedis(redisOptions=>\n    {\n        // redis options.\n        redisOptions.Configuration.EndPoints.Add(IPAddress.Loopback, 0);\n    });\n});\n```\n\n`Configuration` 是 StackExchange.Redis ConfigurationOptions ，您可以通过此[链接](https://stackexchange.github.io/StackExchange.Redis/Configuration)找到更多详细信息。\n\n### 流清理注意事项\n\n由于redis streams 没有自动删除所有已经被所有组确认的消息的特性[issue](https://github.com/redis/redis/issues/5774)，所以你需要考虑是否使用脚本来执行定期删除。"
  },
  {
    "path": "docs/mkdocs.yml",
    "content": "# Project information\nsite_name: CAP\nsite_url: http://cap.dotnetcore.xyz\nsite_description: A distributed transaction solution in micro-service base on eventually consistency, also an eventbus with Outbox pattern.\nsite_author: CAP Team\n\nrepo_name: \"GitHub\"\nrepo_url: \"https://github.com/dotnetcore/CAP\"\nedit_uri: \"edit/master/docs/content\"\ndocs_dir: \"content\"\n\n# Copyright\ncopyright: Copyright &copy; 2023 <a href=\"https://github.com/dotnetcore\">NCC</a>, Maintained by the <a href=\"/about/contact-us/#cap-team\">CAP Team</a>.\n\n#theme: material\ntheme:\n  name: \"material\"\n  palette:\n    primary: \"deep purple\"\n    accent: \"indigo\"\n  language: en\n  include_sidebar: true\n  logo: \"img/logo.svg\"\n  favicon: \"img/favicon.ico\"\n  features:\n    - navigation.tabs\n    - navigation.instant\n  i18n:\n    prev: \"Previous\"\n    next: \"Next\"\n\n#Customization\nextra:\n  alternate:\n    - name: English\n      link: /user-guide/en/getting-started/quick-start\n      lang: en\n    - name: 中文\n      link: /user-guide/zh/getting-started/quick-start\n      lang: zh\n  social:\n    - icon: \"fontawesome/brands/github\"\n      link: \"https://github.com/dotnetcore/CAP\"\n    - icon: \"fontawesome/brands/twitter\"\n      link: \"https://twitter.com/ncc_community\"\n    - icon: \"fontawesome/brands/weibo\"\n      link: \"https://weibo.com/dotnetcore\"\n  analytics:\n    provider: google\n    property: !!python/object/apply:os.getenv [\"GOOGLE_ANALYTICS_KEY\"]\n    feedback:\n      title: Was this page helpful?\n      ratings:\n        - icon: material/emoticon-happy-outline\n          name: This page was helpful\n          data: 1\n          note: >-\n            Thanks for your feedback!\n        - icon: material/emoticon-sad-outline\n          name: This page could be improved\n          data: 0\n          note: >- \n            Thanks for your feedback!\n\n# Extensions\nmarkdown_extensions:\n  - markdown.extensions.admonition\n  - markdown.extensions.codehilite:\n      guess_lang: true\n      linenums: false\n  - markdown.extensions.def_list\n  - markdown.extensions.footnotes\n  - markdown.extensions.meta\n  - markdown.extensions.toc:\n      permalink: true\n  - pymdownx.arithmatex\n  - pymdownx.betterem:\n      smart_enable: all\n  - pymdownx.caret\n  - pymdownx.critic\n  - pymdownx.details\n  - pymdownx.emoji:\n      emoji_generator: !!python/name:pymdownx.emoji.to_svg\n  - pymdownx.inlinehilite\n  - pymdownx.keys\n  - pymdownx.magiclink:\n      repo_url_shorthand: true\n      user: dotnetcore\n      repo: cap\n  - pymdownx.mark\n  - pymdownx.smartsymbols\n  - pymdownx.superfences\n  - pymdownx.tasklist:\n      custom_checkbox: true\n  - pymdownx.tilde\n\nnav:\n  - Home: index.md\n  - Documentation:\n      - Getting Started:\n          - Quick Start: user-guide/en/getting-started/quick-start.md\n          - Introduction: user-guide/en/getting-started/introduction.md\n          - Contributing: user-guide/en/getting-started/contributing.md\n      - CAP:\n          - Configuration: user-guide/en/cap/configuration.md\n          - Messaging: user-guide/en/cap/messaging.md\n          - Filter: user-guide/en/cap/filter.md\n          - Serialization: user-guide/en/cap/serialization.md\n          - Transactions: user-guide/en/cap/transactions.md\n          - Idempotence: user-guide/en/cap/idempotence.md\n      - Transport:\n          - General: user-guide/en/transport/general.md\n          - Amazon SQS: user-guide/en/transport/aws-sqs.md\n          - Apache Kafka®: user-guide/en/transport/kafka.md\n          - Apache Pulsar: user-guide/en/transport/pulsar.md\n          - Azure Service Bus: user-guide/en/transport/azure-service-bus.md\n          - NATS: user-guide/en/transport/nats.md\n          - RabbitMQ: user-guide/en/transport/rabbitmq.md\n          - Redis Streams: user-guide/en/transport/redis-streams.md\n          - In-Memory Queue: user-guide/en/transport/in-memory-queue.md\n      - Storage:\n          - General: user-guide/en/storage/general.md\n          - SQL Server: user-guide/en/storage/sqlserver.md\n          - MySQL: user-guide/en/storage/mysql.md\n          - PostgreSql: user-guide/en/storage/postgresql.md\n          - MongoDB: user-guide/en/storage/mongodb.md\n          - In-Memory: user-guide/en/storage/in-memory-storage.md\n      - Monitoring:\n          - Consul: user-guide/en/monitoring/consul.md\n          - Dashboard: user-guide/en/monitoring/dashboard.md\n          - Kubernetes: user-guide/en/monitoring/kubernetes.md\n          - Diagnostics: user-guide/en/monitoring/diagnostics.md\n          - OpenTelemetry: user-guide/en/monitoring/opentelemetry.md\n      - Samples:\n          - Github: user-guide/en/samples/github.md\n          - eShopOnContainers: user-guide/en/samples/eshoponcontainers.md\n          - FAQ: user-guide/en/samples/faq.md\n  - 文档（中文）:\n      - 入门:\n          - 快速开始: user-guide/zh/getting-started/quick-start.md\n          - 介绍: user-guide/zh/getting-started/introduction.md\n          - 贡献: user-guide/zh/getting-started/contributing.md\n      - CAP:\n          - 配置: user-guide/zh/cap/configuration.md\n          - 消息: user-guide/zh/cap/messaging.md\n          - 过滤器: user-guide/zh/cap/filter.md\n          - 序列化: user-guide/zh/cap/serialization.md\n          - 事务: user-guide/zh/cap/transactions.md\n          - 幂等性: user-guide/zh/cap/idempotence.md\n      - 传输:\n          - 简介: user-guide/zh/transport/general.md\n          - Amazon SQS: user-guide/zh/transport/aws-sqs.md\n          - Apache Kafka®: user-guide/zh/transport/kafka.md\n          - Apache Pulsar: user-guide/zh/transport/pulsar.md\n          - Azure Service Bus: user-guide/zh/transport/azure-service-bus.md\n          - NATS: user-guide/zh/transport/nats.md\n          - RabbitMQ: user-guide/zh/transport/rabbitmq.md\n          - Redis Streams: user-guide/zh/transport/redis-streams.md\n          - In-Memory Queue: user-guide/zh/transport/in-memory-queue.md\n      - 存储:\n          - 简介: user-guide/zh/storage/general.md\n          - SQL Server: user-guide/zh/storage/sqlserver.md\n          - MySQL: user-guide/zh/storage/mysql.md\n          - PostgreSql: user-guide/zh/storage/postgresql.md\n          - MongoDB: user-guide/zh/storage/mongodb.md\n          - In-Memory: user-guide/zh/storage/in-memory-storage.md\n      - 监控:\n          - Consul: user-guide/zh/monitoring/consul.md\n          - Dashboard: user-guide/zh/monitoring/dashboard.md\n          - Kubernetes: user-guide/zh/monitoring/kubernetes.md\n          - Diagnostics: user-guide/zh/monitoring/diagnostics.md\n          - OpenTelemetry: user-guide/zh/monitoring/opentelemetry.md\n      - 示例:\n          - Castle DynamicProxy: user-guide/zh/samples/castle.dynamicproxy.md\n          - Github: user-guide/zh/samples/github.md\n          - eShopOnContainers: user-guide/zh/samples/eshoponcontainers.md\n          - FAQ: user-guide/zh/samples/faq.md\n  - About:\n      - Contact Us: about/contact-us.md\n      - Release Notes: about/release-notes.md\n      - License: about/license.md"
  },
  {
    "path": "docs/readme.md",
    "content": "# CAP Documentation\n\nThe folder contains the documentation for CAP.\n\nWe are using [Github Pages](https://github.com/dotnetcore/CAP/tree/gh-pages) to host the documentation and the rendered version can be found [here](http://cap.dotnetcore.xyz).\n\n## Docs site\n\nDoc pages are authored in Markdown  - you can find a primer [here](https://help.gamejolt.com/markdown).\n\nWeb site made with [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/)\n\n### Local build with docker\n\n```\ncd CAP/docs\ndocker run --rm -it -p 8000:8000 -v ${PWD}:/docs squidfunk/mkdocs-material\n```"
  },
  {
    "path": "samples/Sample.AmazonSQS.InMemory/Controllers/ValuesController.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace Sample.AmazonSQS.InMemory.Controllers\n{\n    [Route(\"api/[controller]\")]\n    public class ValuesController : Controller, ICapSubscribe\n    {\n        private readonly ICapPublisher _capBus;\n\n        public ValuesController(ICapPublisher producer)\n        {\n            _capBus = producer;\n        }\n\n        [Route(\"~/without/transaction\")]\n        public async Task<IActionResult> WithoutTransaction()\n        {\n            await _capBus.PublishAsync(\"sample.aws.in-memory\", DateTime.Now);\n\n            return Ok();\n        }\n\n        [CapSubscribe(\"sample.aws.in-memory\")]\n        public void SubscribeInMemoryTopic(DateTime value)\n        {\n            Console.WriteLine(\"Subscriber output message: \" + value);\n        }\n    }\n}"
  },
  {
    "path": "samples/Sample.AmazonSQS.InMemory/Program.cs",
    "content": "﻿using Amazon;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.DependencyInjection;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// Configure services\nbuilder.Services.AddCap(x =>\n{\n    x.UseInMemoryStorage();\n    x.UseAmazonSQS(RegionEndpoint.CNNorthWest1);\n    x.UseDashboard();\n});\n\nbuilder.Services.AddControllers();\n\nvar app = builder.Build();\n\n// Configure middleware pipeline\napp.UseRouting();\napp.MapControllers();\n\napp.Run();"
  },
  {
    "path": "samples/Sample.AmazonSQS.InMemory/Sample.AmazonSQS.InMemory.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n  </PropertyGroup>\n   \n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.AmazonSQS\\DotNetCore.CAP.AmazonSQS.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.Dashboard\\DotNetCore.CAP.Dashboard.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.InMemoryStorage\\DotNetCore.CAP.InMemoryStorage.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n  </ItemGroup> \n\n</Project>\n"
  },
  {
    "path": "samples/Sample.AmazonSQS.InMemory/appsettings.json",
    "content": "﻿{\n  \"Logging\": {\n    \"IncludeScopes\": false,\n    \"LogLevel\": {\n      \"Default\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "samples/Sample.AzureServiceBus.InMemory/Contracts/DomainEvents/Contract.cs",
    "content": "namespace Sample.AzureServiceBus.InMemory.Contracts.DomainEvents;\n\npublic record EntityCreated(Guid Id);\n\npublic record EntityDeleted(Guid Id);\n"
  },
  {
    "path": "samples/Sample.AzureServiceBus.InMemory/Contracts/IntegrationEvents/Contract.cs",
    "content": "namespace Sample.AzureServiceBus.InMemory.Contracts.IntegrationEvents;\n\npublic record EntityCreatedForIntegration(Guid Id);\n\npublic record EntityDeletedForIntegration(Guid Id);\n"
  },
  {
    "path": "samples/Sample.AzureServiceBus.InMemory/Program.cs",
    "content": "using DotNetCore.CAP;\nusing DotNetCore.CAP.Internal;\n\nusing Sample.AzureServiceBus.InMemory;\nusing Sample.AzureServiceBus.InMemory.Contracts.DomainEvents;\nusing Sample.AzureServiceBus.InMemory.Contracts.IntegrationEvents;\n\nvar builder = WebApplication.CreateBuilder(args);\n\nbuilder.Services.AddLogging(l => l.AddConsole());\n\nbuilder.Services.AddCap(c =>\n{\n\n    c.UseInMemoryStorage();\n    c.UseAzureServiceBus(asb =>\n    {\n        asb.ConnectionString = builder.Configuration.GetConnectionString(\"AzureServiceBus\")!;\n        asb.CustomHeadersBuilder = (message, serviceProvider) =>\n        {\n            var snowFlakeId = serviceProvider.GetRequiredService<ISnowflakeId>();\n\n            return new List<KeyValuePair<string, string>>()\n                        {\n\n                            new(DotNetCore.CAP.Messages.Headers.MessageId,\n                                snowFlakeId.NextId().ToString()),\n                            new(DotNetCore.CAP.Messages.Headers.MessageName, message.Subject),\n                            new(\"IsFromSampleProject\", \"'true'\")\n                        };\n        };\n        asb.SQLFilters = new List<KeyValuePair<string, string>>() {\n            new(\"IsFromSampleProjectFilter\",\"IsFromSampleProject = 'true'\")\n        };\n\n        asb.ConfigureCustomProducer<EntityCreatedForIntegration>(cfg => cfg.UseTopic(\"entity-created\").WithSubscription());\n        asb.ConfigureCustomProducer<EntityDeletedForIntegration>(cfg => cfg.UseTopic(\"entity-deleted\").WithSubscription());\n    });\n\n    c.UseDashboard();\n});\n\nbuilder.Services.AddSingleton<SampleSubscriber>();\n\nvar app = builder.Build();\n\napp.MapGet(\"/entity-created-for-integration\", async (ICapPublisher capPublisher) =>\n{\n    var message = new EntityCreatedForIntegration(Guid.NewGuid());\n    await capPublisher.PublishAsync(nameof(EntityCreatedForIntegration), message);\n});\n\napp.MapGet(\"/entity-deleted-for-integration\", async (ICapPublisher capPublisher) =>\n{\n    var message = new EntityDeletedForIntegration(Guid.NewGuid());\n    await capPublisher.PublishAsync(nameof(EntityDeletedForIntegration), message);\n});\n\napp.MapGet(\"/entity-created\", async (ICapPublisher capPublisher) =>\n{\n    var message = new EntityCreated(Guid.NewGuid());\n    await capPublisher.PublishAsync(nameof(EntityCreated), message);\n});\n\napp.MapGet(\"/entity-deleted\", async (ICapPublisher capPublisher) =>\n{\n    var message = new EntityDeleted(Guid.NewGuid());\n    await capPublisher.PublishAsync(nameof(EntityDeleted), message);\n});\n\napp.Run();"
  },
  {
    "path": "samples/Sample.AzureServiceBus.InMemory/Sample.AzureServiceBus.InMemory.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n    <PropertyGroup>\n        <TargetFramework>net10.0</TargetFramework>\n        <Nullable>enable</Nullable>\n        <ImplicitUsings>enable</ImplicitUsings>\n      <UserSecretsId>1c4ab524-d04d-459c-bf1d-9cb5da3ecaf1</UserSecretsId>\n  </PropertyGroup>\n\n    <ItemGroup>\n        <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.AzureServiceBus\\DotNetCore.CAP.AzureServiceBus.csproj\" />\n        <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.Dashboard\\DotNetCore.CAP.Dashboard.csproj\" />\n        <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.InMemoryStorage\\DotNetCore.CAP.InMemoryStorage.csproj\" />\n        <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n    </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "samples/Sample.AzureServiceBus.InMemory/SampleSubscriber.cs",
    "content": "using DotNetCore.CAP;\n\nnamespace Sample.AzureServiceBus.InMemory;\n\npublic class SampleSubscriber : ICapSubscribe\n{\n    public record Message(string Content);\n    \n    [CapSubscribe(\"cap.sample.tests\")]\n    public void Handle(Message message)\n    {\n        Console.WriteLine($\"Message {message.Content} received\");\n    }\n}"
  },
  {
    "path": "samples/Sample.AzureServiceBus.InMemory/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  }\n}\n"
  },
  {
    "path": "samples/Sample.AzureServiceBus.InMemory/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  },\n  \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "samples/Sample.ConsoleApp/EventSubscriber.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP;\n\nnamespace Sample.ConsoleApp\n{\n    public class EventSubscriber : ICapSubscribe\n    {\n        [CapSubscribe(\"sample.console.showtime\")]\n        public async Task ShowTime(DateTime date)\n        {\n            Console.WriteLine(date);\n            await Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "samples/Sample.ConsoleApp/Program.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP;\nusing DotNetCore.CAP.Filter;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Savorboard.CAP.InMemoryMessageQueue;\n\nnamespace Sample.ConsoleApp\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            var cts = new System.Threading.CancellationTokenSource();\n            var container = new ServiceCollection();\n\n            container.AddLogging(x => x.AddConsole());\n            container.AddCap(x =>\n            {\n                //console app does not support dashboard\n\n                x.UseInMemoryStorage();\n                x.UseInMemoryMessageQueue();\n            }).AddSubscribeFilter<Filter>();\n\n            container.AddSingleton<EventSubscriber>();\n\n            var sp = container.BuildServiceProvider();\n\n            sp.GetService<IBootstrapper>().BootstrapAsync(cts.Token);\n\n            _ = Task.Run(async () =>\n            {\n                while (!cts.IsCancellationRequested)\n                {\n                    await Task.Delay(2000, cts.Token);\n\n                    await sp.GetService<ICapPublisher>().PublishAsync(\"sample.console.showtime\", DateTime.Now, cancellationToken: cts.Token);\n                }\n            }, cts.Token);\n\n            AppDomain.CurrentDomain.ProcessExit += (_, _) =>\n            {\n                cts.Cancel();\n            };\n\n            Console.ReadLine();\n        }\n    }\n\n    public class Filter : SubscribeFilter\n    {\n        public override Task OnSubscribeExceptionAsync(ExceptionContext context)\n        {\n            if (context.Exception.InnerException is TimeoutException)\n            {\n                throw new TimeoutException(\"Http request timeout\");\n            }\n\n            return base.OnSubscribeExceptionAsync(context);\n        }\n    }\n}"
  },
  {
    "path": "samples/Sample.ConsoleApp/Sample.ConsoleApp.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n    <OutputType>Exe</OutputType>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.Logging.Console\" Version=\"10.0.0\" />\n    <PackageReference Include=\"Savorboard.CAP.InMemoryMessageQueue\" Version=\"8.2.1\" />\n  </ItemGroup>\n  \n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.InMemoryStorage\\DotNetCore.CAP.InMemoryStorage.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n  </ItemGroup> \n\n</Project>\n"
  },
  {
    "path": "samples/Sample.Dashboard.Auth/Controllers/ValuesController.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP;\nusing Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Extensions.Logging;\n\nnamespace Sample.Dashboard.Auth.Controllers\n{\n    [Authorize]\n    [Route(\"api/[controller]\")]\n    public class ValuesController : Controller\n    {\n        private readonly ICapPublisher _capBus;\n        private readonly ILogger<ValuesController> _logger;\n        private const string MyTopic = \"sample.dashboard.auth\";\n\n        public ValuesController(ICapPublisher capPublisher, ILogger<ValuesController> logger)\n        {\n            _capBus = capPublisher;\n            _logger = logger;\n        }\n\n        [Route(\"publish\")]\n        public async Task<IActionResult> Publish()\n        {\n            await _capBus.PublishAsync(MyTopic, new Person()\n            {\n                Id = new Random().Next(1, 100),\n                Name = \"Bar\"\n            });\n\n            return Ok();\n        }\n\n        [NonAction]\n        [CapSubscribe(MyTopic)]\n        public void Subscribe(Person p, [FromCap] CapHeader header)\n        {\n            _logger.LogInformation(\"Subscribe Invoked: \" + MyTopic + p);\n        }\n\n        public class Person\n        {\n            public int Id { get; set; }\n            public string Name { get; set; }\n        }\n    }\n}"
  },
  {
    "path": "samples/Sample.Dashboard.Auth/MyDashboardAuthenticationHandler.cs",
    "content": "﻿using System.Linq;\nusing System.Security.Claims;\nusing System.Text.Encodings.Web;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Authentication;\nusing Microsoft.AspNetCore.Authentication.OpenIdConnect;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace Sample.Dashboard.Auth\n{\n    public static class MyDashboardAuthenticationSchemeDefaults\n    {\n        public const string Scheme = \"MyDashboardAuthenticationScheme\";\n    }\n    \n    public class MyDashboardAuthenticationSchemeOptions : AuthenticationSchemeOptions\n    {\n\n    }\n\n    public class MyDashboardAuthenticationHandler : AuthenticationHandler<MyDashboardAuthenticationSchemeOptions>\n    {\n        public MyDashboardAuthenticationHandler(IOptionsMonitor<MyDashboardAuthenticationSchemeOptions> options,\n            ILoggerFactory logger, UrlEncoder encoder) : base(options, logger, encoder)\n        {\n           // options.CurrentValue.ForwardChallenge = \"\";\n        }\n\n        protected override Task<AuthenticateResult> HandleAuthenticateAsync()\n        {\n            var testAuthHeaderPresent = Request.Headers[\"X-Base-Token\"].Contains(\"xxx\");\n\n            var authResult = testAuthHeaderPresent ? CreateAuthenticatonTicket() : AuthenticateResult.NoResult();\n            \n            return Task.FromResult(authResult);\n        }\n\n        protected override Task HandleChallengeAsync(AuthenticationProperties properties)\n        {\n            //Response.Headers[\"WWW-Authenticate\"] = MyDashboardAuthenticationSchemeDefaults.Scheme;\n            //return base.HandleChallengeAsync(properties);\n\n            // Challenge use OpenId for AddCapWithOpenIdAndCustomAuthorization\n            return Context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, properties);\n        }\n\n        private AuthenticateResult CreateAuthenticatonTicket()\n        {\n            var claims = new[] { new Claim(ClaimTypes.Name, \"My Dashboard user\") };\n            var identity = new ClaimsIdentity(claims, MyDashboardAuthenticationSchemeDefaults.Scheme);\n            var principal = new ClaimsPrincipal(identity);\n            var ticket = new AuthenticationTicket(principal, MyDashboardAuthenticationSchemeDefaults.Scheme);\n\n            return AuthenticateResult.Success(ticket);\n        }\n    }\n}\n"
  },
  {
    "path": "samples/Sample.Dashboard.Auth/Program.cs",
    "content": "using Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Hosting;\n\nnamespace Sample.Dashboard.Auth\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            CreateHostBuilder(args).Build().Run();\n        }\n\n        public static IHostBuilder CreateHostBuilder(string[] args) =>\n            Host.CreateDefaultBuilder(args)\n                .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });\n    }\n}"
  },
  {
    "path": "samples/Sample.Dashboard.Auth/Sample.Dashboard.Auth.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n    <PropertyGroup>\n        <TargetFramework>net10.0</TargetFramework>\n    </PropertyGroup>\n\n    <ItemGroup>\n        <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.Dashboard\\DotNetCore.CAP.Dashboard.csproj\" />\n        <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.InMemoryStorage\\DotNetCore.CAP.InMemoryStorage.csproj\" />\n        <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n    </ItemGroup>\n    \n    <ItemGroup>\n        <PackageReference Include=\"Microsoft.AspNetCore.Authentication.OpenIdConnect\" Version=\"10.0.0\" />\n        <PackageReference Include=\"Savorboard.CAP.InMemoryMessageQueue\" Version=\"8.2.1\" />\n    </ItemGroup>\n</Project>\n"
  },
  {
    "path": "samples/Sample.Dashboard.Auth/Startup.cs",
    "content": "using Microsoft.AspNetCore.Authentication.Cookies;\nusing Microsoft.AspNetCore.Authentication.OpenIdConnect;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.DependencyInjection;\nusing Savorboard.CAP.InMemoryMessageQueue;\n\nnamespace Sample.Dashboard.Auth;\n\npublic class Startup\n{\n    public void ConfigureServices(IServiceCollection services)\n    {\n        // AddCapWithOpenIdAuthorization(services);\n        // AddCapWithAnonymousAccess(services);\n        // AddCapWithCustomAuthorization(services);\n        AddCapWithOpenIdAndCustomAuthorization(services);\n\n        services.AddCors(x =>\n        {\n            x.AddDefaultPolicy(p =>\n            {\n                p.WithOrigins(\"https://localhost:5001\").AllowCredentials().AllowAnyHeader().AllowAnyMethod();\n            });\n        });\n\n        services.AddControllers();\n    }\n\n    public void Configure(IApplicationBuilder app)\n    {\n        app.UseCors();\n        app.UseRouting();\n        app.UseAuthentication();\n        app.UseAuthorization();\n        app.UseCookiePolicy();\n        app.UseEndpoints(endpoints =>\n        {\n            endpoints.MapControllers();\n        });\n    }\n\n    private IServiceCollection AddCapWithOpenIdAuthorization(IServiceCollection services)\n    {\n        const string DashboardAuthorizationPolicy = \"DashboardAuthorizationPolicy\";\n\n        services\n            .AddAuthorization(options =>\n            {\n                options.AddPolicy(DashboardAuthorizationPolicy, policy => policy\n                    .AddAuthenticationSchemes(OpenIdConnectDefaults.AuthenticationScheme)\n                    .RequireAuthenticatedUser());\n            })\n            .AddAuthentication(opt => opt.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme)\n            .AddCookie()\n            .AddOpenIdConnect(options =>\n            {\n                options.RequireHttpsMetadata = false;\n                options.Authority = \"https://demo.duendesoftware.com/\";\n                options.ClientId = \"interactive.confidential\";\n                options.ClientSecret = \"secret\";\n                options.ResponseType = \"code\";\n                options.UsePkce = true;\n\n                options.Scope.Clear();\n                options.Scope.Add(\"openid\");\n                options.Scope.Add(\"profile\");\n            });\n\n        services.AddCap(cap =>\n        {\n            cap.UseDashboard(d =>\n            {\n                d.AllowAnonymousExplicit = false;\n                d.AuthorizationPolicy = DashboardAuthorizationPolicy;\n            });\n            cap.UseInMemoryStorage();\n            cap.UseInMemoryMessageQueue();\n        });\n\n        return services;\n    }\n\n    private IServiceCollection AddCapWithCustomAuthorization(IServiceCollection services)\n    {\n        const string MyDashboardAuthenticationPolicy = \"MyDashboardAuthenticationPolicy\";\n\n        services\n            .AddAuthorization(options =>\n            {\n                options.AddPolicy(MyDashboardAuthenticationPolicy, policy => policy\n                    .AddAuthenticationSchemes(MyDashboardAuthenticationSchemeDefaults.Scheme)\n                    .RequireAuthenticatedUser());\n            })\n            .AddAuthentication()\n            .AddScheme<MyDashboardAuthenticationSchemeOptions, MyDashboardAuthenticationHandler>(MyDashboardAuthenticationSchemeDefaults.Scheme, null);\n\n        services.AddCap(cap =>\n        {\n            cap.UseDashboard(d =>\n            {\n                d.AuthorizationPolicy = MyDashboardAuthenticationPolicy;\n            });\n            cap.UseInMemoryStorage();\n            cap.UseInMemoryMessageQueue();\n        });\n\n        return services;\n    }\n\n    private IServiceCollection AddCapWithOpenIdAndCustomAuthorization(IServiceCollection services)\n    {\n        const string DashboardAuthorizationPolicy = \"DashboardAuthorizationPolicy\";\n\n        services\n            .AddAuthorization(options =>\n            {\n                options.AddPolicy(DashboardAuthorizationPolicy, policy => policy\n                    .AddAuthenticationSchemes(OpenIdConnectDefaults.AuthenticationScheme, MyDashboardAuthenticationSchemeDefaults.Scheme)\n                    .RequireAuthenticatedUser());\n            })\n            .AddAuthentication(opt => opt.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme)\n            .AddScheme<MyDashboardAuthenticationSchemeOptions, MyDashboardAuthenticationHandler>(MyDashboardAuthenticationSchemeDefaults.Scheme, null)\n            .AddCookie()\n            .AddOpenIdConnect(options =>\n            {\n                options.RequireHttpsMetadata = false;\n                options.Authority = \"https://demo.duendesoftware.com/\";\n                options.ClientId = \"interactive.confidential\";\n                options.ClientSecret = \"secret\";\n                options.ResponseType = \"code\";\n                options.UsePkce = true;\n\n                options.Scope.Clear();\n                options.Scope.Add(\"openid\");\n                options.Scope.Add(\"profile\");\n            });\n\n        services.AddCap(cap =>\n        {\n            cap.UseDashboard(d =>\n            {\n                d.AllowAnonymousExplicit = false;\n                d.AuthorizationPolicy = DashboardAuthorizationPolicy;\n            });\n            cap.UseInMemoryStorage();\n            cap.UseInMemoryMessageQueue();\n        });\n\n        return services;\n    }\n\n    private IServiceCollection AddCapWithAnonymousAccess(IServiceCollection services)\n    {\n        services.AddCap(cap =>\n        {\n            cap.UseDashboard(d =>\n            {\n                d.AllowAnonymousExplicit = true;\n            });\n            cap.UseInMemoryStorage();\n            cap.UseInMemoryMessageQueue();\n        });\n\n        return services;\n    }\n}"
  },
  {
    "path": "samples/Sample.Dashboard.Auth/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n  \"AllowedHosts\": \"*\",\n  \"ConnectionStrings\": {\n    \"Postgres\": \"Server=127.0.0.1;Port=5432;Database=cap;Uid=postgres;Pwd=root;Include Error Detail=true;\"\n  }\n}\n"
  },
  {
    "path": "samples/Sample.Dashboard.Jwt/Data/User.cs",
    "content": "﻿namespace Sample.Dashboard.Jwt.Data\n{\n    public class User\n    {\n        public string UserName { get; set; } = string.Empty;\n        public string Password { get; set; } = string.Empty;\n    }\n}\n"
  },
  {
    "path": "samples/Sample.Dashboard.Jwt/Dockerfile",
    "content": "FROM mcr.microsoft.com/dotnet/aspnet:6.0\nWORKDIR /app\nCOPY . ./\nENTRYPOINT [\"dotnet\", \"Sample.Dashboard.Jwt.dll\"]"
  },
  {
    "path": "samples/Sample.Dashboard.Jwt/Program.cs",
    "content": "using System.IdentityModel.Tokens.Jwt;\nusing System.Security.Claims;\nusing System.Text;\nusing Microsoft.AspNetCore.Authentication.JwtBearer;\nusing Microsoft.AspNetCore.Authorization;\nusing Microsoft.IdentityModel.Tokens;\nusing Sample.Dashboard.Jwt.Data;\n\nvar builder = WebApplication.CreateBuilder(args);\n\nbuilder.Logging.ClearProviders();\nbuilder.Logging.AddConsole();\n\n// Add services to the container.\nbuilder.Services.AddRazorPages();\n\nvar key = Encoding.UTF8.GetBytes(builder.Configuration[\"Jwt:Key\"]!);\nbuilder.Services.AddAuthentication(options =>\n    {\n        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;\n        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;\n    })\n    .AddJwtBearer(options =>\n    {\n        options.RequireHttpsMetadata = false;\n        options.SaveToken = true;\n        options.TokenValidationParameters = new TokenValidationParameters\n        {\n            ValidateIssuerSigningKey = true,\n            IssuerSigningKey = new SymmetricSecurityKey(key),\n            ValidateIssuer = false,\n            ValidateAudience = false,\n            ValidateLifetime = true,\n            RequireExpirationTime = true,\n            ClockSkew = TimeSpan.Zero,\n        };\n        options.Events = new JwtBearerEvents\n        {\n            OnMessageReceived = context =>\n            {\n                if (context.Request.Query.ContainsKey(\"access_token\"))\n                {\n                    context.Token = context.Request.Query[\"access_token\"];\n                }\n\n                return Task.CompletedTask;\n            }\n        };\n    });\nbuilder.Services.AddAuthorization();\n\nbuilder.Services.AddCapDashboardStandalone();\n\nvar app = builder.Build();\n\napp.UseHttpsRedirection();\napp.UseStaticFiles();\n\napp.UseRouting();\n\napp.MapGet(\"/\", () => Results.LocalRedirect(\"/index.html\", true));\n\napp.MapPost(\"/security/createToken\",\n    [AllowAnonymous] (User user) =>\n    {\n        if (user is { UserName: \"bob\", Password: \"bob\" })\n        {\n            var tokenDescriptor = new SecurityTokenDescriptor\n            {\n                Subject = new ClaimsIdentity(new[]\n                {\n                    new Claim(\"Id\", Guid.NewGuid().ToString()),\n                    new Claim(JwtRegisteredClaimNames.Sub, user.UserName),\n                    new Claim(JwtRegisteredClaimNames.Email, user.UserName),\n                    new Claim(JwtRegisteredClaimNames.Jti,\n                        Guid.NewGuid().ToString())\n                }),\n                Expires = DateTime.UtcNow.AddMinutes(60),\n                Issuer = \"Test\",\n                Audience = \"Test\",\n                SigningCredentials = new SigningCredentials\n                (new SymmetricSecurityKey(key),\n                    SecurityAlgorithms.HmacSha512Signature)\n            };\n            var tokenHandler = new JwtSecurityTokenHandler();\n            var token = tokenHandler.CreateToken(tokenDescriptor);\n            var stringToken = tokenHandler.WriteToken(token);\n            return Results.Ok(stringToken);\n        }\n        return Results.Unauthorized();\n    });\n\napp.UseAuthentication();\napp.UseAuthorization();\n\napp.Run();\n"
  },
  {
    "path": "samples/Sample.Dashboard.Jwt/Sample.Dashboard.Jwt.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n    <PropertyGroup>\n        <TargetFramework>net10.0</TargetFramework>\n        <Nullable>enable</Nullable>\n        <ImplicitUsings>enable</ImplicitUsings>\n        <UserSecretsId>aspnet-Sample.Dashboard.Jwt-6f791f0f-707a-4e40-b28d-5b0262404cfd</UserSecretsId>\n    </PropertyGroup>\n\n    <ItemGroup>\n        <PackageReference Include=\"Invio.Extensions.Authentication.JwtBearer\" Version=\"2.0.1\" />\n        <PackageReference Include=\"Microsoft.AspNetCore.Authentication.JwtBearer\" Version=\"10.0.0\" />\n    </ItemGroup>\n\n    <ItemGroup>\n      <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.Dashboard.K8s\\DotNetCore.CAP.Dashboard.K8s.csproj\" />\n    </ItemGroup>\n\n    <ItemGroup>\n      <None Update=\"Dockerfile\">\n        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n      </None>\n    </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "samples/Sample.Dashboard.Jwt/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Information\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n  \"AllowedHosts\": \"*\",\n  \"ConnectionStrings\": {\n    \"Postgres\": \"Server=127.0.0.1;Port=5432;Database=cap;Uid=postgres;Pwd=root;Include Error Detail=true;\"\n  },\n  \"Jwt\": {\n    \"Key\": \"4smA55penihm9oNNxjou7hyy9CrMrNk3\"\n  }\n}\n"
  },
  {
    "path": "samples/Sample.Dashboard.Jwt/wwwroot/css/site.css",
    "content": "html {\n  font-size: 14px;\n}\n\n@media (min-width: 768px) {\n  html {\n    font-size: 16px;\n  }\n}\n\nhtml {\n  position: relative;\n  min-height: 100%;\n}\n\nbody {\n  margin-bottom: 60px;\n}"
  },
  {
    "path": "samples/Sample.Dashboard.Jwt/wwwroot/index.html",
    "content": "﻿<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n  <title>CAP Dashboard - Log In</title>\n  <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css\" />\n  <link rel=\"stylesheet\" href=\"/css/site.css\" />\n</head>\n<body>\n  <div class=\"container\">\n    <main role=\"main\" class=\"pb-3\">\n      <div class=\"col-sm-5\">\n        <h1 class=\"display-4\">Log In</h1>\n        <div class=\"row mb-3\">\n          <label for=\"userName\" class=\"col-sm-2 col-form-label\">Name</label>\n          <div class=\"col-sm-10\">\n            <input type=\"text\" class=\"form-control\" id=\"userName\">\n          </div>\n        </div>\n        <div class=\"row mb-3\">\n          <label for=\"password\" class=\"col-sm-2 col-form-label\">Password</label>\n          <div class=\"col-sm-10\">\n            <input type=\"password\" id=\"password\" class=\"form-control\">\n          </div>\n        </div>\n        <p>Default credentials: bob/bob</p>\n        <div class=\"col-12\">\n          <button class=\"btn btn-light\" onclick=\"logIn()\">Log In</button>\n        </div>\n      </div>\n    </main>\n  </div>\n\n  <script src=\"https://code.jquery.com/jquery-3.6.4.min.js\"></script>\n  <script src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js\"></script>\n  <script src=\"/js/site.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "samples/Sample.Dashboard.Jwt/wwwroot/js/site.js",
    "content": "﻿// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification\n// for details on configuring this project to bundle and minify static web assets.\n\n// Write your JavaScript code.\n\nfunction logIn() {\n  const userName = $('#userName').val();\n  const password = $('#password').val();\n  $.ajax({\n    method: \"POST\",\n    url: \"security/createToken\",\n    data: JSON.stringify({ userName, password }),\n    contentType: \"application/json; charset=utf-8\",\n    dataType: \"json\"\n  })\n    .done(token => {\n      window.open(`/cap/index.html?access_token=${token}`, '_blank')\n    });\n}"
  },
  {
    "path": "samples/Sample.Kafka.PostgreSql/AppDbContext.cs",
    "content": "﻿using System.Data.Common;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.Extensions.DependencyInjection;\nusing Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal;\n\nnamespace Sample.Kafka.PostgreSql\n{\n    public class Person\n    {\n        public int Id { get; set; }\n\n        public string Name { get; set; }\n\n        public int Age { get; set; }\n\n        public override string ToString()\n        {\n            return $\"Name:{Name}, Age:{Age}\";\n        }\n    }\n\n    public class AppDbContext : DbContext\n    {\n        public AppDbContext(DbContextOptions<AppDbContext> options)\n        : base(options)\n        {\n        }\n\n        public DbSet<Person> Persons { get; set; }\n    }\n\n#pragma warning disable EF1001 // Internal EF Core API usage.\n\n    public class CapNpgsqlRelationalConnection : NpgsqlRelationalConnection\n    {\n        private readonly ICapPublisher _cap;\n\n        protected CapNpgsqlRelationalConnection(RelationalConnectionDependencies dependencies, DbDataSource dataSource) : base(dependencies, dataSource)\n        {\n            _cap = dependencies.CurrentContext.Context.GetService<ICapPublisher>();\n        }\n\n#pragma warning restore EF1001\n\n        public override void CommitTransaction()\n        {\n            if (_cap.Transaction != null)\n            {\n                _cap.Transaction.Commit();\n            }\n            else\n            {\n                base.CommitTransaction();\n            }\n        }\n\n        public override Task CommitTransactionAsync(CancellationToken cancellationToken = default)\n        {\n            if (_cap.Transaction != null)\n            {\n                return _cap.Transaction.CommitAsync(cancellationToken);\n            }\n            else\n            {\n                return base.CommitTransactionAsync(cancellationToken);\n            }\n        }\n\n        public override void RollbackTransaction()\n        {\n            if (_cap.Transaction != null)\n            {\n                _cap.Transaction.Rollback();\n            }\n            else\n            {\n                base.RollbackTransaction();\n            }\n        }\n\n        public override Task RollbackTransactionAsync(CancellationToken cancellationToken = default)\n        {\n            if (_cap.Transaction != null)\n            {\n                return _cap.Transaction.RollbackAsync(cancellationToken);\n            }\n            else\n            {\n                return base.RollbackTransactionAsync(cancellationToken);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "samples/Sample.Kafka.PostgreSql/Controllers/ValuesController.cs",
    "content": "﻿using System;\nusing System.Data;\nusing System.Threading.Tasks;\nusing Dapper;\nusing DotNetCore.CAP;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.EntityFrameworkCore;\nusing Npgsql;\n\nnamespace Sample.Kafka.PostgreSql.Controllers\n{\n    [Route(\"api/[controller]\")]\n    public class ValuesController(ICapPublisher producer) : Controller, ICapSubscribe\n    {\n        [Route(\"~/control/start\")]\n        public async Task<IActionResult> Start([FromServices] IBootstrapper bootstrapper)\n        {\n            await bootstrapper.BootstrapAsync();\n            return Ok();\n        }\n\n        [Route(\"~/control/stop\")]\n        public async Task<IActionResult> Stop([FromServices] IBootstrapper bootstrapper)\n        {\n            await bootstrapper.DisposeAsync();\n            return Ok();\n        }\n\n\n        [Route(\"~/delay/{delaySeconds:int}\")]\n        public async Task<IActionResult> Delay(int delaySeconds)\n        {\n            await producer.PublishDelayAsync(TimeSpan.FromSeconds(delaySeconds), \"sample.kafka.postgrsql\", DateTime.Now);\n\n            return Ok();\n        }\n\n\n        [Route(\"~/without/transaction\")]\n        public async Task<IActionResult> WithoutTransaction()\n        {\n            await producer.PublishAsync(\"sample.kafka.postgrsql\", DateTime.Now);\n\n            return Ok();\n        }\n\n        [Route(\"~/adonet/transaction\")]\n        public IActionResult AdonetWithTransaction()\n        {\n            using (var connection = new NpgsqlConnection(AppConstants.DbConnectionString))\n            {\n                using (var transaction = connection.BeginTransaction(producer, autoCommit: false))\n                {\n                    //your business code\n                    connection.Execute(\"INSERT INTO \\\"Persons\\\"(\\\"Name\\\",\\\"Age\\\",\\\"CreateTime\\\") VALUES('Lucy',25, NOW())\", transaction: (IDbTransaction)transaction.DbTransaction);\n\n                    producer.Publish(\"sample.kafka.postgrsql\", DateTime.Now);\n\n                    transaction.Commit();\n                }\n            }\n\n            producer.Publish(\"sample.kafka.postgrsql\", DateTime.Now);\n\n            return Ok();\n        }\n\n        [Route(\"~/ef/transaction\")]\n        public IActionResult EntityFrameworkWithTransaction([FromServices] AppDbContext dbContext)\n        {\n            using (dbContext.Database.BeginTransaction(producer, false))\n            {\n                dbContext.Persons.Add(new Person() { Name = \"ef.transaction\", Age = 11 });\n\n                dbContext.SaveChanges();\n\n                producer.Publish(\"sample.kafka.postgrsql\", DateTime.UtcNow);\n\n                dbContext.Database.CommitTransaction();\n            }\n            return Ok();\n        }\n\n\n        [CapSubscribe(\"sample.kafka.postgrsql\")]\n        public void Test2(DateTime value)\n        {\n            Console.WriteLine(\"Subscriber output message: \" + value);\n        }\n    }\n}"
  },
  {
    "path": "samples/Sample.Kafka.PostgreSql/Program.cs",
    "content": "﻿using Microsoft.AspNetCore.Builder;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.Extensions.DependencyInjection;\nusing Sample.Kafka.PostgreSql;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// Configure services\nbuilder.Services.AddDbContext<AppDbContext>((sp, opt) =>\n{\n    opt.UseNpgsql(AppConstants.DbConnectionString)\n        .ReplaceService<IRelationalConnection, CapNpgsqlRelationalConnection>();\n});\n\nbuilder.Services.AddCap(x =>\n{\n    //x.UseEntityFramework<AppDbContext>();\n    //docker run --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword -d postgres\n    x.UsePostgreSql(AppConstants.DbConnectionString);\n\n    /* //Run Kafka Docker Container (Powershell)\n    docker run -d `\n        --name kafka `\n        -p 9092:9092 `\n        -e KAFKA_NODE_ID=1 `\n        -e KAFKA_PROCESS_ROLES=broker,controller `\n        -e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092,CONTROLLER://:9093 `\n        -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://127.0.0.1:9092 `\n        -e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER `\n        -e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT `\n        -e KAFKA_CONTROLLER_QUORUM_VOTERS=1@localhost:9093 `\n        -e KAFKA_LOG_DIRS=/var/lib/kafka/data `\n        -e KAFKA_AUTO_CREATE_TOPICS_ENABLE=true `\n        -e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 `\n        -e KAFKA_OFFSETS_TOPIC_MIN_ISR=1 `\n        -e KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=1 `\n        -e KAFKA_TRANSACTION_STATE_LOG_MIN_ISR=1 `\n        apache/kafka:3.7.0\n    */\n    x.UseKafka(\"127.0.0.1:9092\");\n    x.UseDashboard();\n});\n\nbuilder.Services.AddControllers();\n\nvar app = builder.Build();\n\n// Configure middleware pipeline\napp.UseRouting();\napp.MapControllers();\n\napp.Run();\n\npublic static class AppConstants\n{\n    public const string DbConnectionString = \"User ID=postgres;Password=mysecretpassword;Host=127.0.0.1;Port=5432;Database=postgres;\";\n}"
  },
  {
    "path": "samples/Sample.Kafka.PostgreSql/Sample.Kafka.PostgreSql.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <WarningsAsErrors>NU1701</WarningsAsErrors>\n    <NoWarn>NU1701</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Dapper\" Version=\"2.1.66\" />\n    <PackageReference Include=\"Npgsql.EntityFrameworkCore.PostgreSQL\" Version=\"9.0.4\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.Dashboard\\DotNetCore.CAP.Dashboard.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.Kafka\\DotNetCore.CAP.Kafka.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.PostgreSql\\DotNetCore.CAP.PostgreSql.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n  </ItemGroup> \n\n</Project>\n"
  },
  {
    "path": "samples/Sample.Kafka.PostgreSql/appsettings.json",
    "content": "﻿{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Warning\",\n      \"DotNetCore.CAP\": \"Debug\"\n    }\n  }\n}\n"
  },
  {
    "path": "samples/Sample.Pulsar.InMemory/Controllers/ValuesController.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace Sample.Pulsar.InMemory.Controllers\n{\n    [Route(\"api/[controller]\")]\n    public class ValuesController : Controller, ICapSubscribe\n    {\n        private readonly ICapPublisher _capBus;\n\n        public ValuesController(ICapPublisher producer)\n        {\n            _capBus = producer;\n        }\n\n        [Route(\"~/without/transaction\")]\n        public async Task<IActionResult> WithoutTransaction()\n        {\n            await _capBus.PublishAsync(\"persistent://public/default/captesttopic\", DateTime.Now);\n\n            return Ok();\n        }\n\n        [CapSubscribe(\"persistent://public/default/captesttopic\")]\n        public void Test2T2(string value)\n        {\n            Console.WriteLine(\"Subscriber output message: \" + value);\n        }\n    }\n}"
  },
  {
    "path": "samples/Sample.Pulsar.InMemory/Program.cs",
    "content": "﻿using Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// Configure services\nstring pulsarUri = builder.Configuration.GetValue(\"AppSettings:PulsarUri\", \"pulsar://localhost:6650\");\n\nbuilder.Services.AddCap(x =>\n{\n    x.UseInMemoryStorage();\n    x.UsePulsar(pulsarUri);\n    x.UseDashboard();\n});\n\nbuilder.Services.AddControllers();\n\nvar app = builder.Build();\n\n// Configure middleware pipeline\napp.UseRouting();\napp.MapControllers();\n\napp.Run();"
  },
  {
    "path": "samples/Sample.Pulsar.InMemory/Sample.Pulsar.InMemory.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n\t<PropertyGroup>\n\t\t<TargetFramework>net10.0</TargetFramework>\n\t</PropertyGroup>\n\n\t<ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.Dashboard\\DotNetCore.CAP.Dashboard.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.InMemoryStorage\\DotNetCore.CAP.InMemoryStorage.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.Pulsar\\DotNetCore.CAP.Pulsar.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n  </ItemGroup> \n\n</Project>\n"
  },
  {
    "path": "samples/Sample.Pulsar.InMemory/appsettings.json",
    "content": "﻿{\n  \"Logging\": {\n    \"IncludeScopes\": false,\n    \"LogLevel\": {\n      \"Default\": \"Debug\"\n    }\n  },\n  \"AppSettings\": {\n    \"PulsarUri\": \"pulsar://localhost:6650\",\n    \"PulsarTopic\": \"persistent://public/default/captesttopic\"\n  }\n}\n"
  },
  {
    "path": "samples/Sample.RabbitMQ.MongoDB/Controllers/ValuesController.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP;\nusing Microsoft.AspNetCore.Mvc;\nusing MongoDB.Bson;\nusing MongoDB.Driver;\n\nnamespace Sample.RabbitMQ.MongoDB.Controllers\n{\n    [Route(\"api/[controller]\")]\n    [ApiController]\n    public class ValuesController : ControllerBase\n    {\n        private readonly IMongoClient _client;\n        private readonly ICapPublisher _capBus;\n\n        public ValuesController(IMongoClient client, ICapPublisher capBus)\n        {\n            _client = client;\n            _capBus = capBus;\n        }\n\n        [Route(\"~/without/transaction\")]\n        public IActionResult WithoutTransaction()\n        {\n            _capBus.PublishAsync(\"sample.rabbitmq.mongodb\", DateTime.Now);\n\n            return Ok();\n        }\n\n\n        [Route(\"~/delay/{delaySeconds:int}\")]\n        public async Task<IActionResult> Delay(int delaySeconds)\n        {\n            await _capBus.PublishDelayAsync(TimeSpan.FromSeconds(delaySeconds), \"sample.rabbitmq.mongodb\", DateTime.Now);\n\n            return Ok();\n        }\n\n        [Route(\"~/transaction/not/autocommit\")]\n        public IActionResult PublishNotAutoCommit()\n        {\n            //NOTE: before your test, your need to create database and collection at first\n            //注意：MongoDB 不能在事务中创建数据库和集合，所以你需要单独创建它们，模拟一条记录插入则会自动创建\n            //var mycollection = _client.GetDatabase(\"test\").GetCollection<BsonDocument>(\"test.collection\");\n            //mycollection.InsertOne(new BsonDocument { { \"test\", \"test\" } });\n\n            using (var session = _client.StartTransaction(_capBus, autoCommit: false))\n            {\n                var collection = _client.GetDatabase(\"test\").GetCollection<BsonDocument>(\"test.collection\");\n                collection.InsertOne(session, new BsonDocument { { \"hello\", \"world\" } });\n\n                _capBus.Publish(\"sample.rabbitmq.mongodb\", DateTime.Now);\n\n                session.CommitTransaction();\n            }\n            return Ok();\n        }\n\n        [Route(\"~/transaction/autocommit\")]\n        public IActionResult PublishWithoutTrans()\n        {\n            //NOTE: before your test, your need to create database and collection at first\n            //注意：MongoDB 不能在事务中创建数据库和集合，所以你需要单独创建它们，模拟一条记录插入则会自动创建\n            //var mycollection = _client.GetDatabase(\"test\").GetCollection<BsonDocument>(\"test.collection\");\n            //mycollection.InsertOne(new BsonDocument { { \"test\", \"test\" } });\n\n            using (var session = _client.StartTransaction(_capBus, autoCommit: true))\n            {\n                var collection = _client.GetDatabase(\"test\").GetCollection<BsonDocument>(\"test.collection\");\n                collection.InsertOne(session, new BsonDocument { { \"hello\", \"world\" } });\n\n                _capBus.Publish(\"sample.rabbitmq.mongodb\", DateTime.Now);\n            }\n\n            return Ok();\n        }\n\n        [NonAction]\n        [CapSubscribe(\"sample.rabbitmq.mongodb\")]\n        public void ReceiveMessage(DateTime time)\n        {\n            Console.WriteLine($@\"{DateTime.Now}, Subscriber invoked, Sent time:{time}\");\n        }\n    }\n}\n"
  },
  {
    "path": "samples/Sample.RabbitMQ.MongoDB/Program.cs",
    "content": "﻿using Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing MongoDB.Driver;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// Configure services\nbuilder.Services.AddSingleton<IMongoClient>(new MongoClient(builder.Configuration.GetConnectionString(\"MongoDB\")));\n\nbuilder.Services.AddCap(x =>\n{\n    x.UseMongoDB(builder.Configuration.GetConnectionString(\"MongoDB\"));\n    x.UseRabbitMQ(\"\");\n    x.UseDashboard();\n});\n\nbuilder.Services.AddControllers();\n\nvar app = builder.Build();\n\n// Configure middleware pipeline\napp.UseRouting();\napp.MapControllers();\n\napp.Run();\n"
  },
  {
    "path": "samples/Sample.RabbitMQ.MongoDB/Sample.RabbitMQ.MongoDB.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.Dashboard\\DotNetCore.CAP.Dashboard.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.RabbitMQ\\DotNetCore.CAP.RabbitMQ.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.MongoDB\\DotNetCore.CAP.MongoDB.csproj\" />\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "samples/Sample.RabbitMQ.MongoDB/appsettings.json",
    "content": "{\r\n  \"Logging\": {\r\n    \"LogLevel\": {\r\n      \"Default\": \"Debug\"\r\n    }\r\n  },\r\n  \"AllowedHosts\": \"*\",\r\n  \"ConnectionStrings\": {\r\n    \"MongoDB\": \"mongodb://192.168.2.120:27017,192.168.2.120:27018,192.168.2.120:27019/?replicaSet=rs0\"\r\n  },\r\n  \"RabbitMQ\": {\r\n    \"HostName\": \"localhost\",\r\n    \"Port\": 5672,\r\n    \"UserName\": \"\",\r\n    \"Password\": \"\"\r\n  }\r\n} \r\n"
  },
  {
    "path": "samples/Sample.RabbitMQ.MongoDB/docker-compose.yml",
    "content": "version: \"3.9\"\nservices:\n  \n  mongodb:\n    hostname: cap-mongodb\n    container_name: cap-mongodb\n    image: mongo:latest\n    environment:\n      MONGO_INITDB_DATABASE: test\n      MONGO_REPLICA_SET_NAME: rs0\n    volumes:\n      - ./mongo-initdb.d:/docker-entrypoint-initdb.d\n    expose:\n      - 27017\n    ports:\n      - \"27017:27017\"\n    healthcheck:\n      test: test $$(echo \"rs.initiate().ok || rs.slaveOk().ok || rs.status().ok\" | mongo --quiet) -eq 1\n      interval: 10s\n      start_period: 30s\n    entrypoint: [ \"/usr/bin/mongod\", \"--bind_ip_all\", \"--replSet\", \"rs0\" ]\n    networks:\n      - cap-net\n  \n  rabbitmq:\n    image: rabbitmq:latest\n    container_name: cap-rabbitmq\n    ports:\n      - 5672:5672\n      - 15672:15672\n    volumes:\n      - ~/.docker-conf/rabbitmq/data/:/var/lib/rabbitmq/\n      - ~/.docker-conf/rabbitmq/log/:/var/log/rabbitmq\n    networks:\n      - cap-net\n\nnetworks:\n  cap-net:\n    name: cap-net\n    driver: bridge\n  "
  },
  {
    "path": "samples/Sample.RabbitMQ.MySql/AppDbContext.cs",
    "content": "﻿using Microsoft.EntityFrameworkCore;\n\nnamespace Sample.RabbitMQ.MySql\n{\n    public class Person\n    {\n        public int Id { get; set; }\n\n        public string Name { get; set; }\n\n        public int Age { get; set; }\n\n        public override string ToString()\n        {\n            return $\"Name:{Name}, Age:{Age}\";\n        }\n    }\n\n    public class AppDbContext : DbContext\n    {\n        public const string ConnectionString = \"Server=127.0.0.1;Database=cap;Uid=root;Pwd=my-secret-pw;\";\n        public DbSet<Person> Persons { get; set; }\n\n        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)\n        {\n            optionsBuilder.UseMySql(ConnectionString, ServerVersion.AutoDetect(ConnectionString));\n        }\n    }\n}\n"
  },
  {
    "path": "samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs",
    "content": "﻿using System;\nusing System.Data;\nusing System.Threading.Tasks;\nusing Dapper;\nusing DotNetCore.CAP;\nusing Microsoft.AspNetCore.Mvc;\nusing MySqlConnector;\n\nnamespace Sample.RabbitMQ.MySql.Controllers\n{\n    [Route(\"api/[controller]\")]\n    public class ValuesController : Controller\n    {\n        private readonly ICapPublisher _capBus;\n\n        public ValuesController(ICapPublisher capPublisher)\n        {\n            _capBus = capPublisher;\n        }\n\n        [Route(\"~/control/start\")]\n        public async Task<IActionResult> Start([FromServices] IBootstrapper bootstrapper)\n        {\n            await bootstrapper.BootstrapAsync();\n            return Ok();\n        }\n\n        [Route(\"~/control/stop\")]\n        public async Task<IActionResult> Stop([FromServices] IBootstrapper bootstrapper)\n        {\n            await bootstrapper.DisposeAsync();\n            return Ok();\n        }\n\n        [Route(\"~/without/transaction\")]\n        public async Task<IActionResult> WithoutTransactionAsync()\n        {\n            await _capBus.PublishAsync(\"sample.rabbitmq.mysql\", DateTime.Now, cancellationToken: HttpContext.RequestAborted);\n\n            return Ok();\n        }\n\n        [Route(\"~/delay/{delaySeconds:int}\")]\n        public async Task<IActionResult> Delay(int delaySeconds)\n        {\n            await _capBus.PublishDelayAsync(TimeSpan.FromSeconds(delaySeconds), \"sample.rabbitmq.test\", $\"publish time:{DateTime.Now}, delay seconds:{delaySeconds}\");\n\n            return Ok();\n        }\n\n        [Route(\"~/adonet/transaction\")]\n        public async Task<IActionResult> AdonetWithTransaction()\n        {\n            using (var connection = new MySqlConnection(AppDbContext.ConnectionString))\n            {\n                using var transaction = await connection.BeginTransactionAsync(_capBus, true);\n                await connection.ExecuteAsync(\"insert into test(name) values('test')\", transaction: (IDbTransaction)transaction.DbTransaction);\n                await _capBus.PublishAsync(\"sample.rabbitmq.mysql\", DateTime.Now);\n            }\n\n            return Ok();\n        }\n\n        [Route(\"~/ef/transaction\")]\n        public async Task<IActionResult> EntityFrameworkWithTransaction([FromServices] AppDbContext dbContext)\n        {\n            using (var trans = await dbContext.Database.BeginTransactionAsync(_capBus, autoCommit: false))\n            {\n                await dbContext.Persons.AddAsync(new Person() { Name = \"ef.transaction\" });\n                await _capBus.PublishAsync(\"sample.rabbitmq.mysql\", DateTime.Now);\n                await dbContext.SaveChangesAsync();\n                await trans.CommitAsync();\n            }\n            return Ok();\n        }\n\n        [NonAction]\n        [CapSubscribe(\"sample.rabbitmq.mysql\")]\n        public void Subscriber(DateTime time)\n        {\n            Console.WriteLine(\"Publishing time:\" + time);\n        }\n\n        [NonAction]\n        [CapSubscribe(\"sample.rabbitmq.test\")]\n        public void Subscriber2(string message)\n        {\n            Console.WriteLine(\"Publishing message:\" + message);\n        }\n    }\n}\n"
  },
  {
    "path": "samples/Sample.RabbitMQ.MySql/Program.cs",
    "content": "﻿using Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.DependencyInjection;\nusing Sample.RabbitMQ.MySql;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// Add services to the container\nbuilder.Services.AddDbContext<AppDbContext>();\n\nbuilder.Services.AddCap(x =>\n{\n    x.UseEntityFramework<AppDbContext>();\n    x.UseRabbitMQ(\"localhost\");\n    x.UseDashboard();\n});\n\nbuilder.Services.AddControllers();\n\nvar app = builder.Build();\n\n// Configure the HTTP request pipeline\napp.UseRouting();\napp.MapControllers();\n\napp.Run();\n"
  },
  {
    "path": "samples/Sample.RabbitMQ.MySql/Sample.RabbitMQ.MySql.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n\t<PropertyGroup>\n\t\t<TargetFramework>net8.0</TargetFramework>\n\t</PropertyGroup>\n\n\t<ItemGroup>\n\t\t<PackageReference Include=\"Dapper\" Version=\"2.1.66\" />\n\t\t<PackageReference Include=\"Microsoft.AspNetCore.Authentication.JwtBearer\" Version=\"8.0.18\" />\n\t\t<PackageReference Include=\"Pomelo.EntityFrameworkCore.MySql\" Version=\"9.0.0\" />\n\t</ItemGroup>\n\t<ItemGroup>\n\t\t<ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.Dashboard.K8s\\DotNetCore.CAP.Dashboard.K8s.csproj\" />\n\t\t<ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.Dashboard\\DotNetCore.CAP.Dashboard.csproj\" />\n\t\t<ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.MySql\\DotNetCore.CAP.MySql.csproj\" />\n\t\t<ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.RabbitMQ\\DotNetCore.CAP.RabbitMQ.csproj\" />\n\t\t<ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n\t</ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "samples/Sample.RabbitMQ.MySql/appsettings.json",
    "content": "﻿{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"DotNetCore.CAP\": \"Debug\",\n      \"Microsoft.AspNetCore.Hosting.Diagnostics\": \"Warning\",\n      \"Microsoft.AspNetCore.Routing\": \"Warning\"\n    }\n  }\n}\n"
  },
  {
    "path": "samples/Sample.RabbitMQ.SqlServer/AppDbContext.cs",
    "content": "﻿using Microsoft.EntityFrameworkCore;\n\nnamespace Sample.RabbitMQ.SqlServer\n{\n    public class Person\n    {\n        public int Id { get; set; }\n\n        public string Name { get; set; }\n\n        public int Age { get; set; }\n\n        public override string ToString()\n        {\n            return $\"Name:{Name}, Age:{Age}\";\n        }\n    }\n\n    public class AppDbContext : DbContext\n    {\n        public const string ConnectionString = \"Server=127.0.0.1;Database=tempdb;User Id=sa;Password=yourStrong(!)Password;TrustServerCertificate=True\";\n\n        public DbSet<Person> Persons { get; set; }\n\n        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)\n        {\n            optionsBuilder.UseSqlServer(ConnectionString);\n        }\n    }\n}\n"
  },
  {
    "path": "samples/Sample.RabbitMQ.SqlServer/Controllers/ValuesController.cs",
    "content": "﻿using System;\nusing System.Data.Common;\nusing System.Threading.Tasks;\nusing Dapper;\nusing DotNetCore.CAP;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Data.SqlClient;\nusing NameGenerator.Generators;\nusing Sample.RabbitMQ.SqlServer.Messages;\n\nnamespace Sample.RabbitMQ.SqlServer.Controllers\n{\n    [Route(\"api/[controller]\")]\n    public class ValuesController : Controller\n    {\n        private readonly ICapPublisher _capBus;\n\n        public ValuesController(ICapPublisher capPublisher)\n        {\n            _capBus = capPublisher;\n        }\n\n        [Route(\"~/control/start\")]\n        public async Task<IActionResult> Start([FromServices] IBootstrapper bootstrapper)\n        {\n            await bootstrapper.BootstrapAsync();\n            return Ok();\n        }\n\n        [Route(\"~/control/stop\")]\n        public async Task<IActionResult> Stop([FromServices] IBootstrapper bootstrapper)\n        {\n            await bootstrapper.DisposeAsync();\n            return Ok();\n        }\n\n        [Route(\"~/without/transaction\")]\n        public async Task<IActionResult> WithoutTransaction()\n        {\n            await _capBus.PublishAsync(\"sample.rabbitmq.sqlserver\", new Person()\n            {\n                Id = 123,\n                Name = \"Bar\"\n            });\n\n            return Ok();\n        }\n\n        [Route(\"~/delay/{delaySeconds:int}\")]\n        public async Task<IActionResult> Delay(int delaySeconds)\n        {\n            await _capBus.PublishDelayAsync(TimeSpan.FromSeconds(delaySeconds), \"sample.rabbitmq.sqlserver\",\n                new Person()\n                {\n                    Id = 123,\n                    Name = \"Bar\"\n                });\n\n            return Ok();\n        }\n\n        [Route(\"~/delay/transaction/{delaySeconds:int}\")]\n        public async Task<IActionResult> DelayWithTransaction(int delaySeconds)\n        {\n            using (var connection = new SqlConnection(AppDbContext.ConnectionString))\n            {\n                using (var transaction = connection.BeginTransaction(_capBus, true))\n                {\n                    //your business code\n                    connection.Execute(\"INSERT INTO Persons(Name,Age,CreateTime) VALUES(@Name,@Age, GETDATE())\", new\n                    {\n                        Name = new RealNameGenerator().Generate(),\n                        Age = Random.Shared.Next(10, 99),\n                    }, transaction: transaction);\n\n                    await _capBus.PublishDelayAsync(TimeSpan.FromSeconds(delaySeconds), \"sample.rabbitmq.sqlserver\",\n                        new Person()\n                        {\n                            Id = 123,\n                            Name = \"Bar\"\n                        });\n                }\n            }\n\n            return Ok();\n        }\n\n        [Route(\"~/adonet/transaction\")]\n        public async Task<IActionResult> AdonetWithTransaction()\n        {\n            var person = new Person\n            {\n                Name = new RealNameGenerator().Generate(),\n                Age = Random.Shared.Next(10, 99),\n            };\n\n            using (var connection = new SqlConnection(AppDbContext.ConnectionString))\n            {\n                using var transaction = await connection.BeginTransactionAsync(_capBus, false);\n\n                await _capBus.PublishAsync(\"sample.rabbitmq.sqlserver\", person);\n\n                await connection.ExecuteAsync(\"INSERT INTO Persons(Name,Age,CreateTime) VALUES(@Name,@Age, GETDATE())\",\n                      param: new { person.Name, person.Age },\n                      transaction: transaction);\n\n                await _capBus.PublishDelayAsync(TimeSpan.FromSeconds(5), \"sample.rabbitmq.sqlserver\", person);\n\n                await ((DbTransaction)transaction).CommitAsync();\n            }\n\n            person.Name = new RealNameGenerator().Generate();\n\n            await _capBus.PublishAsync(\"sample.rabbitmq.sqlserver\", person);\n\n            return Ok();\n        }\n\n        [Route(\"~/ef/transaction\")]\n        public IActionResult EntityFrameworkWithTransaction([FromServices] AppDbContext dbContext)\n        {\n            using (dbContext.Database.BeginTransaction(_capBus, autoCommit: true))\n            {\n                dbContext.Persons.Add(new Person() { Name = \"ef.transaction\" });\n                dbContext.SaveChanges();\n                _capBus.Publish(\"sample.rabbitmq.sqlserver\", new Person()\n                {\n                    Id = 123,\n                    Name = \"Bar\"\n                });\n            }\n            return Ok();\n        }\n\n        [Route(\"~/typed/subscribe\")]\n        public async Task<IActionResult> TypePublish()\n        {\n            // Add the following code to startup.cs\n            //services\n            //    .AddSingleton<IConsumerServiceSelector, TypedConsumerServiceSelector>()\n            //    .AddQueueHandlers(typeof(Startup).Assembly);\n\n            await using (var connection = new SqlConnection(AppDbContext.ConnectionString))\n            {\n                using var transaction = connection.BeginTransaction(_capBus);\n                // This is where you would do other work that is going to persist data to your database\n\n                var message = TestMessage.Create($\"This is message text created at {DateTime.Now:O}.\");\n\n                await _capBus.PublishAsync(typeof(TestMessage).FullName, message);\n                transaction.Commit();\n            }\n\n            return Content(\"ok\");\n        }\n\n        [NonAction]\n        [CapSubscribe(\"sample.rabbitmq.sqlserver\")]\n        public void Subscriber(Person p)\n        {\n            Console.WriteLine($@\"{DateTime.Now} Subscriber invoked, Info: {p}\");\n        }\n    }\n}\n"
  },
  {
    "path": "samples/Sample.RabbitMQ.SqlServer/Messages/TestMessage.cs",
    "content": "namespace Sample.RabbitMQ.SqlServer.Messages\n{\n    public class TestMessage\n    {\n        public static TestMessage Create(string text) => new()\n        {\n            Text = text\n        };\n\n        public string Text { get; private init; }\n    }\n}"
  },
  {
    "path": "samples/Sample.RabbitMQ.SqlServer/Messages/VeryFastProcessingReceiver.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Sample.RabbitMQ.SqlServer.TypedConsumers;\n\nnamespace Sample.RabbitMQ.SqlServer.Messages\n{\n    [QueueHandlerTopic(\"fasttopic\")]\n    public class VeryFastProcessingReceiver : QueueHandler\n    {\n        private readonly ILogger<VeryFastProcessingReceiver> _logger;\n\n        public VeryFastProcessingReceiver(ILogger<VeryFastProcessingReceiver> logger)\n        {\n            _logger = logger;\n        }\n\n        public async Task Handle(TestMessage value)\n        {\n            _logger.LogInformation($\"Starting FAST processing handler {DateTime.Now:O}: {value.Text}\");\n            await Task.Delay(50);\n            _logger.LogInformation($\"Ending   FAST processing handler {DateTime.Now:O}: {value.Text}\");\n        }\n    }\n}"
  },
  {
    "path": "samples/Sample.RabbitMQ.SqlServer/Messages/XSlowProcessingReceiver.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Sample.RabbitMQ.SqlServer.TypedConsumers;\n\nnamespace Sample.RabbitMQ.SqlServer.Messages\n{\n    [QueueHandlerTopic(\"slowtopic\")]\n    public class XSlowProcessingReceiver : QueueHandler\n    {\n        private readonly ILogger<XSlowProcessingReceiver> _logger;\n\n        public XSlowProcessingReceiver(ILogger<XSlowProcessingReceiver> logger)\n        {\n            _logger = logger;\n        }\n\n        public async Task Handle(TestMessage value)\n        {\n            _logger.LogInformation($\"Starting SLOW processing handler {DateTime.Now:O}: {value.Text}\");\n            await Task.Delay(10000);\n            _logger.LogInformation($\"Ending   SLOW processing handler {DateTime.Now:O}: {value.Text}\");\n        }\n    }\n}"
  },
  {
    "path": "samples/Sample.RabbitMQ.SqlServer/Migrations/20191205032949_FirstMigration.Designer.cs",
    "content": "﻿// <auto-generated />\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Migrations;\nusing Microsoft.EntityFrameworkCore.Storage.ValueConversion;\nusing Sample.RabbitMQ.SqlServer;\n\nnamespace Sample.RabbitMQ.SqlServer.Migrations\n{\n    [DbContext(typeof(AppDbContext))]\n    [Migration(\"20191205032949_FirstMigration\")]\n    partial class FirstMigration\n    {\n        protected override void BuildTargetModel(ModelBuilder modelBuilder)\n        {\n#pragma warning disable 612, 618\n            modelBuilder\n                .HasAnnotation(\"ProductVersion\", \"3.0.0\")\n                .HasAnnotation(\"Relational:MaxIdentifierLength\", 128)\n                .HasAnnotation(\"SqlServer:ValueGenerationStrategy\", SqlServerValueGenerationStrategy.IdentityColumn);\n\n            modelBuilder.Entity(\"Sample.RabbitMQ.SqlServer.Person\", b =>\n                {\n                    b.Property<int>(\"Id\")\n                        .ValueGeneratedOnAdd()\n                        .HasColumnType(\"int\")\n                        .HasAnnotation(\"SqlServer:ValueGenerationStrategy\", SqlServerValueGenerationStrategy.IdentityColumn);\n\n                    b.Property<string>(\"Name\")\n                        .HasColumnType(\"nvarchar(max)\");\n\n                    b.HasKey(\"Id\");\n\n                    b.ToTable(\"Persons\");\n                });\n#pragma warning restore 612, 618\n        }\n    }\n}\n"
  },
  {
    "path": "samples/Sample.RabbitMQ.SqlServer/Migrations/20191205032949_FirstMigration.cs",
    "content": "﻿using Microsoft.EntityFrameworkCore.Migrations;\n\nnamespace Sample.RabbitMQ.SqlServer.Migrations\n{\n    public partial class FirstMigration : Migration\n    {\n        protected override void Up(MigrationBuilder migrationBuilder)\n        {\n            migrationBuilder.CreateTable(\n                name: \"Persons\",\n                columns: table => new\n                {\n                    Id = table.Column<int>(nullable: false)\n                        .Annotation(\"SqlServer:Identity\", \"1, 1\"),\n                    Name = table.Column<string>(nullable: true)\n                },\n                constraints: table =>\n                {\n                    table.PrimaryKey(\"PK_Persons\", x => x.Id);\n                });\n        }\n\n        protected override void Down(MigrationBuilder migrationBuilder)\n        {\n            migrationBuilder.DropTable(\n                name: \"Persons\");\n        }\n    }\n}\n"
  },
  {
    "path": "samples/Sample.RabbitMQ.SqlServer/Migrations/AppDbContextModelSnapshot.cs",
    "content": "﻿// <auto-generated />\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Storage.ValueConversion;\nusing Sample.RabbitMQ.SqlServer;\n\nnamespace Sample.RabbitMQ.SqlServer.Migrations\n{\n    [DbContext(typeof(AppDbContext))]\n    partial class AppDbContextModelSnapshot : ModelSnapshot\n    {\n        protected override void BuildModel(ModelBuilder modelBuilder)\n        {\n#pragma warning disable 612, 618\n            modelBuilder\n                .HasAnnotation(\"ProductVersion\", \"3.0.0\")\n                .HasAnnotation(\"Relational:MaxIdentifierLength\", 128)\n                .HasAnnotation(\"SqlServer:ValueGenerationStrategy\", SqlServerValueGenerationStrategy.IdentityColumn);\n\n            modelBuilder.Entity(\"Sample.RabbitMQ.SqlServer.Person\", b =>\n                {\n                    b.Property<int>(\"Id\")\n                        .ValueGeneratedOnAdd()\n                        .HasColumnType(\"int\")\n                        .HasAnnotation(\"SqlServer:ValueGenerationStrategy\", SqlServerValueGenerationStrategy.IdentityColumn);\n\n                    b.Property<string>(\"Name\")\n                        .HasColumnType(\"nvarchar(max)\");\n\n                    b.HasKey(\"Id\");\n\n                    b.ToTable(\"Persons\");\n                });\n#pragma warning restore 612, 618\n        }\n    }\n}\n"
  },
  {
    "path": "samples/Sample.RabbitMQ.SqlServer/Program.cs",
    "content": "﻿using Dapper;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.Data.SqlClient;\nusing Microsoft.Extensions.DependencyInjection;\nusing Sample.RabbitMQ.SqlServer;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// Configure services\n//docker run -e \"ACCEPT_EULA=Y\" -e \"MSSQL_SA_PASSWORD=yourStrong(!)Password\" -e \"MSSQL_PID=Evaluation\" -p 1433:1433 \\\n// --name sqlpreview --hostname sqlpreview -d mcr.microsoft.com/mssql/server:2022-preview-ubuntu-22.04\nbuilder.Services.AddDbContext<AppDbContext>();\n\n//builder.Services\n//    .AddSingleton<IConsumerServiceSelector, TypedConsumerServiceSelector>()\n//    .AddQueueHandlers(typeof(Program).Assembly);\n\n// Initialize database schema\nawait using (var connection = new SqlConnection(AppDbContext.ConnectionString))\n{\n    await connection.ExecuteAsync(\"\"\"\n        IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[Persons]') AND type IN ('U'))\n        \tDROP TABLE [dbo].[Persons]\n\n        CREATE TABLE [dbo].[Persons] (\n          [Id] int  IDENTITY(1,1) NOT NULL,\n          [Name] varchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS  NULL,\n          [Age] int  NULL,\n          [CreateTime] datetime2(7) DEFAULT getdate() NULL\n        )\n        \"\"\");\n}\n\nbuilder.Services.AddCap(x =>\n{\n    x.UseEntityFramework<AppDbContext>();\n    x.UseRabbitMQ(\"127.0.0.1\");\n    x.UseDashboard();\n\n    //x.EnablePublishParallelSend = true;\n\n    //x.FailedThresholdCallback = failed =>\n    //{\n    //    var logger = failed.ServiceProvider.GetRequiredService<ILogger<Program>>();\n    //    logger.LogError($@\"A message of type {failed.MessageType} failed after executing {x.FailedRetryCount} several times, \n    //        requiring manual troubleshooting. Message name: {failed.Message.GetName()}\");\n    //};\n    //x.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);\n});\n\nbuilder.Services.AddControllers();\n\nvar app = builder.Build();\n\n// Configure middleware pipeline\napp.UseRouting();\napp.MapControllers();\n\napp.Run();\n"
  },
  {
    "path": "samples/Sample.RabbitMQ.SqlServer/Sample.RabbitMQ.SqlServer.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Dapper\" Version=\"2.1.66\" />\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.SqlServer\" Version=\"10.0.0\" />\n    <PackageReference Include=\"NameGenerator\" Version=\"2.0.4\" />\n  </ItemGroup>\n \n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.Dashboard\\DotNetCore.CAP.Dashboard.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.RabbitMQ\\DotNetCore.CAP.RabbitMQ.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.SqlServer\\DotNetCore.CAP.SqlServer.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "samples/Sample.RabbitMQ.SqlServer/TypedConsumers/QueueHandler.cs",
    "content": "namespace Sample.RabbitMQ.SqlServer.TypedConsumers\n{\n    public abstract class QueueHandler { }\n}"
  },
  {
    "path": "samples/Sample.RabbitMQ.SqlServer/TypedConsumers/QueueHandlerTopicAttribute.cs",
    "content": "using System;\n\nnamespace Sample.RabbitMQ.SqlServer.TypedConsumers\n{\n    [AttributeUsage(AttributeTargets.Class)]\n    public class QueueHandlerTopicAttribute : Attribute\n    {\n        public string Topic { get; }\n\n        public QueueHandlerTopicAttribute(string topic)\n        {\n            Topic = topic;\n        }\n    }\n}"
  },
  {
    "path": "samples/Sample.RabbitMQ.SqlServer/TypedConsumers/QueueHandlersExtensions.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Reflection;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Sample.RabbitMQ.SqlServer.TypedConsumers\n{\n    internal static class QueueHandlersExtensions\n    {\n        private static readonly Type queueHandlerType = typeof(QueueHandler);\n\n        public static IServiceCollection AddQueueHandlers(this IServiceCollection services, params Assembly[] assemblies)\n        {\n            assemblies ??= new[] { Assembly.GetEntryAssembly() };\n\n            foreach (var type in assemblies.Distinct().SelectMany(x => x.GetTypes().Where(FilterHandlers)))\n            {\n                services.AddTransient(queueHandlerType, type);\n            }\n\n            return services;\n        }\n\n        private static bool FilterHandlers(Type t)\n        {\n            var topic = t.GetCustomAttribute<QueueHandlerTopicAttribute>();\n\n            return queueHandlerType.IsAssignableFrom(t) && topic != null && t.IsClass && !t.IsAbstract;\n        }\n    }\n}"
  },
  {
    "path": "samples/Sample.RabbitMQ.SqlServer/TypedConsumers/TypedConsumerServiceSelector.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing DotNetCore.CAP;\nusing DotNetCore.CAP.Internal;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\n\nnamespace Sample.RabbitMQ.SqlServer.TypedConsumers\n{\n    internal class TypedConsumerServiceSelector : ConsumerServiceSelector\n    {\n        private readonly CapOptions _capOptions;\n\n        public TypedConsumerServiceSelector(IServiceProvider serviceProvider) : base(serviceProvider)\n        {\n            _capOptions = serviceProvider.GetRequiredService<IOptions<CapOptions>>().Value;\n        }\n\n        protected override IEnumerable<ConsumerExecutorDescriptor> FindConsumersFromInterfaceTypes(IServiceProvider provider)\n        {\n            var executorDescriptorList = new List<ConsumerExecutorDescriptor>(30);\n\n            using var scoped = provider.CreateScope();\n            var consumerServices = scoped.ServiceProvider.GetServices<QueueHandler>();\n            foreach (var service in consumerServices)\n            {\n                var typeInfo = service.GetType().GetTypeInfo();\n                if (!typeof(QueueHandler).GetTypeInfo().IsAssignableFrom(typeInfo))\n                {\n                    continue;\n                }\n\n                executorDescriptorList.AddRange(GetMyDescription(typeInfo));\n            }\n\n            return executorDescriptorList;\n        }\n\n        private IEnumerable<ConsumerExecutorDescriptor> GetMyDescription(TypeInfo typeInfo)\n        {\n            var method = typeInfo.DeclaredMethods.FirstOrDefault(x => x.Name == \"Handle\");\n            if (method == null) yield break;\n\n            var topicAttr = typeInfo.GetCustomAttributes<QueueHandlerTopicAttribute>(true);\n            var topicAttributes = topicAttr as IList<QueueHandlerTopicAttribute> ?? topicAttr.ToList();\n\n            if (topicAttributes.Count == 0) yield break;\n\n            foreach (var attr in topicAttributes)\n            {\n                var topic = attr.Topic == null\n                    ? _capOptions.DefaultGroupName + \".\" + _capOptions.Version\n                    : attr.Topic + \".\" + _capOptions.Version;\n\n                if (!string.IsNullOrEmpty(_capOptions.GroupNamePrefix))\n                {\n                    topic = $\"{_capOptions.GroupNamePrefix}.{topic}\";\n                }\n\n                var parameters = method.GetParameters().Select(p => new ParameterDescriptor\n                {\n                    Name = p.Name,\n                    ParameterType = p.ParameterType,\n                    IsFromCap = p.GetCustomAttributes(typeof(FromCapAttribute)).Any()\n                }).ToList();\n\n                var capName = parameters.FirstOrDefault(x => !x.IsFromCap)?.ParameterType.FullName;\n                if (string.IsNullOrEmpty(capName)) continue;\n\n                yield return new ConsumerExecutorDescriptor\n                {\n                    Attribute = new CapSubscribeAttribute(capName)\n                    {\n                        Group = topic\n                    },\n                    Parameters = parameters,\n                    MethodInfo = method,\n                    ImplTypeInfo = typeInfo,\n                    TopicNamePrefix = _capOptions.TopicNamePrefix,\n                    ServiceTypeInfo = typeInfo\n                };\n            }\n        }\n    }\n}"
  },
  {
    "path": "samples/Sample.RabbitMQ.SqlServer/appsettings.json",
    "content": "﻿{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "samples/Samples.Redis.SqlServer/Controllers/HomeController.cs",
    "content": "﻿using DotNetCore.CAP;\nusing DotNetCore.CAP.Messages;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Extensions.Options;\n\nnamespace Samples.Redis.SqlServer.Controllers;\n\n[ApiController]\n[Route(\"[controller]/[action]\")]\npublic class HomeController : ControllerBase\n{\n    private readonly ILogger<HomeController> _logger;\n    private readonly ICapPublisher _publisher;\n    private readonly IOptions<CapOptions> _options;\n\n    public HomeController(ILogger<HomeController> logger, ICapPublisher publisher, IOptions<CapOptions> options)\n    {\n        _logger = logger;\n        _publisher = publisher;\n        this._options = options;\n    }\n\n    [HttpGet]\n    public async Task Publish([FromQuery] string message = \"test-message\")\n    {\n        await _publisher.PublishAsync(message, new Person() { Age = 11, Name = \"James\" });\n    }\n\n    [CapSubscribe(\"test-message\")]\n    [CapSubscribe(\"test-message-1\")]\n    [CapSubscribe(\"test-message-2\")]\n    [CapSubscribe(\"test-message-3\")]\n    [NonAction]\n    public void Subscribe(Person p, [FromCap] CapHeader header)\n    {\n        _logger.LogInformation($\"{header[Headers.MessageName]} subscribed with value --> \" + p);\n    }\n\n}\n\npublic class Person\n{\n    public string Name { get; set; }\n\n    public int Age { get; set; }\n\n    public override string ToString()\n    {\n        return \"Name:\" + Name + \", Age:\" + Age;\n    }\n}\n"
  },
  {
    "path": "samples/Samples.Redis.SqlServer/Dockerfile",
    "content": "# See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.\n\n# This stage is used when running from VS in fast mode (Default for Debug configuration)\nFROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base\nUSER $APP_UID\nWORKDIR /app\nEXPOSE 80\n\n# This stage is used to build the service project\nFROM mcr.microsoft.com/dotnet/sdk:8.0 AS build\nARG BUILD_CONFIGURATION=Release\nWORKDIR /src\nCOPY [\"src/Directory.Build.props\", \"src/\"]\nCOPY [\"samples/Samples.Redis.SqlServer/Samples.Redis.SqlServer.csproj\", \"samples/Samples.Redis.SqlServer/\"]\nCOPY [\"src/DotNetCore.CAP.RedisStreams/DotNetCore.CAP.RedisStreams.csproj\", \"src/DotNetCore.CAP.RedisStreams/\"]\nCOPY [\"src/DotNetCore.CAP/DotNetCore.CAP.csproj\", \"src/DotNetCore.CAP/\"]\nCOPY [\"src/DotNetCore.CAP.SqlServer/DotNetCore.CAP.SqlServer.csproj\", \"src/DotNetCore.CAP.SqlServer/\"]\nRUN dotnet restore \"./samples/Samples.Redis.SqlServer/Samples.Redis.SqlServer.csproj\"\nCOPY . .\nWORKDIR \"/src/samples/Samples.Redis.SqlServer\"\nRUN dotnet build \"./Samples.Redis.SqlServer.csproj\" -c $BUILD_CONFIGURATION -o /app/build\n\n# This stage is used to publish the service project to be copied to the final stage\nFROM build AS publish\nARG BUILD_CONFIGURATION=Release\nRUN dotnet publish \"./Samples.Redis.SqlServer.csproj\" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false\n\n# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration)\nFROM base AS final\nWORKDIR /app\nCOPY --from=publish /app/publish .\nENTRYPOINT [\"dotnet\", \"Samples.Redis.SqlServer.dll\"]"
  },
  {
    "path": "samples/Samples.Redis.SqlServer/Program.cs",
    "content": "\nusing StackExchange.Redis;\n\nvar builder = WebApplication.CreateBuilder(args);\n\nbuilder.Services\n    .AddControllers();\n\nbuilder.Services\n    .AddEndpointsApiExplorer();\nbuilder.Services\n    .AddSwaggerGen();\n\nbuilder.Services\n    .AddCap(options =>\n    {\n        options.UseRedis(redis =>\n        {\n            redis.Configuration = ConfigurationOptions.Parse(\"redis-node-0:6379,password=cap\");\n            redis.OnConsumeError = context =>\n            {\n                throw new InvalidOperationException(\"\");\n            };\n        });\n\n        options.UseSqlServer(\"Server=db;Database=master;User=sa;Password=P@ssw0rd;Encrypt=False\");\n\n        options.UseDashboard();\n\n    });\n\nvar app = builder.Build();\n\nif (app.Environment.IsDevelopment())\n{\n    app.UseSwagger();\n    app.UseSwaggerUI();\n}\n\napp.UseHttpsRedirection();\n\napp.UseAuthorization();\n\napp.MapControllers();\n\napp.Run();\n"
  },
  {
    "path": "samples/Samples.Redis.SqlServer/Samples.Redis.SqlServer.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\t<PropertyGroup>\n\t\t<TargetFramework>net10.0</TargetFramework>\n\t\t<UserSecretsId>eb622624-fbc4-46d0-b006-dfe8e66df5bb</UserSecretsId>\n\t\t<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>\n\t\t<ImplicitUsings>enable</ImplicitUsings>\n\t\t<DockerfileContext>..\\..</DockerfileContext>\n\t\t<DockerComposeProjectPath>..\\..\\docker-compose.dcproj</DockerComposeProjectPath>\n\t</PropertyGroup>\n\t<ItemGroup>\n\t\t<PackageReference Include=\"Microsoft.VisualStudio.Azure.Containers.Tools.Targets\" Version=\"1.22.1\" />\n\t\t<PackageReference Include=\"Swashbuckle.AspNetCore\" Version=\"10.0.1\" />\n\t</ItemGroup>\n\t<ItemGroup>\n\t\t<ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.Dashboard\\DotNetCore.CAP.Dashboard.csproj\" />\n\t\t<ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.RedisStreams\\DotNetCore.CAP.RedisStreams.csproj\" />\n\t\t<ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.SqlServer\\DotNetCore.CAP.SqlServer.csproj\" />\n\t</ItemGroup>\n</Project>"
  },
  {
    "path": "samples/Samples.Redis.SqlServer/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n  \"AllowedHosts\": \"*\"  \n}\n"
  },
  {
    "path": "samples/Samples.Redis.SqlServer/docker-compose.yml",
    "content": "services:\n  redis-node-0:\n    image: docker.io/bitnami/redis-cluster:7.0\n    volumes:\n      - redis-cluster_data-0:/bitnami/redis/data\n    environment:\n      - 'REDIS_PASSWORD=cap'\n      - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'\n\n  redis-node-1:\n    image: docker.io/bitnami/redis-cluster:7.0\n    volumes:\n      - redis-cluster_data-1:/bitnami/redis/data\n    environment:\n      - 'REDIS_PASSWORD=cap'\n      - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'\n\n  redis-node-2:\n    image: docker.io/bitnami/redis-cluster:7.0\n    volumes:\n      - redis-cluster_data-2:/bitnami/redis/data\n    environment:\n      - 'REDIS_PASSWORD=cap'\n      - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'\n\n  redis-node-3:\n    image: docker.io/bitnami/redis-cluster:7.0\n    volumes:\n      - redis-cluster_data-3:/bitnami/redis/data\n    environment:\n      - 'REDIS_PASSWORD=cap'\n      - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'\n\n  redis-node-4:\n    image: docker.io/bitnami/redis-cluster:7.0\n    volumes:\n      - redis-cluster_data-4:/bitnami/redis/data\n    environment:\n      - 'REDIS_PASSWORD=cap'\n      - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'\n\n  redis-node-5:\n    image: docker.io/bitnami/redis-cluster:7.0\n    ports:\n     - 6379:6379\n    volumes:\n      - redis-cluster_data-5:/bitnami/redis/data\n    depends_on:\n      - redis-node-0\n      - redis-node-1\n      - redis-node-2\n      - redis-node-3\n      - redis-node-4\n    environment:\n      - 'REDIS_PASSWORD=cap'\n      - 'REDISCLI_AUTH=cap'\n      - 'REDIS_CLUSTER_REPLICAS=1'\n      - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'\n      - 'REDIS_CLUSTER_CREATOR=yes'\n\n  db:\n     image: \"mcr.microsoft.com/mssql/server\"\n     ports:\n        - 1433:1433\n     environment:\n       SA_PASSWORD: \"P@ssw0rd\"\n       ACCEPT_EULA: \"Y\"\n\n  redis-sample:\n    build:\n     context: ../..\n     dockerfile: samples/Samples.Redis.SqlServer/Dockerfile\n    environment:\n     - ASPNETCORE_URLS:http://*:8080\n     - ASPNETCORE_ENVIRONMENT=Development\n    ports:\n      - 8080:8080\n    depends_on:\n     - db\n     - redis-node-5\n \nvolumes:\n  redis-cluster_data-0:\n    driver: local\n  redis-cluster_data-1:\n    driver: local\n  redis-cluster_data-2:\n    driver: local\n  redis-cluster_data-3:\n    driver: local\n  redis-cluster_data-4:\n    driver: local\n  redis-cluster_data-5:\n    driver: local"
  },
  {
    "path": "src/Directory.Build.props",
    "content": "<Project>\n\n  <Import Project=\"..\\build\\version.props\" />\n\n  <PropertyGroup Label=\"Package\">\n    <Product>CAP</Product>\n\t<Nullable>enable</Nullable>\n    <Authors>NCC;Savorboard</Authors>\n    <RepositoryUrl>https://github.com/dotnetcore/CAP</RepositoryUrl>\n    <RepositoryType>git</RepositoryType>\n    <RepositoryRoot>$(MSBuildThisFileDirectory)</RepositoryRoot>\n\t<PackageIcon>logo.png</PackageIcon>\n    <PackageProjectUrl>https://github.com/dotnetcore/CAP</PackageProjectUrl>\n\t<PackageLicenseExpression>MIT</PackageLicenseExpression>\n    <PackageTags>CAP;EventBus;Outbox Patterns;Distributed transaction</PackageTags>\n    <Description>Distributed transaction solution in micro-service base on eventually consistency, also an eventbus with Outbox pattern.</Description>\n  </PropertyGroup>\n\n  <!-- Using SourceLink -->\n  <PropertyGroup>\n    <SymbolPackageFormat>snupkg</SymbolPackageFormat>\n\t<PublishRepositoryUrl>true</PublishRepositoryUrl>\n    <EmbedUntrackedSources>true</EmbedUntrackedSources>\n    <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>\n  </PropertyGroup>\n\n  <ItemGroup>\n\t<None Include=\"..\\..\\docs\\content\\img\\logo.png\" Pack=\"true\" Visible=\"false\"  PackagePath=\"\" />\n\t<PackageReference Include=\"Microsoft.SourceLink.GitHub\" Version=\"8.0.0\" PrivateAssets=\"All\"/>\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "src/DotNetCore.CAP/BrokerConnectionException.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\n\nnamespace DotNetCore.CAP;\n\n/// <summary>\n/// Represents an error that occurs when CAP cannot establish or maintain a connection to the message broker.\n/// This exception is thrown when connection issues prevent message publishing or consuming operations.\n/// </summary>\n/// <remarks>\n/// Common causes include:\n/// <list type=\"bullet\">\n/// <item><description>The broker service is offline or unreachable.</description></item>\n/// <item><description>Network connectivity issues prevent communication with the broker.</description></item>\n/// <item><description>Authentication or authorization failures when connecting to the broker.</description></item>\n/// <item><description>Broker-side resource limits or configuration issues.</description></item>\n/// </list>\n/// When this exception occurs, CAP will attempt to reconnect based on configured retry policies.\n/// </remarks>\npublic class BrokerConnectionException : Exception\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"BrokerConnectionException\"/> class with a reference to the inner exception\n    /// that caused this connection error.\n    /// </summary>\n    /// <param name=\"innerException\">\n    /// The underlying exception that caused the connection failure.\n    /// This typically contains specific details about the connection error from the broker client library.\n    /// </param>\n    public BrokerConnectionException(Exception innerException)\n        : base(\"Broker Unreachable\", innerException)\n    {\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/CAP.Attribute.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\r\n// Licensed under the MIT License. See License.txt in the project root for license information.\r\n\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Collections.ObjectModel;\r\nusing DotNetCore.CAP.Internal;\r\nusing DotNetCore.CAP.Messages;\r\n\r\n// ReSharper disable once CheckNamespace\r\nnamespace DotNetCore.CAP;\r\n\r\n/// <summary>\r\n/// Represents an attribute that is applied to a method to indicate that it is a subscriber for a specific CAP topic.\r\n/// </summary>\r\npublic class CapSubscribeAttribute : TopicAttribute\r\n{\r\n    /// <summary>\r\n    /// Initializes a new instance of the <see cref=\"CapSubscribeAttribute\"/> class with the specified topic name and partial flag.\r\n    /// </summary>\r\n    /// <param name=\"name\">The name of the CAP topic.</param>\r\n    /// <param name=\"isPartial\">A flag indicating whether the subscriber is a partial subscriber.</param>\r\n    public CapSubscribeAttribute(string name, bool isPartial = false)\r\n        : base(name, isPartial)\r\n    {\r\n    }\r\n\r\n    /// <summary>\r\n    /// Returns a string that represents the current <see cref=\"CapSubscribeAttribute\"/>.\r\n    /// </summary>\r\n    /// <returns>A string that represents the current <see cref=\"CapSubscribeAttribute\"/>.</returns>\r\n    public override string ToString()\r\n    {\r\n        return Name;\r\n    }\r\n}\r\n\r\n[AttributeUsage(AttributeTargets.Parameter)]\r\npublic class FromCapAttribute : Attribute\r\n{\r\n}\r\n\r\npublic class CapHeader : ReadOnlyDictionary<string, string?>\r\n{\r\n    internal IDictionary<string, string?>? ResponseHeader { get; set; }\r\n\r\n    public CapHeader(IDictionary<string, string?> dictionary) : base(dictionary)\r\n    {\r\n    }\r\n\r\n    /// <summary>\r\n    /// When a callbackName is specified from publish message, use this method to add an additional header.\r\n    /// </summary>\r\n    /// <param name=\"key\">The response header key.</param>\r\n    /// <param name=\"value\">The response header value.</param>\r\n    public void AddResponseHeader(string key, string? value)\r\n    {\r\n        ResponseHeader ??= new Dictionary<string, string?>();\r\n        ResponseHeader[key] = value;\r\n    }\r\n\r\n    /// <summary>\r\n    /// When a callbackName is specified from publish message, use this method to abort the callback.\r\n    /// </summary>\r\n    public void RemoveCallback()\r\n    {\r\n        Dictionary.Remove(Headers.CallbackName);\r\n    }\r\n\r\n    /// <summary>\r\n    /// When a callbackName is specified from Publish message, use this method to rewrite the callback name.\r\n    /// </summary>\r\n    /// <param name=\"callbackName\">The new callback name.</param>\r\n    public void RewriteCallback(string callbackName)\r\n    {\r\n        Dictionary[Headers.CallbackName] = callbackName;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/DotNetCore.CAP/CAP.Builder.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Reflection;\nusing DotNetCore.CAP.Filter;\nusing DotNetCore.CAP.Internal;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\n\n// ReSharper disable UnusedMember.Global\n\nnamespace DotNetCore.CAP;\n\n/// <summary>\n/// A marker service used internally to verify that the CAP service has been registered on a <see cref=\"IServiceCollection\"/>.\n/// This service is registered when <c>AddCap()</c> is called during dependency injection setup.\n/// </summary>\npublic class CapMarkerService\n{\n    /// <summary>\n    /// Gets or sets the name identifier for the CAP service.\n    /// </summary>\n    public string Name { get; set; }\n\n    /// <summary>\n    /// Gets or sets the version of the CAP assembly.\n    /// </summary>\n    public string Version { get; set; }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"CapMarkerService\"/> class with the specified name.\n    /// Automatically retrieves and stores the CAP assembly version information.\n    /// </summary>\n    /// <param name=\"name\">The name identifier for the CAP service.</param>\n    public CapMarkerService(string name)\n    {\n        Name = name;\n\n        try\n        {\n            Version = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductVersion!;\n        }\n        catch\n        {\n            Version = \"N/A\";\n        }\n    }\n}\n\n/// <summary>\n/// A marker service used internally to verify that a CAP storage extension (e.g., SQL Server, PostgreSQL, MySQL, MongoDB) \n/// has been registered on a <see cref=\"IServiceCollection\"/>.\n/// </summary>\npublic class CapStorageMarkerService\n{\n    /// <summary>\n    /// Gets or sets the name identifier for the storage extension (e.g., \"SqlServer\", \"PostgreSql\", \"MySql\").\n    /// </summary>\n    public string Name { get; set; }\n\n    //public IDictionary<string, string> MetaData { get; private set; }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"CapStorageMarkerService\"/> class with the specified storage name.\n    /// </summary>\n    /// <param name=\"name\">The name identifier for the storage extension.</param>\n    public CapStorageMarkerService(string name)\n    {\n        Name = name;\n    }\n}\n\n/// <summary>\n/// A marker service used internally to verify that a CAP message transport extension (e.g., RabbitMQ, Kafka, Azure Service Bus, NATS) \n/// has been registered on a <see cref=\"IServiceCollection\"/>.\n/// </summary>\npublic class CapMessageQueueMakerService\n{\n    /// <summary>\n    /// Gets or sets the name identifier for the message transport extension (e.g., \"RabbitMQ\", \"Kafka\", \"AzureServiceBus\").\n    /// </summary>\n    public string Name { get; set; }\n\n    //public IDictionary<string, object> MetaData { get; private set; }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"CapMessageQueueMakerService\"/> class with the specified message queue name.\n    /// </summary>\n    /// <param name=\"name\">The name identifier for the message transport extension.</param>\n    public CapMessageQueueMakerService(string name)\n    {\n        Name = name;\n    }\n}\n\n/// <summary>\n/// Provides a fluent API for fine-grained configuration of CAP services within a dependency injection container.\n/// This builder allows registration of subscriber filters, custom subscriber assembly scanning, and other CAP extensions.\n/// </summary>\n/// <remarks>\n/// The <see cref=\"CapBuilder\"/> is typically obtained through the <c>AddCap()</c> extension method on <see cref=\"IServiceCollection\"/>,\n/// enabling a fluent configuration experience for CAP setup. All builder methods return the builder instance to support method chaining.\n/// </remarks>\npublic sealed class CapBuilder\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"CapBuilder\"/> class with the specified service collection.\n    /// </summary>\n    /// <param name=\"services\">The <see cref=\"IServiceCollection\"/> where CAP services are being configured.</param>\n    public CapBuilder(IServiceCollection services)\n    {\n        Services = services;\n    }\n\n    /// <summary>\n    /// Gets the <see cref=\"IServiceCollection\"/> where CAP services are registered and configured.\n    /// </summary>\n    /// <remarks>\n    /// This collection is used by all builder methods to register necessary services, filters, and extensions\n    /// in the application's dependency injection container.\n    /// </remarks>\n    public IServiceCollection Services { get; }\n\n    /// <summary>\n    /// Registers a subscriber filter that will be applied to all subscriber method executions.\n    /// Filters can be used for cross-cutting concerns such as logging, error handling, and transaction management.\n    /// </summary>\n    /// <typeparam name=\"T\">\n    /// The type of the filter to register. Must implement <see cref=\"ISubscribeFilter\"/> and be instantiable.\n    /// The filter is registered with a scoped lifetime, meaning a new instance is created per request/scope.\n    /// </typeparam>\n    /// <returns>The current <see cref=\"CapBuilder\"/> instance to support fluent method chaining.</returns>\n    /// <remarks>\n    /// Multiple filters can be registered by calling this method multiple times. Filters are executed in the order\n    /// they are registered, allowing for layered processing of subscriber messages.\n    /// </remarks>\n    /// <example>\n    /// <code>\n    /// services.AddCap(options =>\n    /// {\n    ///     options.UseRabbitMQ(r => r.HostName = \"localhost\");\n    ///     options.UseSqlServer(\"connection_string\");\n    /// })\n    /// .AddSubscribeFilter&lt;LoggingFilter&gt;()\n    /// .AddSubscribeFilter&lt;ExceptionHandlingFilter&gt;();\n    /// </code>\n    /// </example>\n    public CapBuilder AddSubscribeFilter<T>() where T : class, ISubscribeFilter\n    {\n        Services.TryAddScoped<ISubscribeFilter, T>();\n        return this;\n    }\n\n    /// <summary>\n    /// Registers subscriber methods from the specified assemblies.\n    /// This method scans the provided assemblies for classes and methods decorated with CAP subscriber attributes.\n    /// </summary>\n    /// <param name=\"assemblies\">\n    /// An array of <see cref=\"Assembly\"/> instances to scan for subscriber implementations.\n    /// </param>\n    /// <returns>The current <see cref=\"CapBuilder\"/> instance to support fluent method chaining.</returns>\n    /// <exception cref=\"ArgumentNullException\">Thrown if <paramref name=\"assemblies\"/> is null.</exception>\n    /// <remarks>\n    /// This method replaces the default subscriber selector with a custom one that scans the specified assemblies.\n    /// By default, CAP scans all loaded assemblies; this method allows you to restrict scanning to specific assemblies\n    /// for performance optimization or explicit control over subscriber discovery.\n    /// </remarks>\n    /// <example>\n    /// <code>\n    /// var capAssembly = typeof(MyCapHandlers).Assembly;\n    /// services.AddCap(options => { })\n    ///     .AddSubscriberAssembly(capAssembly);\n    /// </code>\n    /// </example>\n    public CapBuilder AddSubscriberAssembly(params Assembly[] assemblies)\n    {\n        ArgumentNullException.ThrowIfNull(assemblies);\n\n        Services.Replace(new ServiceDescriptor(typeof(IConsumerServiceSelector),\n            x => new AssemblyConsumerServiceSelector(x, assemblies),\n            ServiceLifetime.Singleton));\n\n        return this;\n    }\n\n    /// <summary>\n    /// Registers subscriber methods from the assemblies containing the specified marker types.\n    /// This is a convenience overload that extracts the assemblies from the provided types and delegates to <see cref=\"AddSubscriberAssembly(Assembly[])\"/>.\n    /// </summary>\n    /// <param name=\"handlerAssemblyMarkerTypes\">\n    /// An array of marker types (typically classes in the target assemblies) whose containing assemblies will be scanned for subscribers.\n    /// This approach allows type-safe specification of which assemblies to include without directly referencing <see cref=\"Assembly\"/> objects.\n    /// </param>\n    /// <returns>The current <see cref=\"CapBuilder\"/> instance to support fluent method chaining.</returns>\n    /// <exception cref=\"ArgumentNullException\">Thrown if <paramref name=\"handlerAssemblyMarkerTypes\"/> is null.</exception>\n    /// <remarks>\n    /// This method is particularly useful in multi-project scenarios where you have separate projects for handlers\n    /// but want to avoid direct assembly references. Simply pass a type from each assembly, and the method will\n    /// automatically extract and scan those assemblies.\n    /// </remarks>\n    /// <example>\n    /// <code>\n    /// // Assuming MyCapHandlers is a class in the assembly containing subscriber implementations\n    /// services.AddCap(options => { })\n    ///     .AddSubscriberAssembly(typeof(MyCapHandlers));\n    /// </code>\n    /// </example>\n    public CapBuilder AddSubscriberAssembly(params Type[] handlerAssemblyMarkerTypes)\n    {\n        ArgumentNullException.ThrowIfNull(handlerAssemblyMarkerTypes);\n\n        AddSubscriberAssembly(handlerAssemblyMarkerTypes.Select(t => t.GetTypeInfo().Assembly).ToArray());\n\n        return this;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/CAP.Options.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing System.Text.Json;\nusing DotNetCore.CAP.Messages;\n\n// ReSharper disable InconsistentNaming\n\nnamespace DotNetCore.CAP;\n\n/// <summary>\n/// Provides options to customize various aspects of the message processing pipeline. This includes settings for message expiration,\n/// retry mechanisms, concurrency management, and serialization, among others. This class allows fine-tuning\n/// CAP's behavior to better align with specific application requirements, such as adjusting threading models for\n/// subscriber message processing, setting message expiry times, and customizing serialization settings.\n/// </summary>\npublic class CapOptions\n{\n    public CapOptions()\n    {\n        SucceedMessageExpiredAfter = 24 * 3600;\n        FailedMessageExpiredAfter = 15 * 24 * 3600;\n        FailedRetryInterval = 60;\n        FailedRetryCount = 50;\n        ConsumerThreadCount = 1;\n        EnablePublishParallelSend = false;\n        EnableSubscriberParallelExecute = false;\n        SubscriberParallelExecuteThreadCount = Environment.ProcessorCount;\n        SubscriberParallelExecuteBufferFactor = 1;\n        Extensions = new List<ICapOptionsExtension>();\n        Version = \"v1\";\n        DefaultGroupName = \"cap.queue.\" + Assembly.GetEntryAssembly()?.GetName().Name!.ToLower();\n        CollectorCleaningInterval = 300;\n        FallbackWindowLookbackSeconds = 240;\n        SchedulerBatchSize = 1000;\n    }\n\n    internal IList<ICapOptionsExtension> Extensions { get; }\n\n    /// <summary>\n    /// Gets or sets the default consumer group name for subscribers. \n    /// In Kafka, this corresponds to the consumer group name; in RabbitMQ, it corresponds to the queue name.\n    /// Default value is \"cap.queue.\" followed by the entry assembly name in lowercase.\n    /// </summary>\n    public string DefaultGroupName { get; set; }\n\n    /// <summary>\n    /// Gets or sets an optional prefix to be prepended to all consumer group names.\n    /// </summary>\n    public string? GroupNamePrefix { get; set; }\n\n    /// <summary>\n    /// Gets or sets an optional prefix to be prepended to all topic names.\n    /// </summary>\n    public string? TopicNamePrefix { get; set; }\n\n    /// <summary>\n    /// Gets or sets the version identifier for messages, used to isolate data between different instances or deployments.\n    /// This allows multiple instances to coexist without message conflicts. Maximum length is 20 characters.\n    /// Default is \"v1\".\n    /// </summary>\n    public string Version { get; set; }\n\n    /// <summary>\n    /// Gets or sets the time interval (in seconds) after which successfully processed messages are automatically deleted.\n    /// This helps manage storage by removing old successfully delivered messages.\n    /// Default is 86,400 seconds (24 hours).\n    /// </summary>\n    public int SucceedMessageExpiredAfter { get; set; }\n\n    /// <summary>\n    /// Gets or sets the time interval (in seconds) after which failed messages are automatically deleted.\n    /// This allows cleanup of old failed messages that exceed the retry threshold.\n    /// Default is 1,296,000 seconds (15 days).\n    /// </summary>\n    public int FailedMessageExpiredAfter { get; set; }\n\n    /// <summary>\n    /// Gets or sets the polling interval (in seconds) for the retry processor to check and retry failed messages.\n    /// Default is 60 seconds.\n    /// </summary>\n    public int FailedRetryInterval { get; set; }\n\n    /// <summary>\n    /// Gets or sets an optional callback function invoked when a message has been retried the maximum number of times\n    /// specified by <see cref=\"FailedRetryCount\"/> without success. This callback receives detailed information about the failed message.\n    /// </summary>\n    public Action<FailedInfo>? FailedThresholdCallback { get; set; }\n\n    /// <summary>\n    /// Gets or sets the maximum number of retry attempts for failed messages (both published and subscribed).\n    /// Once this threshold is reached, the message is marked as permanently failed and no longer retried.\n    /// Default is 50 times.\n    /// </summary>\n    public int FailedRetryCount { get; set; }\n\n    /// <summary>\n    /// Gets or sets the number of concurrent consumer threads for message consumption from the transport.\n    /// Higher values increase parallelism but consume more resources; lower values reduce resource usage but may lower throughput.\n    /// Default is 1.\n    /// </summary>\n    public int ConsumerThreadCount { get; set; }\n\n    /// <summary>\n    /// Gets or sets a value indicating whether to enable parallel execution of subscriber methods using an in-memory queue.\n    /// When enabled, received messages are buffered in memory and processed concurrently by multiple worker threads.\n    /// Use <see cref=\"SubscriberParallelExecuteThreadCount\"/> to configure the number of parallel threads.\n    /// Default is false.\n    /// </summary>\n    public bool EnableSubscriberParallelExecute { get; set; }\n\n    /// <summary>\n    /// Gets or sets the number of parallel worker threads for subscriber message execution when <see cref=\"EnableSubscriberParallelExecute\"/> is enabled.\n    /// This controls the degree of parallelism when processing subscriber handlers.\n    /// Default is the number of logical processors (<see cref=\"Environment.ProcessorCount\"/>).\n    /// </summary>\n    public int SubscriberParallelExecuteThreadCount { get; set; }\n\n    /// <summary>\n    /// Gets or sets a multiplier factor for determining the in-memory buffer capacity when <see cref=\"EnableSubscriberParallelExecute\"/> is enabled.\n    /// The actual buffer capacity is calculated as: <c>SubscriberParallelExecuteThreadCount × SubscriberParallelExecuteBufferFactor</c>.\n    /// This controls how many messages can be queued before blocking new incoming messages.\n    /// Default is 1.\n    /// </summary>\n    public int SubscriberParallelExecuteBufferFactor { get; set; }\n\n    /// <summary>\n    /// Gets or sets a value indicating whether to enable parallel execution of publish operations using the .NET thread pool.\n    /// When enabled, message publishing tasks are dispatched to the thread pool for concurrent execution, improving throughput for high-volume publishing scenarios.\n    /// Default is false.\n    /// </summary>\n    public bool EnablePublishParallelSend { get; set; } \n\n    /// <summary>\n    /// Gets or sets the lookback time window (in seconds) for the retry processor to pick up scheduled or failed status messages.\n    /// This ensures that messages with clocks slightly out of sync are still processed correctly.\n    /// Default is 240 seconds (4 minutes).\n    /// </summary>\n    public int FallbackWindowLookbackSeconds { get; set; }\n\n    /// <summary>\n    /// Gets or sets the interval (in seconds) at which the cleanup processor removes expired messages from the message storage.\n    /// The processor runs periodically to clean up messages that have exceeded their expiration times.\n    /// Default is 300 seconds (5 minutes).\n    /// </summary>\n    public int CollectorCleaningInterval { get; set; }\n\n    /// <summary>\n    /// Gets or sets the maximum number of delayed or failed messages to fetch in a single scheduler cycle.\n    /// Larger batches improve throughput but consume more memory; smaller batches reduce memory usage but may lower throughput.\n    /// Default is 1,000.\n    /// </summary>\n    public int SchedulerBatchSize { get; set; }\n\n    /// <summary>\n    /// Gets or sets the JSON serialization options used for message content serialization and deserialization.\n    /// Customize this to control JSON formatting, naming policies, converters, and other serialization behavior.\n    /// </summary>\n    public JsonSerializerOptions JsonSerializerOptions { get; } = new();\n\n    /// <summary>\n    /// Gets or sets a value indicating whether to use distributed storage locking when retrying failed messages.\n    /// When enabled, only one instance in a distributed system will perform message retries, preventing duplicate processing.\n    /// This is essential for clustered deployments to ensure exactly-once retry semantics.\n    /// Default is false.\n    /// </summary>\n    public bool UseStorageLock { get; set; }\n\n    /// <summary>\n    /// Registers a CAP options extension that will be executed when configuring CAP services.\n    /// Extensions allow third-party libraries to customize CAP's behavior without modifying core configuration.\n    /// </summary>\n    /// <param name=\"extension\">The extension instance to register.</param>\n    /// <exception cref=\"ArgumentNullException\">Thrown if <paramref name=\"extension\"/> is null.</exception>\n    public void RegisterExtension(ICapOptionsExtension extension)\n    {\n        ArgumentNullException.ThrowIfNull(extension);\n\n        Extensions.Add(extension);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Processor;\nusing DotNetCore.CAP.Serialization;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.Extensions.DependencyInjection;\n\n/// <summary>\n/// Provides extension methods for registering and configuring CAP (Consistency And Partition) services\n/// in a <see cref=\"IServiceCollection\"/> dependency injection container.\n/// </summary>\npublic static class ServiceCollectionExtensions\n{\n    /// <summary>\n    /// Registers and configures all CAP services in the dependency injection container.\n    /// </summary>\n    /// <remarks>\n    /// This method performs the following registrations:\n    /// <list type=\"bullet\">\n    /// <item><description>Core services: Message publisher, consumer selector, subscription invoker, and method matcher cache.</description></item>\n    /// <item><description>Message processors: Retry processor, transport check processor, delayed message processor, and message collector.</description></item>\n    /// <item><description>Message transport: Message sender and default JSON serializer.</description></item>\n    /// <item><description>Processing servers: Consumer registration server, dispatcher, and main CAP processing server.</description></item>\n    /// <item><description>Bootstrapper and hosted service for application startup and lifecycle management.</description></item>\n    /// <item><description>Extensions: Any configured storage and transport extensions (registered via <see cref=\"CapOptions.RegisterExtension\"/>).</description></item>\n    /// </list>\n    /// All core services are registered with singleton lifetime to ensure consistency across the application.\n    /// Storage and transport extensions must be added before calling this method (typically through AddCap callback).\n    /// </remarks>\n    /// <param name=\"services\">\n    /// The <see cref=\"IServiceCollection\"/> where CAP services will be registered.\n    /// This collection represents the application's dependency injection container.\n    /// </param>\n    /// <param name=\"setupAction\">\n    /// A delegate that configures the <see cref=\"CapOptions\"/> settings for CAP.\n    /// This action is invoked to customize behavior such as message expiration, retry policies, concurrency settings,\n    /// and to register storage and transport extensions.\n    /// Use this to call <c>UseRabbitMQ()</c>, <c>UseSqlServer()</c>, and other extension methods.\n    /// </param>\n    /// <returns>\n    /// A <see cref=\"CapBuilder\"/> instance that provides a fluent API for additional CAP configuration,\n    /// such as registering subscriber filters and custom subscriber assembly scanning.\n    /// </returns>\n    /// <exception cref=\"ArgumentNullException\">\n    /// Thrown if <paramref name=\"setupAction\"/> is null.\n    /// </exception>\n    /// <example>\n    /// <code>\n    /// services.AddCap(options =>\n    /// {\n    ///     // Configure options\n    ///     options.SucceedMessageExpiredAfter = 24 * 3600;\n    ///     options.FailedRetryCount = 50;\n    ///     \n    ///     // Register storage backend\n    ///     options.UseSqlServer(\"your_connection_string\");\n    ///     \n    ///     // Register message transport\n    ///     options.UseRabbitMQ(rabbitMqOptions =>\n    ///     {\n    ///         rabbitMqOptions.HostName = \"localhost\";\n    ///         rabbitMqOptions.Port = 5672;\n    ///     });\n    /// })\n    /// .AddSubscribeFilter&lt;LoggingFilter&gt;()\n    /// .AddSubscriberAssembly(typeof(MyCapHandlers));\n    /// </code>\n    /// </example>\n    public static CapBuilder AddCap(this IServiceCollection services, Action<CapOptions> setupAction)\n    {\n        ArgumentNullException.ThrowIfNull(setupAction);\n\n        services.AddSingleton(_ => services);\n        services.TryAddSingleton(new CapMarkerService(\"CAP\"));\n        services.TryAddSingleton<ISnowflakeId, SnowflakeId>();\n        services.TryAddSingleton<ICapPublisher, CapPublisher>();\n\n        services.TryAddSingleton<IConsumerServiceSelector, ConsumerServiceSelector>();\n        services.TryAddSingleton<ISubscribeInvoker, SubscribeInvoker>();\n        services.TryAddSingleton<MethodMatcherCache>();\n\n        services.TryAddSingleton<IConsumerRegister, ConsumerRegister>();\n\n        //Processors\n        services.TryAddEnumerable(ServiceDescriptor.Singleton<IProcessingServer, IDispatcher>(sp => sp.GetRequiredService<IDispatcher>()));\n        services.TryAddEnumerable(ServiceDescriptor.Singleton<IProcessingServer, IConsumerRegister>(sp => sp.GetRequiredService<IConsumerRegister>()));\n        services.TryAddEnumerable(ServiceDescriptor.Singleton<IProcessingServer, CapProcessingServer>());\n\n        //Queue's message processor\n        services.TryAddSingleton<MessageNeedToRetryProcessor>();\n        services.TryAddSingleton<TransportCheckProcessor>();\n        services.TryAddSingleton<MessageDelayedProcessor>();\n        services.TryAddSingleton<CollectorProcessor>();\n\n        //Sender\n        services.TryAddSingleton<IMessageSender, MessageSender>();\n\n        services.TryAddSingleton<ISerializer, JsonUtf8Serializer>();\n\n        // Warning: IPublishMessageSender need to inject at extension project. \n        services.TryAddSingleton<ISubscribeExecutor, SubscribeExecutor>();\n\n        //Options and extension service\n        var options = new CapOptions();\n        setupAction(options);\n\n        services.TryAddSingleton<IDispatcher, Dispatcher>();\n\n        foreach (var serviceExtension in options.Extensions)\n            serviceExtension.AddServices(services);\n\n        services.Configure(setupAction);\n\n        //Startup and Hosted \n        services.AddSingleton<Bootstrapper>();\n        services.AddHostedService(sp => sp.GetRequiredService<Bootstrapper>());\n        services.AddSingleton<IBootstrapper>(sp => sp.GetRequiredService<Bootstrapper>());\n\n        return new CapBuilder(services);\n    }\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP/Diagnostics/CapDiagnosticListenerNames.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nnamespace DotNetCore.CAP.Diagnostics;\n\n/// <summary>\n/// Extension methods on the DiagnosticListener class to log CAP data\n/// </summary>\npublic static class CapDiagnosticListenerNames\n{\n    private const string CapPrefix = \"DotNetCore.CAP.\";\n\n    //Tracing\n    public const string DiagnosticListenerName = \"CapDiagnosticListener\";\n\n    public const string BeforePublishMessageStore = CapPrefix + \"WritePublishMessageStoreBefore\";\n    public const string AfterPublishMessageStore = CapPrefix + \"WritePublishMessageStoreAfter\";\n    public const string ErrorPublishMessageStore = CapPrefix + \"WritePublishMessageStoreError\";\n\n    public const string BeforePublish = CapPrefix + \"WritePublishBefore\";\n    public const string AfterPublish = CapPrefix + \"WritePublishAfter\";\n    public const string ErrorPublish = CapPrefix + \"WritePublishError\";\n\n    public const string BeforeConsume = CapPrefix + \"WriteConsumeBefore\";\n    public const string AfterConsume = CapPrefix + \"WriteConsumeAfter\";\n    public const string ErrorConsume = CapPrefix + \"WriteConsumeError\";\n\n    public const string BeforeSubscriberInvoke = CapPrefix + \"WriteSubscriberInvokeBefore\";\n    public const string AfterSubscriberInvoke = CapPrefix + \"WriteSubscriberInvokeAfter\";\n    public const string ErrorSubscriberInvoke = CapPrefix + \"WriteSubscriberInvokeError\";\n\n    //Metrics\n    public const string MetricListenerName = CapPrefix + \"EventCounter\";\n    public const string PublishedPerSec = \"published-per-second\";\n    public const string ConsumePerSec = \"consume-per-second\";\n    public const string InvokeSubscriberPerSec = \"invoke-subscriber-per-second\";\n    public const string InvokeSubscriberElapsedMs = \"invoke-subscriber-elapsed-ms\";\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Diagnostics/EventCounterSource.Cap.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Diagnostics.Tracing;\n\nnamespace DotNetCore.CAP.Diagnostics;\n\n[EventSource(Name = CapDiagnosticListenerNames.MetricListenerName)]\npublic class CapEventCounterSource : EventSource\n{\n    public static readonly CapEventCounterSource Log = new();\n\n    private IncrementingEventCounter? _publishPerSecondCounter;\n    private IncrementingEventCounter? _consumePerSecondCounter;\n    private IncrementingEventCounter? _subscriberInvokePerSecondCounter;\n\n    private EventCounter? _invokeCounter;\n\n    private CapEventCounterSource() { }\n\n    protected override void OnEventCommand(EventCommandEventArgs args)\n    {\n        if (args.Command == EventCommand.Enable)\n        {\n            _publishPerSecondCounter ??= new IncrementingEventCounter(CapDiagnosticListenerNames.PublishedPerSec, this)\n            {\n                DisplayName = \"Publish Rate\",\n                DisplayRateTimeScale = TimeSpan.FromSeconds(1)\n            };\n\n            _consumePerSecondCounter ??= new IncrementingEventCounter(CapDiagnosticListenerNames.ConsumePerSec, this)\n            {\n                DisplayName = \"Consume Rate\",\n                DisplayRateTimeScale = TimeSpan.FromSeconds(1)\n            };\n\n            _subscriberInvokePerSecondCounter ??= new IncrementingEventCounter(CapDiagnosticListenerNames.InvokeSubscriberPerSec, this)\n            {\n                DisplayName = \"Invoke Subscriber Rate\",\n                DisplayRateTimeScale = TimeSpan.FromSeconds(1)\n            };\n\n            _invokeCounter ??= new EventCounter(CapDiagnosticListenerNames.InvokeSubscriberElapsedMs, this)\n            {\n                DisplayName = \"Invoke Subscriber Elapsed Time\",\n                DisplayUnits = \"ms\"\n            };\n        }\n    }\n\n    public void WritePublishMetrics()\n    {\n        _publishPerSecondCounter?.Increment();\n    }\n\n    public void WriteConsumeMetrics()\n    {\n        _consumePerSecondCounter?.Increment();\n    }\n\n    public void WriteInvokeMetrics()\n    {\n        _subscriberInvokePerSecondCounter?.Increment();\n    }\n\n    public void WriteInvokeTimeMetrics(double elapsedMs)\n    {\n        _invokeCounter?.WriteMetric(elapsedMs);\n    }\n\n    protected override void Dispose(bool disposing)\n    {\n        _publishPerSecondCounter?.Dispose();\n        _consumePerSecondCounter?.Dispose();\n        _subscriberInvokePerSecondCounter?.Dispose();\n        _invokeCounter?.Dispose();\n\n        _publishPerSecondCounter = null;\n        _consumePerSecondCounter = null;\n        _subscriberInvokePerSecondCounter = null;\n        _invokeCounter = null;\n\n        base.Dispose(disposing);\n    }\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP/Diagnostics/EventData.Cap.P.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\n\nnamespace DotNetCore.CAP.Diagnostics;\n\npublic class CapEventDataPubStore\n{\n    public long? OperationTimestamp { get; set; }\n\n    public string Operation { get; set; } = default!;\n\n    public Message Message { get; set; } = default!;\n\n    public long? ElapsedTimeMs { get; set; }\n\n    public Exception? Exception { get; set; }\n}\n\npublic class CapEventDataPubSend\n{\n    public long? OperationTimestamp { get; set; }\n\n    public string Operation { get; set; } = default!;\n\n    public TransportMessage TransportMessage { get; set; } = default!;\n\n    public BrokerAddress BrokerAddress { get; set; }\n\n    public long? ElapsedTimeMs { get; set; }\n\n    public Exception? Exception { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Diagnostics/EventData.Cap.S.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Reflection;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\n\nnamespace DotNetCore.CAP.Diagnostics;\n\npublic class CapEventDataSubStore\n{\n    public long? OperationTimestamp { get; set; }\n\n    public string Operation { get; set; } = default!;\n\n    public TransportMessage TransportMessage { get; set; } = default!;\n\n    public BrokerAddress BrokerAddress { get; set; }\n\n    public long? ElapsedTimeMs { get; set; }\n\n    public Exception? Exception { get; set; }\n}\n\npublic class CapEventDataSubExecute\n{\n    public long? OperationTimestamp { get; set; }\n\n    public string Operation { get; set; } = default!;\n\n    public Message Message { get; set; } = default!;\n\n    public MethodInfo? MethodInfo { get; set; }\n\n    public long? ElapsedTimeMs { get; set; }\n\n    public Exception? Exception { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/DotNetCore.CAP.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>\n\t\t<Nullable>enable</Nullable>\n\t</PropertyGroup>\n\n\t<PropertyGroup>\n\t\t<GenerateDocumentationFile>true</GenerateDocumentationFile>\n\t\t<NoWarn>1701;1702;1705;CS1591</NoWarn>\n\t\t<PackageReadmeFile>README.md</PackageReadmeFile>\n\t</PropertyGroup>\n\n\t<ItemGroup>\n\t\t<None Include=\"..\\..\\README.md\">\n\t\t\t<Pack>True</Pack>\n\t\t\t<PackagePath>\\</PackagePath>\n\t\t</None>\n\t</ItemGroup>\n\n\t<ItemGroup>\n\t\t<PackageReference Include=\"Microsoft.Extensions.Hosting.Abstractions\" Version=\"10.0.0\" />\n\t\t<PackageReference Include=\"Microsoft.Extensions.Logging.Abstractions\" Version=\"10.0.0\" />\n\t\t<PackageReference Include=\"Microsoft.Extensions.Options\" Version=\"10.0.0\" />\n\t</ItemGroup>\n\n</Project>"
  },
  {
    "path": "src/DotNetCore.CAP/IBootstrapper.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace DotNetCore.CAP;\n\n/// <summary>\n/// Defines the contract for CAP bootstrapping logic that initializes the system when the application starts.\n/// Implementations perform setup tasks such as initializing storage, registering consumers, or preparing the message queue.\n/// </summary>\n/// <remarks>\n/// The bootstrapper is responsible for:\n/// <list type=\"bullet\">\n/// <item><description>Initializing storage tables or schema if not already present.</description></item>\n/// <item><description>Registering consumer subscribers from discovered assemblies.</description></item>\n/// <item><description>Verifying connection to message brokers and storage backends.</description></item>\n/// <item><description>Preparing the system for message publishing and consuming operations.</description></item>\n/// </list>\n/// The bootstrapper is registered as a hosted service and automatically starts when the application starts.\n/// </remarks>\npublic interface IBootstrapper : IAsyncDisposable\n{\n    /// <summary>\n    /// Gets a value indicating whether the bootstrap process has completed successfully.\n    /// Returns true if the system is fully initialized; false if bootstrap is still in progress or failed.\n    /// </summary>\n    bool IsStarted { get; }\n\n    /// <summary>\n    /// Asynchronously performs the bootstrap initialization for CAP.\n    /// This method is called when the application starts and should complete all necessary initialization.\n    /// </summary>\n    /// <param name=\"cancellationToken\">A token to monitor for cancellation requests.</param>\n    /// <returns>A task representing the asynchronous bootstrap operation.</returns>\n    Task BootstrapAsync(CancellationToken cancellationToken = default);\n}"
  },
  {
    "path": "src/DotNetCore.CAP/ICapOptionsExtension.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace DotNetCore.CAP;\n\n/// <summary>\n/// Defines an extension mechanism for customizing CAP configuration during dependency injection setup.\n/// Implementations of this interface allow third-party libraries and custom code to register services\n/// and configure CAP functionality without modifying the core CAP assembly.\n/// </summary>\n/// <remarks>\n/// Extensions are registered through <see cref=\"CapOptions.RegisterExtension(ICapOptionsExtension)\"/>\n/// and are executed during the <c>AddCap()</c> service registration process.\n/// This allows modular and composable configuration of storage backends, transport implementations, and other CAP components.\n/// </remarks>\npublic interface ICapOptionsExtension\n{\n    /// <summary>\n    /// Called during CAP service registration to add and configure child services in the dependency injection container.\n    /// </summary>\n    /// <remarks>\n    /// Implementations should use <c>TryAdd</c> or <c>Replace</c> extension methods to register services,\n    /// allowing other extensions or user code to override registrations if needed.\n    /// </remarks>\n    /// <param name=\"services\">\n    /// The <see cref=\"IServiceCollection\"/> where services should be registered.\n    /// This is the same collection being configured for the application's dependency injection.\n    /// </param>\n    /// <example>\n    /// <code>\n    /// public void AddServices(IServiceCollection services)\n    /// {\n    ///     services.TryAddSingleton&lt;IDataStorage, SqlServerDataStorage&gt;();\n    ///     services.TryAddSingleton&lt;ITransport, RabbitMQTransport&gt;();\n    /// }\n    /// </code>\n    /// </example>\n    void AddServices(IServiceCollection services);\n}"
  },
  {
    "path": "src/DotNetCore.CAP/ICapPublisher.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace DotNetCore.CAP;\n\n/// <summary>\n/// A publish service for publishing a message to CAP.\n/// </summary>\npublic interface ICapPublisher\n{\n    /// <summary>\n    /// Gets the service provider.\n    /// </summary>\n    IServiceProvider ServiceProvider { get; }\n\n    /// <summary>\n    /// Gets or sets the CAP transaction context object.\n    /// </summary>\n    ICapTransaction? Transaction { get; set; }\n\n    /// <summary>\n    /// Asynchronously publishes an object message.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of the message content object.</typeparam>\n    /// <param name=\"name\">The topic name or exchange router key.</param>\n    /// <param name=\"contentObj\">The message body content that will be serialized. (can be null)</param>\n    /// <param name=\"callbackName\">The callback subscriber name.</param>\n    /// <param name=\"cancellationToken\">The cancellation token.</param>\n    /// <returns>A task representing the asynchronous operation.</returns>\n    Task PublishAsync<T>(string name, T? contentObj, string? callbackName = null,\n        CancellationToken cancellationToken = default);\n\n    /// <summary>\n    /// Asynchronously publishes an object message with custom headers.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of the message content object.</typeparam>\n    /// <param name=\"name\">The topic name or exchange router key.</param>\n    /// <param name=\"contentObj\">The message body content that will be serialized. (can be null)</param>\n    /// <param name=\"headers\">The message additional headers.</param>\n    /// <param name=\"cancellationToken\">The cancellation token.</param>\n    /// <returns>A task representing the asynchronous operation.</returns>\n    Task PublishAsync<T>(string name, T? contentObj, IDictionary<string, string?> headers,\n        CancellationToken cancellationToken = default);\n\n    /// <summary>\n    /// Publishes an object message.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of the message content object.</typeparam>\n    /// <param name=\"name\">The topic name or exchange router key.</param>\n    /// <param name=\"contentObj\">The message body content that will be serialized. (can be null)</param>\n    /// <param name=\"callbackName\">The callback subscriber name.</param>\n    void Publish<T>(string name, T? contentObj, string? callbackName = null);\n\n    /// <summary>\n    /// Publishes an object message with custom headers.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of the message content object.</typeparam>\n    /// <param name=\"name\">The topic name or exchange router key.</param>\n    /// <param name=\"contentObj\">The message body content that will be serialized. (can be null)</param>\n    /// <param name=\"headers\">The message additional headers.</param>\n    void Publish<T>(string name, T? contentObj, IDictionary<string, string?> headers);\n\n    /// <summary>\n    /// Asynchronously schedules a message to be published at a future time with headers.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of the message content object.</typeparam>\n    /// <param name=\"delayTime\">The delay for the message to be published.</param>\n    /// <param name=\"name\">The topic name or exchange router key.</param>\n    /// <param name=\"contentObj\">The message body content that will be serialized. (can be null)</param>\n    /// <param name=\"headers\">The message additional headers.</param>\n    /// <param name=\"cancellationToken\">The cancellation token.</param>\n    /// <returns>A task representing the asynchronous operation.</returns>\n    Task PublishDelayAsync<T>(TimeSpan delayTime, string name, T? contentObj, IDictionary<string, string?> headers, CancellationToken cancellationToken = default);\n\n    /// <summary>\n    /// Asynchronously schedules a message to be published at a future time.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of the message content object.</typeparam>\n    /// <param name=\"delayTime\">The delay for the message to be published.</param>\n    /// <param name=\"name\">The topic name or exchange router key.</param>\n    /// <param name=\"contentObj\">The message body content that will be serialized. (can be null)</param>\n    /// <param name=\"callbackName\">The callback subscriber name.</param>\n    /// <param name=\"cancellationToken\">The cancellation token.</param>\n    /// <returns>A task representing the asynchronous operation.</returns>\n    Task PublishDelayAsync<T>(TimeSpan delayTime, string name, T? contentObj, string? callbackName = null, CancellationToken cancellationToken = default);\n\n    /// <summary>\n    /// Schedules a message to be published at a future time with headers.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of the message content object.</typeparam>\n    /// <param name=\"delayTime\">The delay for the message to be published.</param>\n    /// <param name=\"name\">The topic name or exchange router key.</param>\n    /// <param name=\"contentObj\">The message body content that will be serialized. (can be null)</param>\n    /// <param name=\"headers\">The message additional headers.</param>\n    void PublishDelay<T>(TimeSpan delayTime, string name, T? contentObj, IDictionary<string, string?> headers);\n\n    /// <summary>\n    /// Schedules a message to be published at a future time.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of the message content object.</typeparam>\n    /// <param name=\"delayTime\">The delay for the message to be published.</param>\n    /// <param name=\"name\">The topic name or exchange router key.</param>\n    /// <param name=\"contentObj\">The message body content that will be serialized. (can be null)</param>\n    /// <param name=\"callbackName\">The callback subscriber name.</param>\n    void PublishDelay<T>(TimeSpan delayTime, string name, T? contentObj, string? callbackName = null);\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP/ICapSubscribe.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nnamespace DotNetCore.CAP;\n\n/// <summary>\n/// A marker interface that identifies a class as containing CAP subscriber methods.\n/// Classes implementing this interface can use CAP subscriber attributes (e.g., <c>[Topic(...)]</c>) on their methods\n/// to subscribe to published messages.\n/// </summary>\n/// <remarks>\n/// This interface serves purely as a marker and does not define any members.\n/// Its purpose is to enable automatic discovery and registration of subscriber classes during application startup.\n/// \n/// Usage example:\n/// <code>\n/// public class OrderSubscriber : ICapSubscribe\n/// {\n///     [CapSubscribe(\"order.created\")]\n///     public async Task OnOrderCreated(OrderCreatedMessage message)\n///     {\n///         // Handle the message\n///         await ProcessOrder(message);\n///     }\n/// }\n/// </code>\n/// </remarks>\npublic interface ICapSubscribe\n{\n}"
  },
  {
    "path": "src/DotNetCore.CAP/ICapTransaction.Base.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Concurrent;\nusing System.Globalization;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Transport;\n\nnamespace DotNetCore.CAP;\n\n/// <summary>\n/// A thread-safe holder for storing the current CAP transaction context within a scope (e.g., per HTTP request or async execution context).\n/// This is used internally to associate a transaction with the ambient execution context.\n/// </summary>\ninternal sealed class CapTransactionHolder\n{\n    /// <summary>\n    /// Gets or sets the CAP transaction associated with the current context.\n    /// </summary>\n    public ICapTransaction? Transaction;\n}\n\n/// <summary>\n/// Provides a base implementation of <see cref=\"ICapTransaction\"/> that manages message publishing within a database transaction.\n/// This class handles buffering, flushing, and coordination of messages with the message transport layer.\n/// </summary>\n/// <remarks>\n/// This base class:\n/// <list type=\"bullet\">\n/// <item><description>Maintains an internal queue of messages to be published.</description></item>\n/// <item><description>Provides methods to add messages to the queue and flush them to the dispatcher.</description></item>\n/// <item><description>Handles both delayed and immediate message publishing based on message headers.</description></item>\n/// <item><description>Integrates with the dispatcher to enqueue messages for publishing or scheduling.</description></item>\n/// </list>\n/// Derived classes must implement the transaction-specific Commit/Rollback operations.\n/// </remarks>\npublic abstract class CapTransactionBase : ICapTransaction\n{\n    private readonly ConcurrentQueue<MediumMessage> _bufferList;\n    private readonly IDispatcher _dispatcher;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"CapTransactionBase\"/> class with a dispatcher.\n    /// </summary>\n    /// <param name=\"dispatcher\">The dispatcher used to enqueue messages for publishing and execution.</param>\n    protected CapTransactionBase(IDispatcher dispatcher)\n    {\n        _dispatcher = dispatcher;\n        _bufferList = new ConcurrentQueue<MediumMessage>();\n    }\n\n    /// <summary>\n    /// Gets or sets a value indicating whether this transaction is automatically committed after a message is published.\n    /// When true, the transaction commits immediately; when false, manual commit is required.\n    /// </summary>\n    public bool AutoCommit { get; set; }\n\n    /// <summary>\n    /// Gets or sets the underlying database transaction object.\n    /// This can be cast to the specific database transaction type (e.g., SqlTransaction, NpgsqlTransaction) when needed.\n    /// </summary>\n    public virtual object? DbTransaction { get; set; }\n\n    /// <summary>\n    /// Commits the transaction synchronously, causing all buffered messages to be sent to the message queue.\n    /// </summary>\n    public abstract void Commit();\n\n    /// <summary>\n    /// Asynchronously commits the transaction, causing all buffered messages to be sent to the message queue.\n    /// </summary>\n    /// <param name=\"cancellationToken\">A token to monitor for cancellation requests.</param>\n    /// <returns>A task representing the asynchronous commit operation.</returns>\n    public abstract Task CommitAsync(CancellationToken cancellationToken = default);\n\n    /// <summary>\n    /// Rolls back the transaction synchronously, discarding all buffered messages without sending them.\n    /// </summary>\n    public abstract void Rollback();\n\n    /// <summary>\n    /// Asynchronously rolls back the transaction, discarding all buffered messages without sending them.\n    /// </summary>\n    /// <param name=\"cancellationToken\">A token to monitor for cancellation requests.</param>\n    /// <returns>A task representing the asynchronous rollback operation.</returns>\n    public abstract Task RollbackAsync(CancellationToken cancellationToken = default);\n\n    /// <summary>\n    /// Adds a message to the internal buffer queue to be sent when the transaction is committed.\n    /// This is typically called when publishing a message within a transaction context.\n    /// </summary>\n    /// <param name=\"msg\">The message to add to the buffer.</param>\n    protected internal virtual void AddToSent(MediumMessage msg)\n    {\n        _bufferList.Enqueue(msg);\n    }\n\n    /// <summary>\n    /// Synchronously flushes all buffered messages from the internal queue to the dispatcher.\n    /// This method blocks until all messages have been enqueued.\n    /// </summary>\n    protected virtual void Flush()\n    {\n        FlushAsync().ConfigureAwait(false).GetAwaiter().GetResult();\n    }\n\n    /// <summary>\n    /// Asynchronously flushes all buffered messages from the internal queue to the dispatcher.\n    /// Delayed messages are enqueued to the scheduler; immediate messages are enqueued for publishing.\n    /// </summary>\n    /// <returns>A task representing the asynchronous flush operation.</returns>\n    protected virtual async Task FlushAsync()\n    {\n        while (!_bufferList.IsEmpty)\n        {\n            if (_bufferList.TryDequeue(out var message))\n            {\n                var isDelayMessage = message.Origin.Headers.ContainsKey(Headers.DelayTime);\n                if (isDelayMessage)\n                {\n                    await _dispatcher.EnqueueToScheduler(message, DateTime.Parse(message.Origin.Headers[Headers.SentTime]!, CultureInfo.InvariantCulture)).ConfigureAwait(false);\n                }\n                else\n                {\n                    await _dispatcher.EnqueueToPublish(message).ConfigureAwait(false);\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    /// Disposes the transaction, releasing the underlying database transaction if it implements <see cref=\"IDisposable\"/>.\n    /// </summary>\n    public virtual void Dispose()\n    {\n        (DbTransaction as IDisposable)?.Dispose();\n        DbTransaction = null;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/ICapTransaction.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace DotNetCore.CAP;\n\n/// <summary>\n/// Represents a CAP transaction wrapper that coordinates message publishing with a database transaction.\n/// This interface provides a consistent API for managing outbox pattern implementations where messages\n/// must be published atomically with database changes.\n/// </summary>\n/// <remarks>\n/// The CAP transaction wrapper enables the reliable message delivery pattern by ensuring that:\n/// <list type=\"bullet\">\n/// <item><description>Messages are published only when the database transaction succeeds.</description></item>\n/// <item><description>Uncommitted messages are discarded if the transaction is rolled back.</description></item>\n/// <item><description>Different message brokers and databases can be supported through implementation-specific subclasses.</description></item>\n/// </list>\n/// Applications typically obtain an instance of this interface through dependency injection and associate it\n/// with a database transaction before publishing messages within that transaction.\n/// </remarks>\npublic interface ICapTransaction : IDisposable\n{\n    /// <summary>\n    /// Gets or sets a value indicating whether the transaction is automatically committed after a message is published.\n    /// When true, the transaction commits immediately upon message publishing; when false, manual commit is required.\n    /// </summary>\n    bool AutoCommit { get; set; }\n\n    /// <summary>\n    /// Gets or sets the underlying database transaction object.\n    /// Can be cast to specific database transaction types (e.g., SqlTransaction, NpgsqlTransaction, IDbTransaction)\n    /// for database-specific operations.\n    /// </summary>\n    object? DbTransaction { get; set; }\n\n    /// <summary>\n    /// Synchronously commits the transaction context, causing all buffered CAP messages to be sent to the message queue.\n    /// This must be called after publishing messages within a transaction to ensure they are delivered.\n    /// </summary>\n    void Commit();\n\n    /// <summary>\n    /// Asynchronously commits the transaction context, causing all buffered CAP messages to be sent to the message queue.\n    /// This must be called after publishing messages within a transaction to ensure they are delivered.\n    /// </summary>\n    /// <param name=\"cancellationToken\">A token to monitor for cancellation requests.</param>\n    /// <returns>A task representing the asynchronous commit operation.</returns>\n    Task CommitAsync(CancellationToken cancellationToken = default);\n\n    /// <summary>\n    /// Synchronously rolls back the transaction context, discarding all buffered CAP messages without sending them.\n    /// This cancels any messages that were queued but not yet committed.\n    /// </summary>\n    void Rollback();\n\n    /// <summary>\n    /// Asynchronously rolls back the transaction context, discarding all buffered CAP messages without sending them.\n    /// This cancels any messages that were queued but not yet committed.\n    /// </summary>\n    /// <param name=\"cancellationToken\">A token to monitor for cancellation requests.</param>\n    /// <returns>A task representing the asynchronous rollback operation.</returns>\n    Task RollbackAsync(CancellationToken cancellationToken = default);\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/ConsumerContext.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Persistence;\n\nnamespace DotNetCore.CAP.Internal;\n\n/// <summary>\n/// A context for consumers, it used to be provider wrapper of method description and received message.\n/// </summary>\npublic class ConsumerContext\n{\n    public ConsumerContext(ConsumerContext context)\n        : this(context.ConsumerDescriptor, context.MediumMessage)\n    {\n    }\n\n    /// <summary>\n    /// create a new instance of  <see cref=\"ConsumerContext\" /> .\n    /// </summary>\n    /// <param name=\"descriptor\">consumer method descriptor. </param>\n    /// <param name=\"message\"> received message.</param>\n    public ConsumerContext(ConsumerExecutorDescriptor descriptor, MediumMessage message)\n    {\n        ConsumerDescriptor = descriptor ?? throw new ArgumentNullException(nameof(descriptor));\n        MediumMessage = message ?? throw new ArgumentNullException(nameof(message));\n    }\n\n    /// <summary>\n    /// a descriptor of consumer information need to be performed.\n    /// </summary>\n    public ConsumerExecutorDescriptor ConsumerDescriptor { get; }\n\n    /// <summary>\n    /// consumer received message.\n    /// </summary>\n    public Message DeliverMessage => MediumMessage.Origin;\n\n    /// <summary>\n    /// consumer received medium message.\n    /// </summary>\n    public MediumMessage MediumMessage { get; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/ConsumerExecutedResult.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Collections.Generic;\n\nnamespace DotNetCore.CAP.Internal;\n\npublic class ConsumerExecutedResult\n{\n    public ConsumerExecutedResult(object? result, string msgId, string? callbackName, IDictionary<string, string?>? callbackHeader)\n    {\n        Result = result;\n        MessageId = msgId;\n        CallbackName = callbackName;\n        CallbackHeader = callbackHeader;\n    }\n\n    public object? Result { get; set; }\n\n    public string MessageId { get; set; }\n\n    public string? CallbackName { get; set; }\n\n    public IDictionary<string, string?>? CallbackHeader { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/ConsumerExecutorDescriptor.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing Microsoft.Extensions.Logging;\n\nnamespace DotNetCore.CAP.Internal;\n\n/// <summary>\n/// A descriptor of user definition method.\n/// </summary>\npublic class ConsumerExecutorDescriptor\n{\n    private string? _topicName;\n    public TypeInfo? ServiceTypeInfo { get; set; }\n\n    public MethodInfo MethodInfo { get; set; } = default!;\n\n    public TypeInfo ImplTypeInfo { get; set; } = default!;\n\n    public TopicAttribute Attribute { get; set; } = default!;\n\n    public TopicAttribute? ClassAttribute { get; set; }\n\n    public IList<ParameterDescriptor> Parameters { get; set; } = new List<ParameterDescriptor>();\n\n    public string? TopicNamePrefix { get; set; }\n\n    /// <summary>\n    /// Topic name based on both <see cref=\"Attribute\" /> and <see cref=\"ClassAttribute\" />.\n    /// </summary>\n    public string TopicName\n    {\n        get\n        {\n            if (_topicName == null)\n            {\n                if (ClassAttribute != null && Attribute.IsPartial)\n                    // Allows class level attribute name to end with a '.' and allows methods level attribute to start with a '.'.\n                    _topicName = $\"{ClassAttribute.Name.TrimEnd('.')}.{Attribute.Name.TrimStart('.')}\";\n                else\n                    _topicName = Attribute.Name;\n\n                if (!string.IsNullOrEmpty(TopicNamePrefix) && !string.IsNullOrEmpty(_topicName))\n                    _topicName = $\"{TopicNamePrefix}.{_topicName}\";\n            }\n\n            return _topicName;\n        }\n    }\n}\n\npublic class ConsumerExecutorDescriptorComparer : IEqualityComparer<ConsumerExecutorDescriptor>\n{\n    private readonly ILogger _logger;\n\n    public ConsumerExecutorDescriptorComparer(ILogger logger)\n    {\n        _logger = logger;\n    }\n\n    public bool Equals(ConsumerExecutorDescriptor? x, ConsumerExecutorDescriptor? y)\n    {\n        //Check whether the compared objects reference the same data.\n        if (ReferenceEquals(x, y))\n        {\n            _logger.ConsumerDuplicates(x!.TopicName, x.Attribute.Group);\n            return true;\n        }\n\n        //Check whether any of the compared objects is null.\n        if (x is null || y is null) return false;\n\n        //Check whether the ConsumerExecutorDescriptor' properties are equal.\n        var ret = x.TopicName.Equals(y.TopicName, StringComparison.OrdinalIgnoreCase) &&\n                  x.Attribute.Group.Equals(y.Attribute.Group, StringComparison.OrdinalIgnoreCase);\n\n        if (ret && (x.ImplTypeInfo != y.ImplTypeInfo || x.MethodInfo != y.MethodInfo)) _logger.ConsumerDuplicates(x.TopicName, x.Attribute.Group);\n\n        return ret;\n    }\n\n    public int GetHashCode(ConsumerExecutorDescriptor? obj)\n    {\n        //Check whether the object is null\n        if (obj is null) return 0;\n\n        //Get hash code for the Attribute Group field if it is not null.\n        var hashAttributeGroup = obj.Attribute?.Group == null ? 0 : obj.Attribute.Group.GetHashCode();\n\n        //Get hash code for the TopicName field.\n        var hashTopicName = obj.TopicName.GetHashCode();\n\n        //Calculate the hash code.\n        return hashAttributeGroup ^ hashTopicName;\n    }\n}\n\npublic class ParameterDescriptor\n{\n    public string Name { get; set; } = default!;\n\n    public Type ParameterType { get; set; } = default!;\n\n    public bool IsFromCap { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/Filter/ExceptionContext.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP.Internal;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP.Filter;\n\npublic class ExceptionContext : FilterContext\n{\n    public ExceptionContext(ConsumerContext context, Exception e)\n        : base(context)\n    {\n        Exception = e;\n    }\n\n    public Exception Exception { get; set; }\n\n    public bool ExceptionHandled { get; set; }\n\n    public object? Result { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/Filter/ExecutedContext.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing DotNetCore.CAP.Internal;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP.Filter;\n\npublic class ExecutedContext : FilterContext\n{\n    public ExecutedContext(ConsumerContext context, object? result) : base(context)\n    {\n        Result = result;\n    }\n\n    public object? Result { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/Filter/ExecutingContext.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing DotNetCore.CAP.Internal;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP.Filter;\n\npublic class ExecutingContext : FilterContext\n{\n    public ExecutingContext(ConsumerContext context, object?[] arguments) : base(context)\n    {\n        Arguments = arguments;\n    }\n\n    public object?[] Arguments { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/Filter/FilterContext.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing DotNetCore.CAP.Internal;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP.Filter;\n\npublic class FilterContext : ConsumerContext\n{\n    public FilterContext(ConsumerContext context) : base(context)\n    {\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/Filter/ISubscribeFilter.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\n// ReSharper disable once CheckNamespace\n\nusing System.Threading.Tasks;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP.Filter;\n\n/// <summary>\n/// A filter that surrounds execution of the subscriber.\n/// </summary>\npublic interface ISubscribeFilter\n{\n    /// <summary>\n    /// Called before the subscriber executes.\n    /// </summary>\n    /// <param name=\"context\">The <see cref=\"ExecutingContext\" />.</param>\n    Task OnSubscribeExecutingAsync(ExecutingContext context);\n\n    /// <summary>\n    /// Called after the subscriber executes.\n    /// </summary>\n    /// <param name=\"context\">The <see cref=\"ExecutedContext\" />.</param>\n    Task OnSubscribeExecutedAsync(ExecutedContext context);\n\n    /// <summary>\n    /// Called after the subscriber has thrown an <see cref=\"System.Exception\" />.\n    /// </summary>\n    /// <param name=\"context\">The <see cref=\"ExceptionContext\" />.</param>\n    Task OnSubscribeExceptionAsync(ExceptionContext context);\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/Filter/SubscribeFilter.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\n// ReSharper disable once CheckNamespace\n\nusing System.Threading.Tasks;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP.Filter;\n\n/// <summary>\n/// Abstract base class for ISubscribeFilter for use when implementing a subset of the interface methods.\n/// </summary>\npublic abstract class SubscribeFilter : ISubscribeFilter\n{\n    /// <summary>\n    /// Called before the subscriber executes.\n    /// </summary>\n    /// <param name=\"context\">The <see cref=\"ExecutingContext\" />.</param>\n    public virtual Task OnSubscribeExecutingAsync(ExecutingContext context)\n    {\n        return Task.CompletedTask;\n    }\n\n    /// <summary>\n    /// Called after the subscriber executes.\n    /// </summary>\n    /// <param name=\"context\">The <see cref=\"ExecutedContext\" />.</param>\n    public virtual Task OnSubscribeExecutedAsync(ExecutedContext context)\n    {\n        return Task.CompletedTask;\n    }\n\n    /// <summary>\n    /// Called after the subscriber has thrown an <see cref=\"System.Exception\" />.\n    /// </summary>\n    /// <param name=\"context\">The <see cref=\"ExceptionContext\" />.</param>\n    public virtual Task OnSubscribeExceptionAsync(ExceptionContext context)\n    {\n        return Task.CompletedTask;\n    }\n\n\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/Helper.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.ComponentModel;\nusing System.Linq;\nusing System.Net;\nusing System.Reflection;\nusing System.Runtime.ExceptionServices;\nusing System.Text.RegularExpressions;\n\nnamespace DotNetCore.CAP.Internal;\n\npublic static class Helper\n{\n    public static bool IsController(TypeInfo typeInfo)\n    {\n        if (!typeInfo.IsClass) return false;\n\n        if (typeInfo.IsAbstract) return false;\n\n        if (!typeInfo.IsPublic) return false;\n\n        if (typeInfo.ContainsGenericParameters) return false;\n\n        return !typeInfo.ContainsGenericParameters\n               && typeInfo.Name.EndsWith(\"Controller\", StringComparison.OrdinalIgnoreCase);\n    }\n\n    public static bool IsComplexType(Type type)\n    {\n        return !CanConvertFromString(type);\n    }\n\n    public static string WildcardToRegex(string wildcard)\n    {\n        if (wildcard.IndexOf('*') >= 0) return (\"^\" + wildcard + \"$\").Replace(\"*\", \"[0-9a-zA-Z]+\").Replace(\".\", \"\\\\.\");\n\n        if (wildcard.IndexOf('#') >= 0)\n            return (\"^\" + wildcard.Replace(\".\", \"\\\\.\") + \"$\").Replace(\"#\", \"[0-9a-zA-Z\\\\.]+\");\n\n        return wildcard;\n    }\n\n    public static string? GetInstanceHostname()\n    {\n        try\n        {\n            var hostName = Dns.GetHostName();\n            if (hostName.Length <= 50) return hostName;\n            return hostName.Substring(0, 50);\n        }\n        catch\n        {\n            return null;\n        }\n    }\n\n    public static string Normalized(string name)\n    {\n        if (string.IsNullOrEmpty(name)) return name;\n        var pattern = \"[\\\\>\\\\.\\\\ \\\\*]\";\n        return Regex.IsMatch(name, pattern) ? Regex.Replace(name, pattern, \"_\") : name;\n    }\n\n    public static bool IsUsingType<T>(in Type type)\n    {\n        var flags = BindingFlags.Public | BindingFlags.NonPublic |\n                    BindingFlags.Static | BindingFlags.Instance |\n                    BindingFlags.DeclaredOnly;\n        return type.GetFields(flags).Any(x => x.FieldType == typeof(T));\n    }\n\n    public static bool IsInnerIP(string ipAddress)\n    {\n        var ipNum = GetIpNum(ipAddress);\n\n        //Private IP：\n        //category A: 10.0.0.0-10.255.255.255\n        //category B: 172.16.0.0-172.31.255.255\n        //category C: 192.168.0.0-192.168.255.255  \n\n        var aBegin = GetIpNum(\"10.0.0.0\");\n        var aEnd = GetIpNum(\"10.255.255.255\");\n        var bBegin = GetIpNum(\"172.16.0.0\");\n        var bEnd = GetIpNum(\"172.31.255.255\");\n        var cBegin = GetIpNum(\"192.168.0.0\");\n        var cEnd = GetIpNum(\"192.168.255.255\");\n        return IsInner(ipNum, aBegin, aEnd) || IsInner(ipNum, bBegin, bEnd) || IsInner(ipNum, cBegin, cEnd);\n    }\n\n    private static long GetIpNum(string ipAddress)\n    {\n        var ip = ipAddress.Split('.');\n        long a = int.Parse(ip[0]);\n        long b = int.Parse(ip[1]);\n        long c = int.Parse(ip[2]);\n        long d = int.Parse(ip[3]);\n\n        var ipNum = a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d;\n        return ipNum;\n    }\n\n    private static bool IsInner(long userIp, long begin, long end)\n    {\n        return userIp >= begin && userIp <= end;\n    }\n\n    private static bool CanConvertFromString(Type destinationType)\n    {\n        destinationType = Nullable.GetUnderlyingType(destinationType) ?? destinationType;\n        return IsSimpleType(destinationType) ||\n               TypeDescriptor.GetConverter(destinationType).CanConvertFrom(typeof(string));\n    }\n\n    private static bool IsSimpleType(Type type)\n    {\n        return type.GetTypeInfo().IsPrimitive ||\n               type == typeof(decimal) ||\n               type == typeof(string) ||\n               type == typeof(DateTime) ||\n               type == typeof(Guid) ||\n               type == typeof(DateTimeOffset) ||\n               type == typeof(TimeSpan) ||\n               type == typeof(Uri);\n    }\n\n    internal static void ReThrow(this Exception exception)\n    {\n        ExceptionDispatchInfo.Capture(exception).Throw();\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/IBootstrapper.Default.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Persistence;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\n\nnamespace DotNetCore.CAP.Internal;\n\n/// <summary>\n/// Default implement of <see cref=\"T:DotNetCore.CAP.Internal.IBootstrapper\" />.\n/// </summary>\ninternal class Bootstrapper : BackgroundService, IBootstrapper\n{\n    private readonly ILogger<IBootstrapper> _logger;\n    private readonly IServiceProvider _serviceProvider;\n\n    private CancellationTokenSource? _cts;\n    private bool _disposed;\n    private IEnumerable<IProcessingServer> _processors = default!;\n\n    public bool IsStarted => !_cts?.IsCancellationRequested ?? false;\n\n    public Bootstrapper(IServiceProvider serviceProvider, ILogger<IBootstrapper> logger)\n    {\n        _serviceProvider = serviceProvider;\n        _logger = logger;\n    }\n\n    public async Task BootstrapAsync(CancellationToken cancellationToken = default)\n    {\n        if (_cts != null)\n        {\n            _logger.LogInformation(\"### CAP background task is already started!\");\n\n            return;\n        }\n\n        _logger.LogDebug(\"### CAP background task is starting.\");\n\n        _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);\n\n        CheckRequirement();\n\n        _processors = _serviceProvider.GetServices<IProcessingServer>();\n\n        try\n        {\n            await _serviceProvider.GetRequiredService<IStorageInitializer>().InitializeAsync(_cts.Token).ConfigureAwait(false);\n        }\n        catch (Exception e)\n        {\n            if (e is InvalidOperationException) throw;\n            _logger.LogError(e, \"Initializing the storage structure failed!\");\n        }\n\n        _cts.Token.Register(() =>\n        {\n            _logger.LogDebug(\"### CAP background task is stopping.\");\n\n\n            foreach (var item in _processors)\n                try\n                {\n                    item.Dispose();\n                }\n                catch (OperationCanceledException ex)\n                {\n                    _logger.ExpectedOperationCanceledException(ex);\n                }\n        });\n\n        await BootstrapCoreAsync().ConfigureAwait(false);\n\n        _disposed = false;\n        _logger.LogInformation(\"### CAP started!\");\n    }\n\n    protected virtual async Task BootstrapCoreAsync()\n    {\n        foreach (var item in _processors)\n        {\n            try\n            {\n                _cts!.Token.ThrowIfCancellationRequested();\n\n                await item.StartAsync(_cts!.Token);\n            }\n            catch (OperationCanceledException)\n            {\n                // ignore\n            }\n            catch (Exception ex)\n            {\n                _logger.ProcessorsStartedError(ex);\n            }\n        }\n    }\n\n    public override void Dispose()\n    {\n        if (_disposed) return;\n\n        _cts?.Cancel();\n        _cts?.Dispose();\n        _cts = null;\n        _disposed = true;\n    }\n\n    protected override async Task ExecuteAsync(CancellationToken stoppingToken)\n    {\n        await BootstrapAsync(stoppingToken).ConfigureAwait(false);\n    }\n\n    public override async Task StopAsync(CancellationToken cancellationToken)\n    {\n        _cts?.Cancel();\n\n        await base.StopAsync(cancellationToken).ConfigureAwait(false);\n    }\n\n    private void CheckRequirement()\n    {\n        var marker = _serviceProvider.GetService<CapMarkerService>();\n        if (marker == null)\n            throw new InvalidOperationException(\n                \"AddCap() must be added on the service collection.   eg: services.AddCap(...)\");\n\n        var messageQueueMarker = _serviceProvider.GetService<CapMessageQueueMakerService>();\n        if (messageQueueMarker == null)\n            throw new InvalidOperationException(\n                \"You must be config transport provider for CAP!\" + Environment.NewLine +\n                \"==================================================================================\" +\n                Environment.NewLine +\n                \"========   eg: services.AddCap( options => { options.UseRabbitMQ(...) }); ========\" +\n                Environment.NewLine +\n                \"==================================================================================\");\n\n        var databaseMarker = _serviceProvider.GetService<CapStorageMarkerService>();\n        if (databaseMarker == null)\n            throw new InvalidOperationException(\n                \"You must be config storage provider for CAP!\" + Environment.NewLine +\n                \"===================================================================================\" +\n                Environment.NewLine +\n                \"========   eg: services.AddCap( options => { options.UseSqlServer(...) }); ========\" +\n                Environment.NewLine +\n                \"===================================================================================\");\n    }\n\n    public ValueTask DisposeAsync()\n    {\n        Dispose();\n\n        return ValueTask.CompletedTask;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Globalization;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Diagnostics;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.Internal;\n\ninternal class CapPublisher : ICapPublisher\n{\n    // ReSharper disable once InconsistentNaming\n    protected static readonly DiagnosticListener s_diagnosticListener =\n        new(CapDiagnosticListenerNames.DiagnosticListenerName);\n\n    private readonly CapOptions _capOptions;\n    private readonly ISnowflakeId _snowflakeId;\n    private readonly IDispatcher _dispatcher;\n    private readonly IDataStorage _storage;\n\n    private readonly AsyncLocal<CapTransactionHolder> _asyncLocal;\n\n    public CapPublisher(IServiceProvider service)\n    {\n        ServiceProvider = service;\n        _dispatcher = service.GetRequiredService<IDispatcher>();\n        _storage = service.GetRequiredService<IDataStorage>();\n        _capOptions = service.GetRequiredService<IOptions<CapOptions>>().Value;\n        _snowflakeId = service.GetRequiredService<ISnowflakeId>();\n        _asyncLocal = new AsyncLocal<CapTransactionHolder>();\n    }\n\n    public IServiceProvider ServiceProvider { get; }\n\n    public ICapTransaction? Transaction\n    {\n        get => _asyncLocal.Value?.Transaction;\n        set\n        {\n            _asyncLocal.Value ??= new CapTransactionHolder();\n            _asyncLocal.Value.Transaction = value;\n        }\n    }\n\n    public async Task PublishAsync<T>(string name, T? value, IDictionary<string, string?> headers,\n        CancellationToken cancellationToken = default)\n    {\n        await PublishInternalAsync(name, value, headers, null, cancellationToken).ConfigureAwait(false);\n    }\n\n    public async Task PublishAsync<T>(string name, T? value, string? callbackName = null,\n        CancellationToken cancellationToken = default)\n    {\n        var headers = new Dictionary<string, string?>\n        {\n            { Headers.CallbackName, callbackName }\n        };\n        await PublishAsync(name, value, headers, cancellationToken).ConfigureAwait(false);\n    }\n\n    public async Task PublishDelayAsync<T>(TimeSpan delayTime, string name, T? value, IDictionary<string, string?> headers,\n        CancellationToken cancellationToken = default)\n    {\n        if (delayTime <= TimeSpan.Zero)\n        {\n            throw new ArgumentException(\"Delay time span must be greater than 0\", nameof(delayTime));\n        }\n\n        await PublishInternalAsync(name, value, headers, delayTime, cancellationToken).ConfigureAwait(false);\n    }\n\n    public async Task PublishDelayAsync<T>(TimeSpan delayTime, string name, T? value, string? callbackName = null,\n        CancellationToken cancellationToken = default)\n    {\n        var header = new Dictionary<string, string?>\n        {\n            { Headers.CallbackName, callbackName }\n        };\n\n        await PublishDelayAsync(delayTime, name, value, header, cancellationToken).ConfigureAwait(false);\n    }\n\n    public void Publish<T>(string name, T? value, string? callbackName = null)\n    {\n        PublishAsync(name, value, callbackName).ConfigureAwait(false).GetAwaiter().GetResult();\n    }\n\n    public void Publish<T>(string name, T? value, IDictionary<string, string?> headers)\n    {\n        PublishAsync(name, value, headers).ConfigureAwait(false).GetAwaiter().GetResult();\n    }\n\n    public void PublishDelay<T>(TimeSpan delayTime, string name, T? value, IDictionary<string, string?> headers)\n    {\n        PublishDelayAsync(delayTime, name, value, headers).ConfigureAwait(false).GetAwaiter().GetResult();\n    }\n\n    public void PublishDelay<T>(TimeSpan delayTime, string name, T? value, string? callbackName = null)\n    {\n        PublishDelayAsync(delayTime, name, value, callbackName).ConfigureAwait(false).GetAwaiter().GetResult();\n    }\n\n    private async Task PublishInternalAsync<T>(string name, T? value, IDictionary<string, string?> headers, TimeSpan? delayTime = null,\n        CancellationToken cancellationToken = default)\n    {\n        if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));\n\n        if (!string.IsNullOrEmpty(_capOptions.TopicNamePrefix)) name = $\"{_capOptions.TopicNamePrefix}.{name}\";\n\n        if (!headers.ContainsKey(Headers.MessageId))\n        {\n            var messageId = _snowflakeId.NextId().ToString();\n            headers.Add(Headers.MessageId, messageId);\n        }\n\n        if (!headers.ContainsKey(Headers.CorrelationId))\n        {\n            headers.Add(Headers.CorrelationId, headers[Headers.MessageId]);\n            headers.Add(Headers.CorrelationSequence, 0.ToString());\n        }\n\n        headers.Add(Headers.MessageName, name);\n        headers.Add(Headers.Type, typeof(T).Name);\n\n        var publishTime = DateTime.Now;\n        if (delayTime != null)\n        {\n            publishTime += delayTime.Value;\n            headers.Add(Headers.DelayTime, delayTime.Value.ToString());\n            headers.Add(Headers.SentTime, publishTime.ToString(CultureInfo.InvariantCulture));\n        }\n        else\n        {\n            headers.Add(Headers.SentTime, publishTime.ToString(CultureInfo.InvariantCulture));\n        }\n\n        var message = new Message(headers, value);\n\n        long? tracingTimestamp = null;\n        try\n        {\n            tracingTimestamp = TracingBefore(message);\n\n            if (Transaction?.DbTransaction == null)\n            {\n                var mediumMessage = await _storage.StoreMessageAsync(name, message).ConfigureAwait(false);\n\n                TracingAfter(tracingTimestamp, message);\n\n                if (delayTime != null)\n                {\n                    await _dispatcher.EnqueueToScheduler(mediumMessage, publishTime).ConfigureAwait(false);\n                }\n                else\n                {\n                    await _dispatcher.EnqueueToPublish(mediumMessage).ConfigureAwait(false);\n                }\n            }\n            else\n            {\n                var transaction = (CapTransactionBase)Transaction;\n\n                var mediumMessage = await _storage.StoreMessageAsync(name, message, transaction.DbTransaction).ConfigureAwait(false);\n\n                TracingAfter(tracingTimestamp, message);\n\n                transaction.AddToSent(mediumMessage);\n\n                if (transaction.AutoCommit) await transaction.CommitAsync(cancellationToken).ConfigureAwait(false);\n            }\n        }\n        catch (Exception e)\n        {\n            TracingError(tracingTimestamp, message, e);\n\n            throw;\n        }\n    }\n\n    #region tracing\n\n    private static long? TracingBefore(Message message)\n    {\n        if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.BeforePublishMessageStore))\n        {\n            var eventData = new CapEventDataPubStore\n            {\n                OperationTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),\n                Operation = message.GetName(),\n                Message = message\n            };\n\n            s_diagnosticListener.Write(CapDiagnosticListenerNames.BeforePublishMessageStore, eventData);\n\n            return eventData.OperationTimestamp;\n        }\n\n        return null;\n    }\n\n    private static void TracingAfter(long? tracingTimestamp, Message message)\n    {\n        if (tracingTimestamp != null &&\n            s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.AfterPublishMessageStore))\n        {\n            var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();\n            var eventData = new CapEventDataPubStore\n            {\n                OperationTimestamp = now,\n                Operation = message.GetName(),\n                Message = message,\n                ElapsedTimeMs = now - tracingTimestamp.Value\n            };\n\n            s_diagnosticListener.Write(CapDiagnosticListenerNames.AfterPublishMessageStore, eventData);\n        }\n    }\n\n    private static void TracingError(long? tracingTimestamp, Message message, Exception ex)\n    {\n        if (tracingTimestamp != null &&\n            s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.ErrorPublishMessageStore))\n        {\n            var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();\n            var eventData = new CapEventDataPubStore\n            {\n                OperationTimestamp = now,\n                Operation = message.GetName(),\n                Message = message,\n                ElapsedTimeMs = now - tracingTimestamp.Value,\n                Exception = ex\n            };\n\n            s_diagnosticListener.Write(CapDiagnosticListenerNames.ErrorPublishMessageStore, eventData);\n        }\n    }\n\n    #endregion\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Diagnostics;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Serialization;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.Internal;\n\ninternal class ConsumerRegister : IConsumerRegister\n{\n    // diagnostics listener\n    // ReSharper disable once InconsistentNaming\n    private static readonly DiagnosticListener s_diagnosticListener =\n        new(CapDiagnosticListenerNames.DiagnosticListenerName);\n\n    private readonly ILogger _logger;\n    private readonly CapOptions _options;\n    private readonly TimeSpan _pollingDelay = TimeSpan.FromSeconds(1);\n    private readonly IServiceProvider _serviceProvider;\n    private Task? _compositeTask;\n\n    private IConsumerClientFactory _consumerClientFactory = default!;\n    private CancellationTokenSource _cts = new();\n    private IDispatcher _dispatcher = default!;\n    private int _disposed;\n    private bool _isHealthy = true;\n\n    private MethodMatcherCache _selector = default!;\n    private ISerializer _serializer = default!;\n    private BrokerAddress _serverAddress;\n    private IDataStorage _storage = default!;\n\n    public ConsumerRegister(ILogger<ConsumerRegister> logger, IServiceProvider serviceProvider)\n    {\n        _logger = logger;\n        _serviceProvider = serviceProvider;\n        _options = serviceProvider.GetRequiredService<IOptions<CapOptions>>().Value;\n    }\n\n    public bool IsHealthy()\n    {\n        return _isHealthy;\n    }\n\n    public async ValueTask StartAsync(CancellationToken stoppingToken)\n    {\n        _cts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken);\n        _cts.Token.Register(Dispose);\n\n        _selector = _serviceProvider.GetRequiredService<MethodMatcherCache>();\n        _dispatcher = _serviceProvider.GetRequiredService<IDispatcher>();\n        _serializer = _serviceProvider.GetRequiredService<ISerializer>();\n        _storage = _serviceProvider.GetRequiredService<IDataStorage>();\n        _consumerClientFactory = _serviceProvider.GetRequiredService<IConsumerClientFactory>();\n\n        await ExecuteAsync();\n\n        _disposed = 0;\n    }\n\n    public async ValueTask ReStartAsync(bool force = false)\n    {\n        if (!IsHealthy() || force)\n        {\n            Pulse();\n\n            _cts = new CancellationTokenSource();\n            _isHealthy = true;\n\n            await ExecuteAsync();\n        }\n    }\n\n    public void Dispose()\n    {\n        if (Interlocked.CompareExchange(ref _disposed, 1, 0) == 1)\n            return;\n\n        try\n        {\n            Pulse();\n\n            _compositeTask?.Wait(TimeSpan.FromSeconds(2));\n        }\n        catch (AggregateException ex)\n        {\n            var innerEx = ex.InnerExceptions[0];\n            if (!(innerEx is OperationCanceledException)) _logger.ExpectedOperationCanceledException(innerEx);\n        }\n    }\n\n    public void Pulse()\n    {\n        _cts.Cancel();\n        _cts.Dispose();\n    }\n\n    public async ValueTask ExecuteAsync()\n    {\n        var groupingMatches = _selector.GetCandidatesMethodsOfGroupNameGrouped();\n\n        foreach (var matchGroup in groupingMatches)\n        {\n            ICollection<string> topics;\n            var limit = _selector.GetGroupConcurrentLimit(matchGroup.Key);\n            try\n            {\n                await using var client = await _consumerClientFactory.CreateAsync(matchGroup.Key, limit);\n                client.OnLogCallback = WriteLog;\n                topics = await client.FetchTopicsAsync(matchGroup.Value.Select(x => x.TopicName));\n            }\n            catch (BrokerConnectionException e)\n            {\n                _isHealthy = false;\n                _logger.LogError(e, e.Message);\n                return;\n            }\n\n            for (var i = 0; i < _options.ConsumerThreadCount; i++)\n            {\n                var topicIds = topics.Select(t => t);\n                _ = Task.Factory.StartNew(async () =>\n                  {\n                      try\n                      {\n                          await using var client = await _consumerClientFactory.CreateAsync(matchGroup.Key, limit);\n\n                          _serverAddress = client.BrokerAddress;\n\n                          RegisterMessageProcessor(client);\n\n                          await client.SubscribeAsync(topicIds);\n\n                          await client.ListeningAsync(_pollingDelay, _cts.Token);\n                      }\n                      catch (OperationCanceledException)\n                      {\n                          //ignore\n                      }\n                      catch (BrokerConnectionException e)\n                      {\n                          _isHealthy = false;\n                          _logger.LogError(e, e.Message);\n                      }\n                      catch (Exception e)\n                      {\n                          _logger.LogError(e, e.Message);\n                      }\n                  }, _cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);\n            }\n        }\n\n        _compositeTask = Task.CompletedTask;\n    }\n\n    private void RegisterMessageProcessor(IConsumerClient client)\n    {\n        client.OnLogCallback = WriteLog;\n        client.OnMessageCallback = async (transportMessage, sender) =>\n        {\n            long? tracingTimestamp = null;\n            try\n            {\n                _logger.MessageReceived(transportMessage.GetId(), transportMessage.GetName());\n\n                tracingTimestamp = TracingBefore(transportMessage, _serverAddress);\n\n                var name = transportMessage.GetName();\n                var group = transportMessage.GetGroup()!;\n\n                Message message;\n\n                var canFindSubscriber = _selector.TryGetTopicExecutor(name, group, out var executor);\n                try\n                {\n                    if (!canFindSubscriber)\n                    {\n                        var error =\n                            $\"Message can not be found subscriber. Name:{name}, Group:{group}. {Environment.NewLine} see: https://github.com/dotnetcore/CAP/issues/63\";\n                        var ex = new SubscriberNotFoundException(error);\n\n                        TracingError(tracingTimestamp, transportMessage, client.BrokerAddress, ex);\n\n                        throw ex;\n                    }\n\n                    var type = executor!.Parameters.FirstOrDefault(x => x.IsFromCap == false)?.ParameterType;\n                    message = await _serializer.DeserializeAsync(transportMessage, type);\n                    message.RemoveException();\n                }\n                catch (Exception e)\n                {\n                    transportMessage.Headers[Headers.Exception] = e.GetType().Name + \"-->\" + e.Message;\n                    string? dataUri;\n                    if (transportMessage.Headers.TryGetValue(Headers.Type, out var val))\n                    {\n                        if (transportMessage.Body.Length != 0)\n                            dataUri = $\"data:{val};base64,\" + Convert.ToBase64String(transportMessage.Body.Span);\n                        else\n                            dataUri = null;\n                        message = new Message(transportMessage.Headers, dataUri);\n                    }\n                    else\n                    {\n                        if (transportMessage.Body.Length != 0)\n                            dataUri = \"data:UnknownType;base64,\" + Convert.ToBase64String(transportMessage.Body.Span);\n                        else\n                            dataUri = null;\n                        message = new Message(transportMessage.Headers, dataUri);\n                    }\n                }\n\n                if (message.HasException())\n                {\n                    var content = _serializer.Serialize(message);\n\n                    await _storage.StoreReceivedExceptionMessageAsync(name, group, content);\n\n                    await client.CommitAsync(sender);\n\n                    try\n                    {\n                        _options.FailedThresholdCallback?.Invoke(new FailedInfo\n                        {\n                            ServiceProvider = _serviceProvider,\n                            MessageType = MessageType.Subscribe,\n                            Message = message\n                        });\n\n                        _logger.ConsumerExecutedAfterThreshold(message.GetId(), _options.FailedRetryCount);\n                    }\n                    catch (Exception e)\n                    {\n                        _logger.ExecutedThresholdCallbackFailed(e);\n                    }\n\n                    TracingAfter(tracingTimestamp, transportMessage, _serverAddress);\n                }\n                else\n                {\n                    var mediumMessage = await _storage.StoreReceivedMessageAsync(name, group, message);\n                    mediumMessage.Origin = message;\n\n                    TracingAfter(tracingTimestamp, transportMessage, _serverAddress);\n\n                    await _dispatcher.EnqueueToExecute(mediumMessage, executor!);\n\n                    await client.CommitAsync(sender);\n\n                }\n            }\n            catch (Exception e)\n            {\n                _logger.LogError(e, \"An exception occurred when process received message. Message:'{0}'.\",\n                    transportMessage);\n\n                await client.RejectAsync(sender);\n\n                TracingError(tracingTimestamp, transportMessage, client.BrokerAddress, e);\n            }\n        };\n    }\n\n    private void WriteLog(LogMessageEventArgs logmsg)\n    {\n        switch (logmsg.LogType)\n        {\n            case MqLogType.ConsumerCancelled:\n                _isHealthy = false;\n                _logger.LogWarning(\"RabbitMQ consumer cancelled. --> \" + logmsg.Reason);\n                break;\n            case MqLogType.ConsumerRegistered:\n                _isHealthy = true;\n                _logger.LogInformation(\"RabbitMQ consumer registered. --> \" + logmsg.Reason);\n                break;\n            case MqLogType.ConsumerUnregistered:\n                _logger.LogWarning(\"RabbitMQ consumer unregistered. --> \" + logmsg.Reason);\n                break;\n            case MqLogType.ConsumerShutdown:\n                _isHealthy = false;\n                _logger.LogWarning(\"RabbitMQ consumer shutdown. --> \" + logmsg.Reason);\n                break;\n            case MqLogType.ConsumeError:\n                _logger.LogError(\"Kafka client consume error. --> \" + logmsg.Reason);\n                break;\n            case MqLogType.ConsumeRetries:\n                _logger.LogWarning(\"Kafka client consume exception, retying... --> \" + logmsg.Reason);\n                break;\n            case MqLogType.ServerConnError:\n                _isHealthy = false;\n                _logger.LogCritical(\"Kafka server connection error. --> \" + logmsg.Reason);\n                break;\n            case MqLogType.ExceptionReceived:\n                _logger.LogError(\"AzureServiceBus subscriber received an error. --> \" + logmsg.Reason);\n                break;\n            case MqLogType.AsyncErrorEvent:\n                _logger.LogError(\"NATS subscriber received an error. --> \" + logmsg.Reason);\n                break;\n            case MqLogType.ConnectError:\n                _isHealthy = false;\n                _logger.LogError(\"NATS server connection error. -->  \" + logmsg.Reason);\n                break;\n            case MqLogType.InvalidIdFormat:\n                _logger.LogError(\n                    \"AmazonSQS subscriber delete inflight message failed, invalid id. --> \" + logmsg.Reason);\n                break;\n            case MqLogType.MessageNotInflight:\n                _logger.LogError(\n                    \"AmazonSQS subscriber change message's visibility failed, message isn't in flight. --> \" +\n                    logmsg.Reason);\n                break;\n            case MqLogType.RedisConsumeError:\n                _isHealthy = true;\n                _logger.LogError(\"Redis client consume error. --> {reason}\", logmsg.Reason);\n                break;\n            default:\n                throw new ArgumentOutOfRangeException();\n        }\n    }\n\n    #region tracing\n\n    private long? TracingBefore(TransportMessage message, BrokerAddress broker)\n    {\n        if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.BeforeConsume))\n        {\n            var eventData = new CapEventDataSubStore\n            {\n                OperationTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),\n                Operation = message.GetName(),\n                BrokerAddress = broker,\n                TransportMessage = message\n            };\n\n            s_diagnosticListener.Write(CapDiagnosticListenerNames.BeforeConsume, eventData);\n\n            return eventData.OperationTimestamp;\n        }\n\n        return null;\n    }\n\n    private void TracingAfter(long? tracingTimestamp, TransportMessage message, BrokerAddress broker)\n    {\n        CapEventCounterSource.Log.WriteConsumeMetrics();\n        if (tracingTimestamp != null && s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.AfterConsume))\n        {\n            var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();\n            var eventData = new CapEventDataSubStore\n            {\n                OperationTimestamp = now,\n                Operation = message.GetName(),\n                BrokerAddress = broker,\n                TransportMessage = message,\n                ElapsedTimeMs = now - tracingTimestamp.Value\n            };\n\n            s_diagnosticListener.Write(CapDiagnosticListenerNames.AfterConsume, eventData);\n        }\n    }\n\n    private void TracingError(long? tracingTimestamp, TransportMessage message, BrokerAddress broker, Exception ex)\n    {\n        if (tracingTimestamp != null && s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.ErrorConsume))\n        {\n            var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();\n\n            var eventData = new CapEventDataSubStore\n            {\n                OperationTimestamp = now,\n                Operation = message.GetName(),\n                BrokerAddress = broker,\n                TransportMessage = message,\n                ElapsedTimeMs = now - tracingTimestamp.Value,\n                Exception = ex\n            };\n\n            s_diagnosticListener.Write(CapDiagnosticListenerNames.ErrorConsume, eventData);\n        }\n    }\n\n    #endregion\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/IConsumerRegister.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Threading.Tasks;\n\nnamespace DotNetCore.CAP.Internal;\n\n/// <summary>\n/// Handler received message of subscribed.\n/// </summary>\npublic interface IConsumerRegister : IProcessingServer\n{\n    bool IsHealthy();\n\n    ValueTask ReStartAsync(bool force = false);\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Assembly.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\n\nnamespace DotNetCore.CAP.Internal;\n\n/// <inheritdoc />\n/// <summary>\n/// A <see cref=\"T:DotNetCore.CAP.Abstractions.IConsumerServiceSelector\" /> implementation that scanning subscribers from\n/// the assembly.\n/// </summary>\npublic class AssemblyConsumerServiceSelector : ConsumerServiceSelector\n{\n    private readonly Assembly[] _assemblies;\n\n    public AssemblyConsumerServiceSelector(IServiceProvider serviceProvider, Assembly[] assemblies) : base(\n        serviceProvider)\n    {\n        _assemblies = assemblies;\n    }\n\n    protected override IEnumerable<ConsumerExecutorDescriptor> FindConsumersFromInterfaceTypes(\n        IServiceProvider provider)\n    {\n        var descriptors = new List<ConsumerExecutorDescriptor>();\n\n        descriptors.AddRange(base.FindConsumersFromInterfaceTypes(provider));\n\n        var assembliesToScan = _assemblies.Distinct().ToArray();\n\n        var capSubscribeTypeInfo = typeof(ICapSubscribe).GetTypeInfo();\n\n        foreach (var type in assembliesToScan.SelectMany(a => a.DefinedTypes))\n        {\n            if (!capSubscribeTypeInfo.IsAssignableFrom(type)) continue;\n\n            descriptors.AddRange(GetTopicAttributesDescription(type));\n        }\n\n        return descriptors;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Text.RegularExpressions;\nusing System.Threading;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.Internal;\n\n/// <inheritdoc />\n/// <summary>\n/// A default <see cref=\"T:DotNetCore.CAP.Abstractions.IConsumerServiceSelector\" /> implementation.\n/// </summary>\npublic class ConsumerServiceSelector : IConsumerServiceSelector\n{\n    /// <summary>\n    /// since this class be designed as a Singleton service,the following two list must be thread safe!\n    /// </summary>\n    private readonly ConcurrentDictionary<string, List<RegexExecuteDescriptor<ConsumerExecutorDescriptor>>> _cacheList;\n\n    private readonly CapOptions _capOptions;\n    private readonly ILogger<ConsumerServiceSelector> _logger;\n    private readonly IServiceProvider _serviceProvider;\n\n    /// <summary>\n    /// Creates a new <see cref=\"ConsumerServiceSelector\" />.\n    /// </summary>\n    public ConsumerServiceSelector(IServiceProvider serviceProvider)\n    {\n        _serviceProvider = serviceProvider;\n        _capOptions = serviceProvider.GetRequiredService<IOptions<CapOptions>>().Value;\n        _logger = serviceProvider.GetRequiredService<ILogger<ConsumerServiceSelector>>();\n        _cacheList = new ConcurrentDictionary<string, List<RegexExecuteDescriptor<ConsumerExecutorDescriptor>>>();\n    }\n\n    public IReadOnlyList<ConsumerExecutorDescriptor> SelectCandidates()\n    {\n        var executorDescriptorList = new List<ConsumerExecutorDescriptor>();\n\n        executorDescriptorList.AddRange(FindConsumersFromInterfaceTypes(_serviceProvider));\n\n        executorDescriptorList.AddRange(FindConsumersFromControllerTypes());\n\n        executorDescriptorList =\n            executorDescriptorList.Distinct(new ConsumerExecutorDescriptorComparer(_logger)).ToList();\n\n        return executorDescriptorList;\n    }\n\n    public ConsumerExecutorDescriptor? SelectBestCandidate(string key,\n        IReadOnlyList<ConsumerExecutorDescriptor> executeDescriptor)\n    {\n        if (executeDescriptor.Count == 0) return null;\n\n        var result = MatchUsingName(key, executeDescriptor);\n        if (result != null) return result;\n\n        //[*] match with regex, i.e.  foo.*.abc\n        //[#] match regex, i.e. foo.#\n        return MatchWildcardUsingRegex(key, executeDescriptor);\n    }\n\n    protected virtual IEnumerable<ConsumerExecutorDescriptor> FindConsumersFromInterfaceTypes(IServiceProvider provider)\n    {\n        // Single-pass scan over service registrations to discover ICapSubscribe implementations (keyed & non-keyed)\n        var results = new List<ConsumerExecutorDescriptor>();\n        var subscribeTypeInfo = typeof(ICapSubscribe).GetTypeInfo();\n\n        using var scope = provider.CreateScope();\n        var scopeProvider = scope.ServiceProvider;\n        var serviceCollection = scopeProvider.GetRequiredService<IServiceCollection>();\n\n        foreach (var service in serviceCollection)\n        {\n            Type detectType;\n            Type? actualType = null;\n\n            if (service.IsKeyedService)\n            {\n                // Fast skip for keyed services\n                var hasKeyedImpl = service.KeyedImplementationType != null || service.KeyedImplementationFactory != null;\n                if (!hasKeyedImpl)\n                    continue;\n\n                detectType = service.KeyedImplementationType ?? service.ServiceType;\n                if (!subscribeTypeInfo.IsAssignableFrom(detectType))\n                    continue;\n\n                actualType = service.KeyedImplementationType;\n                if (actualType == null && service.KeyedImplementationFactory != null)\n                {\n                    // Resolve keyed instance to get its runtime type\n                    var instance = scopeProvider.GetRequiredKeyedService(service.ServiceType, service.ServiceKey);\n                    actualType = instance?.GetType();\n                }\n            }\n            else\n            {\n                // Fast skip for non-keyed services\n                var hasImpl = service.ImplementationType != null || service.ImplementationFactory != null;\n                if (!hasImpl)\n                    continue;\n\n                detectType = service.ImplementationType ?? service.ServiceType;\n                if (!subscribeTypeInfo.IsAssignableFrom(detectType))\n                    continue;\n\n                actualType = service.ImplementationType;\n                if (actualType == null && service.ImplementationFactory != null)\n                {\n                    // Resolve instance produced by factory to inspect runtime type\n                    var instance = scopeProvider.GetRequiredService(service.ServiceType);\n                    actualType = instance?.GetType();\n                }\n            }\n\n            if (actualType == null)\n            {\n                // Consistent error message for diagnostic purposes\n                throw new InvalidOperationException($\"Unable to resolve actual subscriber type for service: {service.ServiceType.FullName}\");\n            }\n\n            var serviceTypeInfo = service.ServiceType.GetTypeInfo();\n            results.AddRange(GetTopicAttributesDescription(actualType.GetTypeInfo(), serviceTypeInfo));\n        }\n\n        return results;\n    }\n\n    protected virtual IEnumerable<ConsumerExecutorDescriptor> FindConsumersFromControllerTypes()\n    {\n        var executorDescriptorList = new List<ConsumerExecutorDescriptor>();\n\n        var types = Assembly.GetEntryAssembly()!.ExportedTypes;\n        foreach (var type in types)\n        {\n            var typeInfo = type.GetTypeInfo();\n            if (Helper.IsController(typeInfo)) executorDescriptorList.AddRange(GetTopicAttributesDescription(typeInfo));\n        }\n\n        return executorDescriptorList;\n    }\n\n    protected IEnumerable<ConsumerExecutorDescriptor> GetTopicAttributesDescription(TypeInfo typeInfo,\n        TypeInfo? serviceTypeInfo = null)\n    {\n        var topicClassAttribute = typeInfo.GetCustomAttribute<TopicAttribute>(true);\n\n        foreach (var method in typeInfo.GetRuntimeMethods())\n        {\n            var topicMethodAttributes = method.GetCustomAttributes<TopicAttribute>(true);\n\n            // Ignore partial attributes when no topic attribute is defined on class.\n            if (topicClassAttribute is null)\n                topicMethodAttributes = topicMethodAttributes.Where(x => !x.IsPartial && x.Name != null);\n\n            if (!topicMethodAttributes.Any()) continue;\n\n            foreach (var attr in topicMethodAttributes)\n            {\n                SetSubscribeAttribute(attr);\n\n                var parameters = method.GetParameters()\n                    .Select(parameter => new ParameterDescriptor\n                    {\n                        Name = parameter.Name!,\n                        ParameterType = parameter.ParameterType,\n                        IsFromCap = parameter.GetCustomAttributes(typeof(FromCapAttribute)).Any()\n                                    || typeof(CancellationToken).IsAssignableFrom(parameter.ParameterType)\n                    }).ToList();\n\n                yield return InitDescriptor(attr, method, typeInfo, serviceTypeInfo, parameters, topicClassAttribute);\n            }\n        }\n    }\n\n    protected virtual void SetSubscribeAttribute(TopicAttribute attribute)\n    {\n        var prefix = !string.IsNullOrEmpty(_capOptions.GroupNamePrefix)\n           ? $\"{_capOptions.GroupNamePrefix}.\"\n           : string.Empty;\n\n        if (attribute.Group == null && attribute.GroupConcurrent > 0)\n        {\n            attribute.Group = $\"{prefix}{attribute.Name}.{_capOptions.Version}\";\n        }\n        else\n        {\n            attribute.Group = $\"{prefix}{attribute.Group ?? _capOptions.DefaultGroupName}.{_capOptions.Version}\";\n        }\n    }\n\n    private ConsumerExecutorDescriptor InitDescriptor(\n        TopicAttribute attr,\n        MethodInfo methodInfo,\n        TypeInfo implType,\n        TypeInfo? serviceTypeInfo,\n        IList<ParameterDescriptor> parameters,\n        TopicAttribute? classAttr = null)\n    {\n        var descriptor = new ConsumerExecutorDescriptor\n        {\n            Attribute = attr,\n            ClassAttribute = classAttr,\n            MethodInfo = methodInfo,\n            ImplTypeInfo = implType,\n            ServiceTypeInfo = serviceTypeInfo,\n            Parameters = parameters,\n            TopicNamePrefix = _capOptions.TopicNamePrefix\n        };\n\n        return descriptor;\n    }\n\n    private static ConsumerExecutorDescriptor? MatchUsingName(string key,\n        IReadOnlyList<ConsumerExecutorDescriptor> executeDescriptor)\n    {\n        ArgumentNullException.ThrowIfNull(key);\n\n        return executeDescriptor.FirstOrDefault(x =>\n            x.TopicName.Equals(key, StringComparison.InvariantCultureIgnoreCase));\n    }\n\n    private ConsumerExecutorDescriptor? MatchWildcardUsingRegex(string key,\n        IReadOnlyList<ConsumerExecutorDescriptor> executeDescriptor)\n    {\n        var group = executeDescriptor[0].Attribute.Group;\n        if (!_cacheList.TryGetValue(group, out var tmpList))\n        {\n            tmpList = executeDescriptor.Select(x => new RegexExecuteDescriptor<ConsumerExecutorDescriptor>\n            {\n                Name = Helper.WildcardToRegex(x.TopicName),\n                Descriptor = x\n            }).ToList();\n            _cacheList.TryAdd(group, tmpList);\n        }\n\n        foreach (var red in tmpList)\n            if (Regex.IsMatch(key, red.Name, RegexOptions.Singleline))\n                return red.Descriptor;\n\n        return null;\n    }\n\n    private class RegexExecuteDescriptor<T>\n    {\n        public string Name { get; set; } = default!;\n\n        public T Descriptor { get; set; } = default!;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/IConsumerServiceSelector.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Collections.Generic;\n\nnamespace DotNetCore.CAP.Internal;\n\n/// <summary>\n/// Defines an interface for selecting an consumer service method to invoke for the current message.\n/// </summary>\npublic interface IConsumerServiceSelector\n{\n    /// <summary>\n    /// Selects a set of <see cref=\"ConsumerExecutorDescriptor\" /> candidates for the current message associated with\n    /// </summary>\n    /// <returns>A set of <see cref=\"ConsumerExecutorDescriptor\" /> candidates or <c>null</c>.</returns>\n    IReadOnlyList<ConsumerExecutorDescriptor> SelectCandidates();\n\n    /// <summary>\n    /// Selects the best <see cref=\"ConsumerExecutorDescriptor\" /> candidate from <paramref name=\"candidates\" /> for the\n    /// current message associated.\n    /// </summary>\n    /// <param name=\"key\">topic or exchange router key.</param>\n    /// <param name=\"candidates\">the set of <see cref=\"ConsumerExecutorDescriptor\" /> candidates.</param>\n    ConsumerExecutorDescriptor? SelectBestCandidate(string key, IReadOnlyList<ConsumerExecutorDescriptor> candidates);\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/IMessageSender.Default.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Diagnostics;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Diagnostics;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Serialization;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.Internal;\n\ninternal class MessageSender : IMessageSender\n{\n    // ReSharper disable once InconsistentNaming\n    protected static readonly DiagnosticListener s_diagnosticListener =\n        new(CapDiagnosticListenerNames.DiagnosticListenerName);\n\n    private readonly IDataStorage _dataStorage;\n    private readonly ILogger _logger;\n    private readonly IOptions<CapOptions> _options;\n    private readonly ISerializer _serializer;\n    private readonly IServiceProvider _serviceProvider;\n    private readonly ITransport _transport;\n\n    public MessageSender(\n        ILogger<MessageSender> logger,\n        IServiceProvider serviceProvider)\n    {\n        _logger = logger;\n        _serviceProvider = serviceProvider;\n\n        _options = serviceProvider.GetRequiredService<IOptions<CapOptions>>();\n        _dataStorage = serviceProvider.GetRequiredService<IDataStorage>();\n        _serializer = serviceProvider.GetRequiredService<ISerializer>();\n        _transport = serviceProvider.GetRequiredService<ITransport>();\n    }\n\n    public async Task<OperateResult> SendAsync(MediumMessage message)\n    {\n        bool retry;\n        OperateResult result;\n        do\n        {\n            (retry, result) = await SendWithoutRetryAsync(message).ConfigureAwait(false);\n            if (result.Equals(OperateResult.Success)) return result;\n        } while (retry);\n\n        return result;\n    }\n\n    private async Task<(bool, OperateResult)> SendWithoutRetryAsync(MediumMessage message)\n    {\n        var transportMsg = await _serializer.SerializeAsync(message.Origin).ConfigureAwait(false);\n\n        var tracingTimestamp = TracingBefore(transportMsg, _transport.BrokerAddress);\n\n        var result = await _transport.SendAsync(transportMsg).ConfigureAwait(false);\n\n        if (result.Succeeded)\n        {\n            await SetSuccessfulState(message).ConfigureAwait(false);\n\n            TracingAfter(tracingTimestamp, transportMsg, _transport.BrokerAddress);\n\n            return (false, OperateResult.Success);\n        }\n\n        TracingError(tracingTimestamp, transportMsg, _transport.BrokerAddress, result);\n\n        var needRetry = await SetFailedState(message, result.Exception!).ConfigureAwait(false);\n\n        return (needRetry, OperateResult.Failed(result.Exception!));\n    }\n\n    private async Task SetSuccessfulState(MediumMessage message)\n    {\n        message.ExpiresAt = DateTime.Now.AddSeconds(_options.Value.SucceedMessageExpiredAfter);\n        await _dataStorage.ChangePublishStateAsync(message, StatusName.Succeeded).ConfigureAwait(false);\n    }\n\n    private async Task<bool> SetFailedState(MediumMessage message, Exception ex)\n    {\n        var needRetry = UpdateMessageForRetry(message);\n\n        message.Origin.AddOrUpdateException(ex);\n        message.ExpiresAt = message.Added.AddSeconds(_options.Value.FailedMessageExpiredAfter);\n\n        await _dataStorage.ChangePublishStateAsync(message, StatusName.Failed).ConfigureAwait(false);\n\n        return needRetry;\n    }\n\n    private bool UpdateMessageForRetry(MediumMessage message)\n    {\n        var retries = ++message.Retries;\n        var retryCount = Math.Min(_options.Value.FailedRetryCount, 3);\n        if (retries >= retryCount)\n        {\n            if (retries == _options.Value.FailedRetryCount)\n                try\n                {\n                    _options.Value.FailedThresholdCallback?.Invoke(new FailedInfo\n                    {\n                        ServiceProvider = _serviceProvider,\n                        MessageType = MessageType.Publish,\n                        Message = message.Origin\n                    });\n\n                    _logger.SenderAfterThreshold(message.DbId, _options.Value.FailedRetryCount);\n                }\n                catch (Exception ex)\n                {\n                    _logger.ExecutedThresholdCallbackFailed(ex);\n                }\n\n            return false;\n        }\n\n        _logger.SenderRetrying(message.DbId, retries);\n\n        return true;\n    }\n\n    #region tracing\n\n    private long? TracingBefore(TransportMessage message, BrokerAddress broker)\n    {\n        CapEventCounterSource.Log.WritePublishMetrics();\n\n        if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.BeforePublish))\n        {\n            var eventData = new CapEventDataPubSend\n            {\n                OperationTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),\n                Operation = message.GetName(),\n                BrokerAddress = broker,\n                TransportMessage = message\n            };\n\n            s_diagnosticListener.Write(CapDiagnosticListenerNames.BeforePublish, eventData);\n\n            return eventData.OperationTimestamp;\n        }\n\n        return null;\n    }\n\n    private void TracingAfter(long? tracingTimestamp, TransportMessage message, BrokerAddress broker)\n    {\n        if (tracingTimestamp != null && s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.AfterPublish))\n        {\n            var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();\n            var eventData = new CapEventDataPubSend\n            {\n                OperationTimestamp = now,\n                Operation = message.GetName(),\n                BrokerAddress = broker,\n                TransportMessage = message,\n                ElapsedTimeMs = now - tracingTimestamp.Value\n            };\n\n            s_diagnosticListener.Write(CapDiagnosticListenerNames.AfterPublish, eventData);\n        }\n    }\n\n    private void TracingError(long? tracingTimestamp, TransportMessage message, BrokerAddress broker,\n        OperateResult result)\n    {\n        if (tracingTimestamp != null && s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.ErrorPublish))\n        {\n            var ex = new PublisherSentFailedException(result.ToString(), result.Exception);\n            var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();\n\n            var eventData = new CapEventDataPubSend\n            {\n                OperationTimestamp = now,\n                Operation = message.GetName(),\n                BrokerAddress = broker,\n                TransportMessage = message,\n                ElapsedTimeMs = now - tracingTimestamp.Value,\n                Exception = ex\n            };\n\n            s_diagnosticListener.Write(CapDiagnosticListenerNames.ErrorPublish, eventData);\n        }\n    }\n\n    #endregion\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/IMessageSender.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Persistence;\n\nnamespace DotNetCore.CAP.Internal;\n\npublic interface IMessageSender\n{\n    Task<OperateResult> SendAsync(MediumMessage message);\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/IProcessingServer.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace DotNetCore.CAP.Internal;\n\n/// <inheritdoc />\n/// <summary>\n/// A process thread abstract of message process.\n/// </summary>\npublic interface IProcessingServer : IDisposable\n{\n    ValueTask StartAsync(CancellationToken stoppingToken);\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/ISnowflakeId.Default.cs",
    "content": "﻿// Copyright 2010-2012 Twitter, Inc.\n// An object that generates IDs. This is broken into a separate class in case we ever want to support multiple worker threads per process\n\nusing System;\nusing System.Linq;\nusing System.Net.NetworkInformation;\nusing System.Threading;\n\nnamespace DotNetCore.CAP.Internal;\n\npublic class SnowflakeId : ISnowflakeId\n{\n    /// <summary>\n    /// Start time 2010-11-04 09:42:54\n    /// </summary>\n    public const long Twepoch = 1288834974657L;\n\n    /// <summary>\n    /// The number of bits occupied by workerId\n    /// </summary>\n    private const int WorkerIdBits = 10;\n\n    /// <summary>\n    /// The number of bits occupied by timestamp\n    /// </summary>\n    private const int TimestampBits = 41;\n\n    /// <summary>\n    /// The number of bits occupied by sequence\n    /// </summary>\n    private const int SequenceBits = 12;\n\n    /// <summary>\n    /// Maximum supported machine id, the result is 1023\n    /// </summary>\n    private const int MaxWorkerId = ~(-1 << WorkerIdBits);\n\n    /// <summary>\n    /// mask that help to extract timestamp and sequence from a long\n    /// </summary>\n    private const long TimestampAndSequenceMask = ~(-1L << (TimestampBits + SequenceBits));\n\n    private readonly object _lock = new();\n\n    /// <summary>\n    /// timestamp and sequence mix in one Long\n    /// highest 11 bit: not used\n    /// middle  41 bit: timestamp\n    /// lowest  12 bit: sequence\n    /// </summary>\n    private long _timestampAndSequence;\n\n    public SnowflakeId()\n    {\n        if (!long.TryParse(Environment.GetEnvironmentVariable(\"CAP_WORKERID\"), out var workerId))\n            workerId = Util.GenerateWorkerId(MaxWorkerId);\n\n        Initialize(workerId);\n    }\n\n    public SnowflakeId(long workerId)\n    {\n        Initialize(workerId);\n    }\n\n    /// <summary>\n    /// business meaning: machine ID (0 ~ 1023)\n    /// actual layout in memory:\n    /// highest 1 bit: 0\n    /// middle 10 bit: workerId\n    /// lowest 53 bit: all 0\n    /// </summary>\n    private long WorkerId { get; set; }\n\n    public virtual long NextId()\n    {\n        lock (_lock)\n        {\n            WaitIfNecessary();\n            var timestampWithSequence = _timestampAndSequence & TimestampAndSequenceMask;\n            return WorkerId | timestampWithSequence;\n        }\n    }\n\n    /// <summary>\n    /// init first timestamp and sequence immediately\n    /// </summary>\n    private void InitTimestampAndSequence()\n    {\n        var timestamp = GetNewestTimestamp();\n        var timestampWithSequence = timestamp << SequenceBits;\n        _timestampAndSequence = timestampWithSequence;\n    }\n\n    /// <summary>\n    /// block current thread if the QPS of acquiring UUID is too high\n    /// that current sequence space is exhausted\n    /// </summary>\n    private void WaitIfNecessary()\n    {\n        var currentWithSequence = ++_timestampAndSequence;\n        var current = currentWithSequence >> SequenceBits;\n        var newest = GetNewestTimestamp();\n\n        if (current >= newest) Thread.Sleep(5);\n    }\n\n    /// <summary>\n    /// Common method for initializing <see cref=\"SnowflakeId\"/>\n    /// </summary>\n    /// <param name=\"workerId\"></param>\n    /// <exception cref=\"ArgumentException\"></exception>\n    private void Initialize(long workerId)\n    {\n        InitTimestampAndSequence();\n        // sanity check for workerId\n        if (workerId is > MaxWorkerId or < 0)\n            throw new ArgumentException($\"worker Id can't be greater than {MaxWorkerId} or less than 0\");\n\n        WorkerId = workerId << (TimestampBits + SequenceBits);\n    }\n\n    /// <summary>\n    /// get newest timestamp relative to twepoch\n    /// </summary>\n    /// <returns></returns>\n    private static long GetNewestTimestamp()\n    {\n        return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - Twepoch;\n    }\n}\n\ninternal static class Util\n{\n    /// <summary>\n    /// auto generate workerId, try using mac first, if failed, then randomly generate one\n    /// </summary>\n    /// <returns>workerId</returns>\n    public static long GenerateWorkerId(int maxWorkerId)\n    {\n        try\n        {\n            return GenerateWorkerIdBaseOnMac();\n        }\n        catch\n        {\n            return GenerateRandomWorkerId(maxWorkerId);\n        }\n    }\n\n    /// <summary>\n    /// use lowest 10 bit of available MAC as workerId\n    /// </summary>\n    /// <returns>workerId</returns>\n    private static long GenerateWorkerIdBaseOnMac()\n    {\n        NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();\n        //exclude virtual and Loopback\n        var firstUpInterface = nics.OrderByDescending(x => x.Speed).FirstOrDefault(x =>\n            !x.Description.Contains(\"Virtual\") && x.NetworkInterfaceType != NetworkInterfaceType.Loopback &&\n            x.OperationalStatus == OperationalStatus.Up);\n        if (firstUpInterface == null) throw new Exception(\"no available mac found\");\n        var address = firstUpInterface.GetPhysicalAddress();\n        var mac = address.GetAddressBytes();\n\n        return ((mac[4] & 0B11) << 8) | (mac[5] & 0xFF);\n    }\n\n    /// <summary>\n    /// randomly generate one as workerId\n    /// </summary>\n    /// <returns></returns>\n    private static long GenerateRandomWorkerId(int maxWorkerId)\n    {\n        return new Random().Next(maxWorkerId + 1);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/ISnowflakeId.cs",
    "content": "// Copyright 2010-2012 Twitter, Inc.\n// An object that generates IDs. This is broken into a separate class in case we ever want to support multiple worker threads per process\n\nnamespace DotNetCore.CAP.Internal;\n\npublic interface ISnowflakeId\n{\n    long NextId();\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/ISubscribeExector.Default.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Reflection;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Diagnostics;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Persistence;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.Internal;\n\ninternal class SubscribeExecutor : ISubscribeExecutor\n{\n    // diagnostics listener\n    // ReSharper disable once InconsistentNaming\n    private static readonly DiagnosticListener s_diagnosticListener =\n        new(CapDiagnosticListenerNames.DiagnosticListenerName);\n\n    private readonly IDataStorage _dataStorage;\n    private readonly string? _hostName;\n    private readonly ILogger _logger;\n    private readonly CapOptions _options;\n    private readonly IServiceProvider _provider;\n\n    public SubscribeExecutor(\n        ILogger<SubscribeExecutor> logger,\n        IOptions<CapOptions> options,\n        IServiceProvider provider)\n    {\n        _provider = provider;\n        _logger = logger;\n        _options = options.Value;\n\n        _dataStorage = _provider.GetRequiredService<IDataStorage>();\n        Invoker = _provider.GetRequiredService<ISubscribeInvoker>();\n        _hostName = Helper.GetInstanceHostname();\n    }\n\n    private ISubscribeInvoker Invoker { get; }\n\n    public async Task<OperateResult> ExecuteAsync(MediumMessage message, ConsumerExecutorDescriptor? descriptor = null, CancellationToken cancellationToken = default)\n    {\n        if (descriptor == null)\n        {\n            var selector = _provider.GetRequiredService<MethodMatcherCache>();\n            if (!selector.TryGetTopicExecutor(message.Origin.GetName(), message.Origin.GetGroup()!, out descriptor))\n            {\n                var error =\n                    $\"Message (Name:{message.Origin.GetName()},Group:{message.Origin.GetGroup()}) can not be found subscriber.\" +\n                    $\"{Environment.NewLine} see: https://github.com/dotnetcore/CAP/issues/63\";\n                _logger.LogError(error);\n\n                TracingError(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), message.Origin, null, new Exception(error));\n\n                var ex = new SubscriberNotFoundException(error);\n                await SetFailedState(message, ex);\n                return OperateResult.Failed(ex);\n            }\n        }\n\n        bool retry;\n        OperateResult result;\n\n        //record instance id\n        message.Origin.Headers[Headers.ExecutionInstanceId] = _hostName;\n\n        do\n        {\n            var (shouldRetry, operateResult) = await ExecuteWithoutRetryAsync(message, descriptor, cancellationToken).ConfigureAwait(false);\n            result = operateResult;\n            if (result.Equals(OperateResult.Success)) return result;\n            retry = shouldRetry;\n        } while (retry);\n\n        return result;\n    }\n\n    private async Task<(bool, OperateResult)> ExecuteWithoutRetryAsync(MediumMessage message,\n        ConsumerExecutorDescriptor descriptor, CancellationToken cancellationToken)\n    {\n        if (message == null) throw new ArgumentNullException(nameof(message));\n\n        cancellationToken.ThrowIfCancellationRequested();\n\n        try\n        {\n            _logger.ConsumerExecuting(descriptor.ImplTypeInfo.Name, descriptor.MethodInfo.Name,\n                descriptor.Attribute.Group);\n\n            var sp = Stopwatch.StartNew();\n\n            await InvokeConsumerMethodAsync(message, descriptor, cancellationToken).ConfigureAwait(false);\n\n            sp.Stop();\n\n            await SetSuccessfulState(message).ConfigureAwait(false);\n\n            CapEventCounterSource.Log.WriteInvokeTimeMetrics(sp.Elapsed.TotalMilliseconds);\n            _logger.ConsumerExecuted(descriptor.ImplTypeInfo.Name, descriptor.MethodInfo.Name,\n                descriptor.Attribute.Group, sp.Elapsed.TotalMilliseconds, message.Origin.GetExecutionInstanceId());\n\n            return (false, OperateResult.Success);\n        }\n        catch (Exception ex)\n        {\n            _logger.ConsumerExecuteFailed(message.Origin.GetName(), message.DbId,\n                message.Origin.GetExecutionInstanceId(), ex);\n\n            return (await SetFailedState(message, ex).ConfigureAwait(false), OperateResult.Failed(ex));\n        }\n    }\n\n    private Task SetSuccessfulState(MediumMessage message)\n    {\n        message.ExpiresAt = DateTime.Now.AddSeconds(_options.SucceedMessageExpiredAfter);\n\n        return _dataStorage.ChangeReceiveStateAsync(message, StatusName.Succeeded);\n    }\n\n    private async Task<bool> SetFailedState(MediumMessage message, Exception ex)\n    {\n        if (ex is SubscriberNotFoundException)\n            message.Retries = _options.FailedRetryCount; // not retry if SubscriberNotFoundException\n\n        var needRetry = UpdateMessageForRetry(message);\n\n        message.Origin.AddOrUpdateException(ex);\n        message.ExpiresAt = message.Added.AddSeconds(_options.FailedMessageExpiredAfter);\n\n        await _dataStorage.ChangeReceiveStateAsync(message, StatusName.Failed).ConfigureAwait(false);\n\n        return needRetry;\n    }\n\n    private bool UpdateMessageForRetry(MediumMessage message)\n    {\n        var retries = ++message.Retries;\n\n        var retryCount = Math.Min(_options.FailedRetryCount, 3);\n        if (retries >= retryCount)\n        {\n            if (retries == _options.FailedRetryCount)\n                try\n                {\n                    _options.FailedThresholdCallback?.Invoke(new FailedInfo\n                    {\n                        ServiceProvider = _provider,\n                        MessageType = MessageType.Subscribe,\n                        Message = message.Origin\n                    });\n\n                    _logger.ConsumerExecutedAfterThreshold(message.DbId, _options.FailedRetryCount);\n                }\n                catch (Exception ex)\n                {\n                    _logger.ExecutedThresholdCallbackFailed(ex);\n                }\n\n            return false;\n        }\n\n        _logger.ConsumerExecutionRetrying(message.DbId, retries);\n\n        return true;\n    }\n\n    private async Task InvokeConsumerMethodAsync(MediumMessage message, ConsumerExecutorDescriptor descriptor,\n        CancellationToken cancellationToken)\n    {\n        var consumerContext = new ConsumerContext(descriptor, message);\n        var tracingTimestamp = TracingBefore(message.Origin, descriptor.MethodInfo);\n        try\n        {\n            var ret = await Invoker.InvokeAsync(consumerContext, cancellationToken).ConfigureAwait(false);\n\n            TracingAfter(tracingTimestamp, message.Origin, descriptor.MethodInfo);\n\n            if (!string.IsNullOrEmpty(ret.CallbackName))\n            {\n                ret.CallbackHeader ??= new Dictionary<string, string?>();\n                ret.CallbackHeader[Headers.CorrelationId] = message.Origin.GetId();\n                ret.CallbackHeader[Headers.CorrelationSequence] = (message.Origin.GetCorrelationSequence() + 1).ToString();\n\n                if (message.Origin.Headers.TryGetValue(Headers.TraceParent, out var traceparent))\n                    ret.CallbackHeader[Headers.TraceParent] = traceparent;\n\n                await _provider.GetRequiredService<ICapPublisher>()\n                    .PublishAsync(ret.CallbackName, ret.Result, ret.CallbackHeader, cancellationToken).ConfigureAwait(false);\n            }\n        }\n        catch (OperationCanceledException)\n        {\n            //ignore\n        }\n        catch (Exception ex)\n        {\n            var e = new SubscriberExecutionFailedException(ex.Message, ex);\n\n            TracingError(tracingTimestamp, message.Origin, descriptor.MethodInfo, e);\n\n            e.ReThrow();\n        }\n    }\n\n    #region tracing\n\n    private long? TracingBefore(Message message, MethodInfo method)\n    {\n        if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.BeforeSubscriberInvoke))\n        {\n            var eventData = new CapEventDataSubExecute\n            {\n                OperationTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),\n                Operation = message.GetName(),\n                Message = message,\n                MethodInfo = method\n            };\n\n            s_diagnosticListener.Write(CapDiagnosticListenerNames.BeforeSubscriberInvoke, eventData);\n\n            return eventData.OperationTimestamp;\n        }\n\n        return null;\n    }\n\n    private void TracingAfter(long? tracingTimestamp, Message message, MethodInfo method)\n    {\n        CapEventCounterSource.Log.WriteInvokeMetrics();\n        if (tracingTimestamp != null &&\n            s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.AfterSubscriberInvoke))\n        {\n            var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();\n            var eventData = new CapEventDataSubExecute\n            {\n                OperationTimestamp = now,\n                Operation = message.GetName(),\n                Message = message,\n                MethodInfo = method,\n                ElapsedTimeMs = now - tracingTimestamp.Value\n            };\n\n            s_diagnosticListener.Write(CapDiagnosticListenerNames.AfterSubscriberInvoke, eventData);\n        }\n    }\n\n    private void TracingError(long? tracingTimestamp, Message message, MethodInfo? method, Exception ex)\n    {\n        if (tracingTimestamp != null &&\n            s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.ErrorSubscriberInvoke))\n        {\n            var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();\n            var eventData = new CapEventDataSubExecute\n            {\n                OperationTimestamp = now,\n                Operation = message.GetName(),\n                Message = message,\n                MethodInfo = method,\n                ElapsedTimeMs = now - tracingTimestamp.Value,\n                Exception = ex\n            };\n\n            s_diagnosticListener.Write(CapDiagnosticListenerNames.ErrorSubscriberInvoke, eventData);\n        }\n    }\n\n    #endregion\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/ISubscribeExecutor.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Persistence;\n\nnamespace DotNetCore.CAP.Internal;\n\n/// <summary>\n/// Consumer executor\n/// </summary>\npublic interface ISubscribeExecutor\n{\n    Task<OperateResult> ExecuteAsync(MediumMessage message, ConsumerExecutorDescriptor? descriptor = null, CancellationToken cancellationToken = default);\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/ISubscribeInvoker.Default.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Concurrent;\nusing System.ComponentModel;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Filter;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Serialization;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Internal;\n\nnamespace DotNetCore.CAP.Internal;\n\npublic class SubscribeInvoker : ISubscribeInvoker\n{\n    private readonly ConcurrentDictionary<string, ObjectMethodExecutor> _executors;\n    private readonly ISerializer _serializer;\n    private readonly IServiceProvider _serviceProvider;\n\n    public SubscribeInvoker(IServiceProvider serviceProvider, ISerializer serializer)\n    {\n        _serviceProvider = serviceProvider;\n        _serializer = serializer;\n        _executors = new ConcurrentDictionary<string, ObjectMethodExecutor>();\n    }\n\n    public async Task<ConsumerExecutedResult> InvokeAsync(ConsumerContext context,\n        CancellationToken cancellationToken = default)\n    {\n        cancellationToken.ThrowIfCancellationRequested();\n\n        var methodInfo = context.ConsumerDescriptor.MethodInfo;\n        var reflectedTypeHandle = methodInfo.ReflectedType!.TypeHandle.Value;\n        var methodHandle = methodInfo.MethodHandle.Value;\n        var key = $\"{reflectedTypeHandle}_{methodHandle}\";\n\n        var executor = _executors.GetOrAdd(key,\n            _ => ObjectMethodExecutor.Create(methodInfo, context.ConsumerDescriptor.ImplTypeInfo));\n\n        await using var scope = _serviceProvider.CreateAsyncScope();\n\n        var provider = scope.ServiceProvider;\n\n        var obj = GetInstance(provider, context);\n\n        var message = context.DeliverMessage;\n        var parameterDescriptors = context.ConsumerDescriptor.Parameters;\n        var executeParameters = new object?[parameterDescriptors.Count];\n        for (var i = 0; i < parameterDescriptors.Count; i++)\n        {\n            var parameterDescriptor = parameterDescriptors[i];\n            if (parameterDescriptor.IsFromCap)\n            {\n                executeParameters[i] = GetCapProvidedParameter(parameterDescriptor, message, cancellationToken);\n            }\n            else\n            {\n                if (message.Value != null)\n                {\n                    // use ISerializer when reading from storage, skip other objects if not Json\n                    if (_serializer.IsJsonType(message.Value))\n                    {\n                        executeParameters[i] =\n                            _serializer.Deserialize(message.Value, parameterDescriptor.ParameterType);\n                    }\n                    else\n                    {\n                        var converter = TypeDescriptor.GetConverter(parameterDescriptor.ParameterType);\n                        if (converter.CanConvertFrom(message.Value.GetType()))\n                        {\n                            executeParameters[i] = converter.ConvertFrom(message.Value);\n                        }\n                        else\n                        {\n                            if (parameterDescriptor.ParameterType.IsInstanceOfType(message.Value))\n                                executeParameters[i] = message.Value;\n                            else\n                                executeParameters[i] =\n                                    Convert.ChangeType(message.Value, parameterDescriptor.ParameterType);\n                        }\n                    }\n                }\n            }\n        }\n\n        var filter = provider.GetService<ISubscribeFilter>();\n        object? resultObj = null;\n        try\n        {\n            if (filter != null)\n            {\n                var etContext = new ExecutingContext(context, executeParameters);\n                await filter.OnSubscribeExecutingAsync(etContext).ConfigureAwait(false);\n                executeParameters = etContext.Arguments;\n            }\n\n            resultObj = await ExecuteWithParameterAsync(executor, obj, executeParameters).ConfigureAwait(false);\n\n            if (filter != null)\n            {\n                var edContext = new ExecutedContext(context, resultObj);\n                await filter.OnSubscribeExecutedAsync(edContext).ConfigureAwait(false);\n                resultObj = edContext.Result;\n            }\n        }\n        catch (Exception e)\n        {\n            if (filter != null)\n            {\n                var exContext = new ExceptionContext(context, e);\n                await filter.OnSubscribeExceptionAsync(exContext).ConfigureAwait(false);\n                if (!exContext.ExceptionHandled) exContext.Exception.ReThrow();\n\n                if (exContext.Result != null) resultObj = exContext.Result;\n            }\n            else\n            {\n                throw;\n            }\n        }\n\n        var callbackName = message.GetCallbackName();\n        if (string.IsNullOrEmpty(callbackName))\n        {\n            return new ConsumerExecutedResult(resultObj, message.GetId(), null, null);\n        }\n        else\n        {\n            var capHeader = executeParameters.FirstOrDefault(x => x is CapHeader) as CapHeader;\n            return new ConsumerExecutedResult(resultObj, message.GetId(), callbackName, capHeader?.ResponseHeader);\n        }\n    }\n\n    private static object GetCapProvidedParameter(ParameterDescriptor parameterDescriptor, Message message,\n        CancellationToken cancellationToken)\n    {\n        if (typeof(CancellationToken).IsAssignableFrom(parameterDescriptor.ParameterType)) return cancellationToken;\n\n        if (parameterDescriptor.ParameterType.IsAssignableFrom(typeof(CapHeader)))\n            return new CapHeader(message.Headers);\n\n        throw new ArgumentException(parameterDescriptor.Name);\n    }\n\n    protected virtual object GetInstance(IServiceProvider provider, ConsumerContext context)\n    {\n        var srvType = context.ConsumerDescriptor.ServiceTypeInfo?.AsType();\n        var implType = context.ConsumerDescriptor.ImplTypeInfo.AsType();\n\n        object? obj = null;\n        if (srvType != null) obj = provider.GetServices(srvType).FirstOrDefault(o => o?.GetType() == implType);\n\n        if (obj == null) obj = ActivatorUtilities.GetServiceOrCreateInstance(provider, implType);\n\n        return obj;\n    }\n\n    private async Task<object?> ExecuteWithParameterAsync(ObjectMethodExecutor executor, object @class,\n        object?[] parameter)\n    {\n        if (executor.IsMethodAsync) return await executor.ExecuteAsync(@class, parameter);\n\n        return executor.Execute(@class, parameter);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/ISubscribeInvoker.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace DotNetCore.CAP.Internal;\n\n/// <summary>\n/// Perform user definition method of consumers.\n/// </summary>\npublic interface ISubscribeInvoker\n{\n    /// <summary>\n    /// Invoke subscribe method with the consumer context.\n    /// </summary>\n    /// <param name=\"context\">consumer execute context</param>\n    /// <param name=\"cancellationToken\">The object of <see cref=\"CancellationToken\" />.</param>\n    Task<ConsumerExecutedResult> InvokeAsync(ConsumerContext context, CancellationToken cancellationToken = default);\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/LoggerExtensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing Microsoft.Extensions.Logging;\n\nnamespace DotNetCore.CAP.Internal;\n\ninternal static class LoggerExtensions\n{\n    public static void ConsumerExecutedAfterThreshold(this ILogger logger, string messageId, int retries)\n    {\n        logger.LogWarning(\n            $\"The Subscriber of the message({messageId}) still fails after {retries}th executions and we will stop retrying.\");\n    }\n\n    public static void SenderAfterThreshold(this ILogger logger, string messageId, int retries)\n    {\n        logger.LogWarning(\n            $\"The Publisher of the message({messageId}) still fails after {retries}th sends and we will stop retrying.\");\n    }\n\n    public static void ExecutedThresholdCallbackFailed(this ILogger logger, Exception ex)\n    {\n        logger.LogWarning(ex, \"FailedThresholdCallback action raised an exception:\" + ex.Message);\n    }\n\n    public static void ConsumerDuplicates(this ILogger logger, string subscriber, string group)\n    {\n        logger.LogWarning(\n            $\"We detected that you have duplicate subscribers ({subscriber}) in same group ({group}), this will cause diversity behavior.\");\n    }\n\n    public static void ConsumerExecutionRetrying(this ILogger logger, string messageId, int retries)\n    {\n        logger.LogWarning($\"The {retries}th retrying consume a message failed. message id: {messageId}\");\n    }\n\n    public static void SenderRetrying(this ILogger logger, string messageId, int retries)\n    {\n        logger.LogWarning($\"The {retries}th retrying send a message failed. message id: {messageId} \");\n    }\n\n    public static void MessageReceived(this ILogger logger, string messageId, string name)\n    {\n        logger.LogDebug($\"Received message. id:{messageId}, name: {name}\");\n    }\n\n    public static void MessagePublishException(this ILogger logger, string? messageId, string reason, Exception? ex)\n    {\n        logger.LogError(ex,\n            $\"An exception occurred while publishing a message, reason:{reason}. message id:{messageId}\");\n    }\n\n    public static void ConsumerExecuting(this ILogger logger, string className, string methodName, string group)\n    {\n        logger.LogInformation($\"Executing subscriber method '{className}.{methodName}' on group '{group}'\");\n    }\n\n    public static void ConsumerExecuted(this ILogger logger, string className, string methodName, string group,\n        double milliseconds, string? instance)\n    {\n        logger.LogInformation(\n            $\"Executed subscriber method '{className}.{methodName}' on group '{group}' with instance '{instance}' in {milliseconds}ms\");\n    }\n\n    public static void ConsumerExecuteFailed(this ILogger logger, string topic, string id, string? instance,\n        Exception? ex)\n    {\n        logger.LogError(ex,\n            $\"An exception occurred while executing the subscription method. Topic:{topic}, Id:{id}, Instance: {instance}\");\n    }\n\n    public static void ServerStarting(this ILogger logger)\n    {\n        logger.LogInformation(\"Starting the processing server.\");\n    }\n\n    public static void ProcessorsStartedError(this ILogger logger, Exception ex)\n    {\n        logger.LogError(ex, \"Starting the processors throw an exception.\");\n    }\n\n    public static void ServerShuttingDown(this ILogger logger)\n    {\n        logger.LogInformation(\"Shutting down the processing server...\");\n    }\n\n    public static void ExpectedOperationCanceledException(this ILogger logger, Exception ex)\n    {\n        logger.LogWarning(ex, $\"Expected an OperationCanceledException, but found '{ex.Message}'.\");\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/MethodMatcherCache.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\n\nnamespace DotNetCore.CAP.Internal;\n\npublic class MethodMatcherCache\n{\n    private readonly IConsumerServiceSelector _selector;\n\n    public MethodMatcherCache(IConsumerServiceSelector selector)\n    {\n        _selector = selector;\n        Entries = new ConcurrentDictionary<string, IReadOnlyList<ConsumerExecutorDescriptor>>();\n        GroupConcurrent = new ConcurrentDictionary<string, byte>();\n    }\n\n    private ConcurrentDictionary<string, IReadOnlyList<ConsumerExecutorDescriptor>> Entries { get; }\n\n    private ConcurrentDictionary<string, byte> GroupConcurrent { get; }\n\n    /// <summary>\n    /// Get a dictionary of candidates.In the dictionary,\n    /// the Key is the CAPSubscribeAttribute Group, the Value for the current Group of candidates\n    /// </summary>\n    public ConcurrentDictionary<string, IReadOnlyList<ConsumerExecutorDescriptor>> GetCandidatesMethodsOfGroupNameGrouped()\n    {\n        if (Entries.Count != 0) return Entries;\n\n        var executorCollection = _selector.SelectCandidates();\n\n        foreach (var executor in executorCollection)\n        {\n            GroupConcurrent.AddOrUpdate(executor.Attribute.Group, executor.Attribute.GroupConcurrent,\n                (group, val) => (byte)(val + executor.Attribute.GroupConcurrent));\n        }\n\n        var groupedCandidates = executorCollection.GroupBy(x => x.Attribute.Group);\n\n        foreach (var item in groupedCandidates) Entries.TryAdd(item.Key, item.ToList());\n\n        return Entries;\n    }\n\n    public byte GetGroupConcurrentLimit(string group)\n    {\n        return GroupConcurrent.TryGetValue(group, out byte value) ? value : (byte)1;\n    }\n\n    public List<string> GetAllTopics()\n    {\n        if (Entries.Count == 0) GetCandidatesMethodsOfGroupNameGrouped();\n\n        var result = new List<string>();\n        foreach (var item in Entries.Values) result.AddRange(item.Select(x => x.TopicName));\n        return result;\n    }\n\n    /// <summary>\n    /// Attempts to get the topic executor associated with the specified topic name and group name from the\n    /// <see cref=\"Entries\" />.\n    /// </summary>\n    /// <param name=\"topicName\">The topic name of the value to get.</param>\n    /// <param name=\"groupName\">The group name of the value to get.</param>\n    /// <param name=\"matchTopic\">topic executor of the value.</param>\n    /// <returns>true if the key was found, otherwise false. </returns>\n    public bool TryGetTopicExecutor(string topicName, string groupName,\n        [NotNullWhen(true)] out ConsumerExecutorDescriptor? matchTopic)\n    {\n        if (Entries == null) throw new ArgumentNullException(nameof(Entries));\n\n        matchTopic = null;\n\n        if (Entries.TryGetValue(groupName, out var groupMatchTopics))\n        {\n            matchTopic = _selector.SelectBestCandidate(topicName, groupMatchTopics);\n\n            return matchTopic != null;\n        }\n\n        return false;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/NoopTransaction.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nnamespace DotNetCore.CAP.Internal;\n\npublic class NoopTransaction\n{\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/ObjectMethodExecutor/AwaitableInfo.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\n#nullable disable\n\nusing System;\nusing System.Linq;\nusing System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace Microsoft.Extensions.Internal;\n\ninternal readonly struct AwaitableInfo\n{\n    public Type AwaiterType { get; }\n    public PropertyInfo AwaiterIsCompletedProperty { get; }\n    public MethodInfo AwaiterGetResultMethod { get; }\n    public MethodInfo AwaiterOnCompletedMethod { get; }\n    public MethodInfo AwaiterUnsafeOnCompletedMethod { get; }\n    public Type ResultType { get; }\n    public MethodInfo GetAwaiterMethod { get; }\n\n    public AwaitableInfo(\n        Type awaiterType,\n        PropertyInfo awaiterIsCompletedProperty,\n        MethodInfo awaiterGetResultMethod,\n        MethodInfo awaiterOnCompletedMethod,\n        MethodInfo awaiterUnsafeOnCompletedMethod,\n        Type resultType,\n        MethodInfo getAwaiterMethod)\n    {\n        AwaiterType = awaiterType;\n        AwaiterIsCompletedProperty = awaiterIsCompletedProperty;\n        AwaiterGetResultMethod = awaiterGetResultMethod;\n        AwaiterOnCompletedMethod = awaiterOnCompletedMethod;\n        AwaiterUnsafeOnCompletedMethod = awaiterUnsafeOnCompletedMethod;\n        ResultType = resultType;\n        GetAwaiterMethod = getAwaiterMethod;\n    }\n\n    public static bool IsTypeAwaitable(Type type, out AwaitableInfo awaitableInfo)\n    {\n        // Based on Roslyn code: http://source.roslyn.io/#Microsoft.CodeAnalysis.Workspaces/Shared/Extensions/ISymbolExtensions.cs,db4d48ba694b9347\n\n        // Awaitable must have method matching \"object GetAwaiter()\"\n        var getAwaiterMethod = type.GetRuntimeMethods().FirstOrDefault(m =>\n            m.Name.Equals(\"GetAwaiter\", StringComparison.OrdinalIgnoreCase)\n            && m.GetParameters().Length == 0\n            && m.ReturnType != null);\n        if (getAwaiterMethod == null)\n        {\n            awaitableInfo = default;\n            return false;\n        }\n\n        var awaiterType = getAwaiterMethod.ReturnType;\n\n        // Awaiter must have property matching \"bool IsCompleted { get; }\"\n        var isCompletedProperty = awaiterType.GetRuntimeProperties().FirstOrDefault(p =>\n            p.Name.Equals(\"IsCompleted\", StringComparison.OrdinalIgnoreCase)\n            && p.PropertyType == typeof(bool)\n            && p.GetMethod != null);\n        if (isCompletedProperty == null)\n        {\n            awaitableInfo = default;\n            return false;\n        }\n\n        // Awaiter must implement INotifyCompletion\n        var awaiterInterfaces = awaiterType.GetInterfaces();\n        var implementsINotifyCompletion = awaiterInterfaces.Any(t => t == typeof(INotifyCompletion));\n        if (!implementsINotifyCompletion)\n        {\n            awaitableInfo = default;\n            return false;\n        }\n\n        // INotifyCompletion supplies a method matching \"void OnCompleted(Action action)\"\n        var onCompletedMethod = typeof(INotifyCompletion).GetRuntimeMethods().Single(m =>\n            m.Name.Equals(\"OnCompleted\", StringComparison.OrdinalIgnoreCase)\n            && m.ReturnType == typeof(void)\n            && m.GetParameters().Length == 1\n            && m.GetParameters()[0].ParameterType == typeof(Action));\n\n        // Awaiter optionally implements ICriticalNotifyCompletion\n        var implementsICriticalNotifyCompletion = awaiterInterfaces.Any(t => t == typeof(ICriticalNotifyCompletion));\n        MethodInfo unsafeOnCompletedMethod;\n        if (implementsICriticalNotifyCompletion)\n            // ICriticalNotifyCompletion supplies a method matching \"void UnsafeOnCompleted(Action action)\"\n            unsafeOnCompletedMethod = typeof(ICriticalNotifyCompletion).GetRuntimeMethods().Single(m =>\n                m.Name.Equals(\"UnsafeOnCompleted\", StringComparison.OrdinalIgnoreCase)\n                && m.ReturnType == typeof(void)\n                && m.GetParameters().Length == 1\n                && m.GetParameters()[0].ParameterType == typeof(Action));\n        else\n            unsafeOnCompletedMethod = null;\n\n        // Awaiter must have method matching \"void GetResult\" or \"T GetResult()\"\n        var getResultMethod = awaiterType.GetRuntimeMethods().FirstOrDefault(m =>\n            m.Name.Equals(\"GetResult\")\n            && m.GetParameters().Length == 0);\n        if (getResultMethod == null)\n        {\n            awaitableInfo = default;\n            return false;\n        }\n\n        awaitableInfo = new AwaitableInfo(\n            awaiterType,\n            isCompletedProperty,\n            getResultMethod,\n            onCompletedMethod,\n            unsafeOnCompletedMethod,\n            getResultMethod.ReturnType,\n            getAwaiterMethod);\n        return true;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/ObjectMethodExecutor/CoercedAwaitableInfo.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\n#nullable disable\n\nusing System;\nusing System.Linq.Expressions;\n\nnamespace Microsoft.Extensions.Internal;\n\ninternal readonly struct CoercedAwaitableInfo\n{\n    public AwaitableInfo AwaitableInfo { get; }\n    public Expression CoercerExpression { get; }\n    public Type CoercerResultType { get; }\n    public bool RequiresCoercion => CoercerExpression != null;\n\n    public CoercedAwaitableInfo(AwaitableInfo awaitableInfo)\n    {\n        AwaitableInfo = awaitableInfo;\n        CoercerExpression = null;\n        CoercerResultType = null;\n    }\n\n    public CoercedAwaitableInfo(Expression coercerExpression, Type coercerResultType,\n        AwaitableInfo coercedAwaitableInfo)\n    {\n        CoercerExpression = coercerExpression;\n        CoercerResultType = coercerResultType;\n        AwaitableInfo = coercedAwaitableInfo;\n    }\n\n    public static bool IsTypeAwaitable(Type type, out CoercedAwaitableInfo info)\n    {\n        if (AwaitableInfo.IsTypeAwaitable(type, out var directlyAwaitableInfo))\n        {\n            info = new CoercedAwaitableInfo(directlyAwaitableInfo);\n            return true;\n        }\n\n        // It's not directly awaitable, but maybe we can coerce it.\n        // Currently we support coercing FSharpAsync<T>.\n        if (ObjectMethodExecutorFSharpSupport.TryBuildCoercerFromFSharpAsyncToAwaitable(type,\n                out var coercerExpression,\n                out var coercerResultType))\n            if (AwaitableInfo.IsTypeAwaitable(coercerResultType, out var coercedAwaitableInfo))\n            {\n                info = new CoercedAwaitableInfo(coercerExpression, coercerResultType, coercedAwaitableInfo);\n                return true;\n            }\n\n        info = default;\n        return false;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/ObjectMethodExecutor/ObjectMethodExecutor.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\n#nullable enable\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq.Expressions;\nusing System.Reflection;\n\nnamespace Microsoft.Extensions.Internal;\n\ninternal class ObjectMethodExecutor\n{\n    private static readonly ConstructorInfo _objectMethodExecutorAwaitableConstructor =\n        typeof(ObjectMethodExecutorAwaitable).GetConstructor(new[]\n        {\n            typeof(object), // customAwaitable\n            typeof(Func<object, object>), // getAwaiterMethod\n            typeof(Func<object, bool>), // isCompletedMethod\n            typeof(Func<object, object>), // getResultMethod\n            typeof(Action<object, Action>), // onCompletedMethod\n            typeof(Action<object, Action>) // unsafeOnCompletedMethod\n        })!;\n\n    private readonly MethodExecutor? _executor;\n    private readonly MethodExecutorAsync? _executorAsync;\n    private readonly object?[]? _parameterDefaultValues;\n\n    private ObjectMethodExecutor(MethodInfo methodInfo, TypeInfo targetTypeInfo, object?[]? parameterDefaultValues)\n    {\n        if (methodInfo == null) throw new ArgumentNullException(nameof(methodInfo));\n\n        MethodInfo = methodInfo;\n        MethodParameters = methodInfo.GetParameters();\n        TargetTypeInfo = targetTypeInfo;\n        MethodReturnType = methodInfo.ReturnType;\n\n        var isAwaitable = CoercedAwaitableInfo.IsTypeAwaitable(MethodReturnType, out var coercedAwaitableInfo);\n\n        IsMethodAsync = isAwaitable;\n        AsyncResultType = isAwaitable ? coercedAwaitableInfo.AwaitableInfo.ResultType : null;\n\n        // Upstream code may prefer to use the sync-executor even for async methods, because if it knows\n        // that the result is a specific Task<T> where T is known, then it can directly cast to that type\n        // and await it without the extra heap allocations involved in the _executorAsync code path.\n        _executor = GetExecutor(methodInfo, targetTypeInfo);\n\n        if (IsMethodAsync) _executorAsync = GetExecutorAsync(methodInfo, targetTypeInfo, coercedAwaitableInfo);\n\n        _parameterDefaultValues = parameterDefaultValues;\n    }\n\n    public MethodInfo MethodInfo { get; }\n\n    public ParameterInfo[] MethodParameters { get; }\n\n    public TypeInfo TargetTypeInfo { get; }\n\n    public Type? AsyncResultType { get; }\n\n    // This field is made internal set because it is set in unit tests.\n    public Type MethodReturnType { get; internal set; }\n\n    public bool IsMethodAsync { get; }\n\n    public static ObjectMethodExecutor Create(MethodInfo methodInfo, TypeInfo targetTypeInfo)\n    {\n        return new ObjectMethodExecutor(methodInfo, targetTypeInfo, null);\n    }\n\n    public static ObjectMethodExecutor Create(MethodInfo methodInfo, TypeInfo targetTypeInfo,\n        object?[] parameterDefaultValues)\n    {\n        if (parameterDefaultValues == null) throw new ArgumentNullException(nameof(parameterDefaultValues));\n\n        return new ObjectMethodExecutor(methodInfo, targetTypeInfo, parameterDefaultValues);\n    }\n\n    /// <summary>\n    /// Executes the configured method on <paramref name=\"target\" />. This can be used whether or not\n    /// the configured method is asynchronous.\n    /// </summary>\n    /// <remarks>\n    /// Even if the target method is asynchronous, it's desirable to invoke it using Execute rather than\n    /// ExecuteAsync if you know at compile time what the return type is, because then you can directly\n    /// \"await\" that value (via a cast), and then the generated code will be able to reference the\n    /// resulting awaitable as a value-typed variable. If you use ExecuteAsync instead, the generated\n    /// code will have to treat the resulting awaitable as a boxed object, because it doesn't know at\n    /// compile time what type it would be.\n    /// </remarks>\n    /// <param name=\"target\">The object whose method is to be executed.</param>\n    /// <param name=\"parameters\">Parameters to pass to the method.</param>\n    /// <returns>The method return value.</returns>\n    public object? Execute(object target, object?[]? parameters)\n    {\n        Debug.Assert(_executor != null, \"Sync execution is not supported.\");\n        return _executor(target, parameters);\n    }\n\n    /// <summary>\n    /// Executes the configured method on <paramref name=\"target\" />. This can only be used if the configured\n    /// method is asynchronous.\n    /// </summary>\n    /// <remarks>\n    /// If you don't know at compile time the type of the method's returned awaitable, you can use ExecuteAsync,\n    /// which supplies an awaitable-of-object. This always works, but can incur several extra heap allocations\n    /// as compared with using Execute and then using \"await\" on the result value typecasted to the known\n    /// awaitable type. The possible extra heap allocations are for:\n    /// 1. The custom awaitable (though usually there's a heap allocation for this anyway, since normally\n    /// it's a reference type, and you normally create a new instance per call).\n    /// 2. The custom awaiter (whether or not it's a value type, since if it's not, you need a new instance\n    /// of it, and if it is, it will have to be boxed so the calling code can reference it as an object).\n    /// 3. The async result value, if it's a value type (it has to be boxed as an object, since the calling\n    /// code doesn't know what type it's going to be).\n    /// </remarks>\n    /// <param name=\"target\">The object whose method is to be executed.</param>\n    /// <param name=\"parameters\">Parameters to pass to the method.</param>\n    /// <returns>An object that you can \"await\" to get the method return value.</returns>\n    public ObjectMethodExecutorAwaitable ExecuteAsync(object target, object?[]? parameters)\n    {\n        Debug.Assert(_executorAsync != null, \"Async execution is not supported.\");\n        return _executorAsync(target, parameters);\n    }\n\n    public object? GetDefaultValueForParameter(int index)\n    {\n        if (_parameterDefaultValues == null)\n            throw new InvalidOperationException(\n                $\"Cannot call {nameof(GetDefaultValueForParameter)}, because no parameter default values were supplied.\");\n\n        if (index < 0 || index > MethodParameters.Length - 1) throw new ArgumentOutOfRangeException(nameof(index));\n\n        return _parameterDefaultValues[index];\n    }\n\n    private static MethodExecutor GetExecutor(MethodInfo methodInfo, TypeInfo targetTypeInfo)\n    {\n        // Parameters to executor\n        var targetParameter = Expression.Parameter(typeof(object), \"target\");\n        var parametersParameter = Expression.Parameter(typeof(object?[]), \"parameters\");\n\n        // Build parameter list\n        var paramInfos = methodInfo.GetParameters();\n        var parameters = new List<Expression>(paramInfos.Length);\n        for (var i = 0; i < paramInfos.Length; i++)\n        {\n            var paramInfo = paramInfos[i];\n            var valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i));\n            var valueCast = Expression.Convert(valueObj, paramInfo.ParameterType);\n\n            // valueCast is \"(Ti) parameters[i]\"\n            parameters.Add(valueCast);\n        }\n\n        // Call method\n        var instanceCast = Expression.Convert(targetParameter, targetTypeInfo.AsType());\n        var methodCall = Expression.Call(instanceCast, methodInfo, parameters);\n\n        // methodCall is \"((Ttarget) target) method((T0) parameters[0], (T1) parameters[1], ...)\"\n        // Create function\n        if (methodCall.Type == typeof(void))\n        {\n            var lambda = Expression.Lambda<VoidMethodExecutor>(methodCall, targetParameter, parametersParameter);\n            var voidExecutor = lambda.Compile();\n            return WrapVoidMethod(voidExecutor);\n        }\n        else\n        {\n            // must coerce methodCall to match ActionExecutor signature\n            var castMethodCall = Expression.Convert(methodCall, typeof(object));\n            var lambda = Expression.Lambda<MethodExecutor>(castMethodCall, targetParameter, parametersParameter);\n            return lambda.Compile();\n        }\n    }\n\n    private static MethodExecutor WrapVoidMethod(VoidMethodExecutor executor)\n    {\n        return delegate(object target, object?[]? parameters)\n        {\n            executor(target, parameters);\n            return null;\n        };\n    }\n\n    private static MethodExecutorAsync GetExecutorAsync(\n        MethodInfo methodInfo,\n        TypeInfo targetTypeInfo,\n        CoercedAwaitableInfo coercedAwaitableInfo)\n    {\n        // Parameters to executor\n        var targetParameter = Expression.Parameter(typeof(object), \"target\");\n        var parametersParameter = Expression.Parameter(typeof(object[]), \"parameters\");\n\n        // Build parameter list\n        var paramInfos = methodInfo.GetParameters();\n        var parameters = new List<Expression>(paramInfos.Length);\n        for (var i = 0; i < paramInfos.Length; i++)\n        {\n            var paramInfo = paramInfos[i];\n            var valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i));\n            var valueCast = Expression.Convert(valueObj, paramInfo.ParameterType);\n\n            // valueCast is \"(Ti) parameters[i]\"\n            parameters.Add(valueCast);\n        }\n\n        // Call method\n        var instanceCast = Expression.Convert(targetParameter, targetTypeInfo.AsType());\n        var methodCall = Expression.Call(instanceCast, methodInfo, parameters);\n\n        // Using the method return value, construct an ObjectMethodExecutorAwaitable based on\n        // the info we have about its implementation of the awaitable pattern. Note that all\n        // the funcs/actions we construct here are precompiled, so that only one instance of\n        // each is preserved throughout the lifetime of the ObjectMethodExecutor.\n\n        // var getAwaiterFunc = (object awaitable) =>\n        //     (object)((CustomAwaitableType)awaitable).GetAwaiter();\n        var customAwaitableParam = Expression.Parameter(typeof(object), \"awaitable\");\n        var awaitableInfo = coercedAwaitableInfo.AwaitableInfo;\n        var postCoercionMethodReturnType = coercedAwaitableInfo.CoercerResultType ?? methodInfo.ReturnType;\n        var getAwaiterFunc = Expression.Lambda<Func<object, object>>(\n            Expression.Convert(\n                Expression.Call(\n                    Expression.Convert(customAwaitableParam, postCoercionMethodReturnType),\n                    awaitableInfo.GetAwaiterMethod),\n                typeof(object)),\n            customAwaitableParam).Compile();\n\n        // var isCompletedFunc = (object awaiter) =>\n        //     ((CustomAwaiterType)awaiter).IsCompleted;\n        var isCompletedParam = Expression.Parameter(typeof(object), \"awaiter\");\n        var isCompletedFunc = Expression.Lambda<Func<object, bool>>(\n            Expression.MakeMemberAccess(\n                Expression.Convert(isCompletedParam, awaitableInfo.AwaiterType),\n                awaitableInfo.AwaiterIsCompletedProperty),\n            isCompletedParam).Compile();\n\n        var getResultParam = Expression.Parameter(typeof(object), \"awaiter\");\n        Func<object, object> getResultFunc;\n        if (awaitableInfo.ResultType == typeof(void))\n            // var getResultFunc = (object awaiter) =>\n            // {\n            //     ((CustomAwaiterType)awaiter).GetResult(); // We need to invoke this to surface any exceptions\n            //     return (object)null;\n            // };\n            getResultFunc = Expression.Lambda<Func<object, object>>(\n                Expression.Block(\n                    Expression.Call(\n                        Expression.Convert(getResultParam, awaitableInfo.AwaiterType),\n                        awaitableInfo.AwaiterGetResultMethod),\n                    Expression.Constant(null)\n                ),\n                getResultParam).Compile();\n        else\n            // var getResultFunc = (object awaiter) =>\n            //     (object)((CustomAwaiterType)awaiter).GetResult();\n            getResultFunc = Expression.Lambda<Func<object, object>>(\n                Expression.Convert(\n                    Expression.Call(\n                        Expression.Convert(getResultParam, awaitableInfo.AwaiterType),\n                        awaitableInfo.AwaiterGetResultMethod),\n                    typeof(object)),\n                getResultParam).Compile();\n\n        // var onCompletedFunc = (object awaiter, Action continuation) => {\n        //     ((CustomAwaiterType)awaiter).OnCompleted(continuation);\n        // };\n        var onCompletedParam1 = Expression.Parameter(typeof(object), \"awaiter\");\n        var onCompletedParam2 = Expression.Parameter(typeof(Action), \"continuation\");\n        var onCompletedFunc = Expression.Lambda<Action<object, Action>>(\n            Expression.Call(\n                Expression.Convert(onCompletedParam1, awaitableInfo.AwaiterType),\n                awaitableInfo.AwaiterOnCompletedMethod,\n                onCompletedParam2),\n            onCompletedParam1,\n            onCompletedParam2).Compile();\n\n        Action<object, Action>? unsafeOnCompletedFunc = null;\n        if (awaitableInfo.AwaiterUnsafeOnCompletedMethod != null)\n        {\n            // var unsafeOnCompletedFunc = (object awaiter, Action continuation) => {\n            //     ((CustomAwaiterType)awaiter).UnsafeOnCompleted(continuation);\n            // };\n            var unsafeOnCompletedParam1 = Expression.Parameter(typeof(object), \"awaiter\");\n            var unsafeOnCompletedParam2 = Expression.Parameter(typeof(Action), \"continuation\");\n            unsafeOnCompletedFunc = Expression.Lambda<Action<object, Action>>(\n                Expression.Call(\n                    Expression.Convert(unsafeOnCompletedParam1, awaitableInfo.AwaiterType),\n                    awaitableInfo.AwaiterUnsafeOnCompletedMethod,\n                    unsafeOnCompletedParam2),\n                unsafeOnCompletedParam1,\n                unsafeOnCompletedParam2).Compile();\n        }\n\n        // If we need to pass the method call result through a coercer function to get an\n        // awaitable, then do so.\n        var coercedMethodCall = coercedAwaitableInfo.RequiresCoercion\n            ? Expression.Invoke(coercedAwaitableInfo.CoercerExpression, methodCall)\n            : (Expression)methodCall;\n\n        // return new ObjectMethodExecutorAwaitable(\n        //     (object)coercedMethodCall,\n        //     getAwaiterFunc,\n        //     isCompletedFunc,\n        //     getResultFunc,\n        //     onCompletedFunc,\n        //     unsafeOnCompletedFunc);\n        var returnValueExpression = Expression.New(\n            _objectMethodExecutorAwaitableConstructor,\n            Expression.Convert(coercedMethodCall, typeof(object)),\n            Expression.Constant(getAwaiterFunc),\n            Expression.Constant(isCompletedFunc),\n            Expression.Constant(getResultFunc),\n            Expression.Constant(onCompletedFunc),\n            Expression.Constant(unsafeOnCompletedFunc, typeof(Action<object, Action>)));\n\n        var lambda =\n            Expression.Lambda<MethodExecutorAsync>(returnValueExpression, targetParameter, parametersParameter);\n        return lambda.Compile();\n    }\n\n    private delegate ObjectMethodExecutorAwaitable MethodExecutorAsync(object target, object?[]? parameters);\n\n    private delegate object? MethodExecutor(object target, object?[]? parameters);\n\n    private delegate void VoidMethodExecutor(object target, object?[]? parameters);\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/ObjectMethodExecutor/ObjectMethodExecutorAwaitable.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\n#nullable disable\n\nusing System;\nusing System.Runtime.CompilerServices;\n\nnamespace Microsoft.Extensions.Internal;\n\n/// <summary>\n/// Provides a common awaitable structure that <see cref=\"ObjectMethodExecutor.ExecuteAsync\" /> can\n/// return, regardless of whether the underlying value is a System.Task, an FSharpAsync, or an\n/// application-defined custom awaitable.\n/// </summary>\ninternal readonly struct ObjectMethodExecutorAwaitable\n{\n    private readonly object _customAwaitable;\n    private readonly Func<object, object> _getAwaiterMethod;\n    private readonly Func<object, bool> _isCompletedMethod;\n    private readonly Func<object, object> _getResultMethod;\n    private readonly Action<object, Action> _onCompletedMethod;\n    private readonly Action<object, Action> _unsafeOnCompletedMethod;\n\n    // Perf note: since we're requiring the customAwaitable to be supplied here as an object,\n    // this will trigger a further allocation if it was a value type (i.e., to box it). We can't\n    // fix this by making the customAwaitable type generic, because the calling code typically\n    // does not know the type of the awaitable/awaiter at compile-time anyway.\n    //\n    // However, we could fix it by not passing the customAwaitable here at all, and instead\n    // passing a func that maps directly from the target object (e.g., controller instance),\n    // target method (e.g., action method info), and params array to the custom awaiter in the\n    // GetAwaiter() method below. In effect, by delaying the actual method call until the\n    // upstream code calls GetAwaiter on this ObjectMethodExecutorAwaitable instance.\n    // This optimization is not currently implemented because:\n    // [1] It would make no difference when the awaitable was an object type, which is\n    //     by far the most common scenario (e.g., System.Task<T>).\n    // [2] It would be complex - we'd need some kind of object pool to track all the parameter\n    //     arrays until we needed to use them in GetAwaiter().\n    // We can reconsider this in the future if there's a need to optimize for ValueTask<T>\n    // or other value-typed awaitables.\n\n    public ObjectMethodExecutorAwaitable(\n        object customAwaitable,\n        Func<object, object> getAwaiterMethod,\n        Func<object, bool> isCompletedMethod,\n        Func<object, object> getResultMethod,\n        Action<object, Action> onCompletedMethod,\n        Action<object, Action> unsafeOnCompletedMethod)\n    {\n        _customAwaitable = customAwaitable;\n        _getAwaiterMethod = getAwaiterMethod;\n        _isCompletedMethod = isCompletedMethod;\n        _getResultMethod = getResultMethod;\n        _onCompletedMethod = onCompletedMethod;\n        _unsafeOnCompletedMethod = unsafeOnCompletedMethod;\n    }\n\n    public Awaiter GetAwaiter()\n    {\n        var customAwaiter = _getAwaiterMethod(_customAwaitable);\n        return new Awaiter(customAwaiter, _isCompletedMethod, _getResultMethod, _onCompletedMethod,\n            _unsafeOnCompletedMethod);\n    }\n\n    public readonly struct Awaiter : ICriticalNotifyCompletion\n    {\n        private readonly object _customAwaiter;\n        private readonly Func<object, bool> _isCompletedMethod;\n        private readonly Func<object, object> _getResultMethod;\n        private readonly Action<object, Action> _onCompletedMethod;\n        private readonly Action<object, Action> _unsafeOnCompletedMethod;\n\n        public Awaiter(\n            object customAwaiter,\n            Func<object, bool> isCompletedMethod,\n            Func<object, object> getResultMethod,\n            Action<object, Action> onCompletedMethod,\n            Action<object, Action> unsafeOnCompletedMethod)\n        {\n            _customAwaiter = customAwaiter;\n            _isCompletedMethod = isCompletedMethod;\n            _getResultMethod = getResultMethod;\n            _onCompletedMethod = onCompletedMethod;\n            _unsafeOnCompletedMethod = unsafeOnCompletedMethod;\n        }\n\n        public bool IsCompleted => _isCompletedMethod(_customAwaiter);\n\n        public object GetResult()\n        {\n            return _getResultMethod(_customAwaiter);\n        }\n\n        public void OnCompleted(Action continuation)\n        {\n            _onCompletedMethod(_customAwaiter, continuation);\n        }\n\n        public void UnsafeOnCompleted(Action continuation)\n        {\n            // If the underlying awaitable implements ICriticalNotifyCompletion, use its UnsafeOnCompleted.\n            // If not, fall back on using its OnCompleted.\n            //\n            // Why this is safe:\n            // - Implementing ICriticalNotifyCompletion is a way of saying the caller can choose whether it\n            //   needs the execution context to be preserved (which it signals by calling OnCompleted), or\n            //   that it doesn't (which it signals by calling UnsafeOnCompleted). Obviously it's faster *not*\n            //   to preserve and restore the context, so we prefer that where possible.\n            // - If a caller doesn't need the execution context to be preserved and hence calls UnsafeOnCompleted,\n            //   there's no harm in preserving it anyway - it's just a bit of wasted cost. That's what will happen\n            //   if a caller sees that the proxy implements ICriticalNotifyCompletion but the proxy chooses to\n            //   pass the call on to the underlying awaitable's OnCompleted method.\n\n            var underlyingMethodToUse = _unsafeOnCompletedMethod ?? _onCompletedMethod;\n            underlyingMethodToUse(_customAwaiter, continuation);\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/ObjectMethodExecutor/ObjectMethodExecutorFSharpSupport.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\n#nullable disable\n\nusing System;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Microsoft.Extensions.Internal;\n\n/// <summary>\n/// Helper for detecting whether a given type is FSharpAsync`1, and if so, supplying\n/// an <see cref=\"Expression\" /> for mapping instances of that type to a C# awaitable.\n/// </summary>\n/// <remarks>\n/// The main design goal here is to avoid taking a compile-time dependency on\n/// FSharp.Core.dll, because non-F# applications wouldn't use it. So all the references\n/// to FSharp types have to be constructed dynamically at runtime.\n/// </remarks>\ninternal static class ObjectMethodExecutorFSharpSupport\n{\n    private static readonly object _fsharpValuesCacheLock = new();\n    private static Assembly _fsharpCoreAssembly;\n    private static MethodInfo _fsharpAsyncStartAsTaskGenericMethod;\n    private static PropertyInfo _fsharpOptionOfTaskCreationOptionsNoneProperty;\n    private static PropertyInfo _fsharpOptionOfCancellationTokenNoneProperty;\n\n    public static bool TryBuildCoercerFromFSharpAsyncToAwaitable(\n        Type possibleFSharpAsyncType,\n        out Expression coerceToAwaitableExpression,\n        out Type awaitableType)\n    {\n        var methodReturnGenericType = possibleFSharpAsyncType.IsGenericType\n            ? possibleFSharpAsyncType.GetGenericTypeDefinition()\n            : null;\n\n        if (!IsFSharpAsyncOpenGenericType(methodReturnGenericType))\n        {\n            coerceToAwaitableExpression = null;\n            awaitableType = null;\n            return false;\n        }\n\n        var awaiterResultType = possibleFSharpAsyncType.GetGenericArguments().Single();\n        awaitableType = typeof(Task<>).MakeGenericType(awaiterResultType);\n\n        // coerceToAwaitableExpression = (object fsharpAsync) =>\n        // {\n        //     return (object)FSharpAsync.StartAsTask<TResult>(\n        //         (Microsoft.FSharp.Control.FSharpAsync<TResult>)fsharpAsync,\n        //         FSharpOption<TaskCreationOptions>.None,\n        //         FSharpOption<CancellationToken>.None);\n        // };\n        var startAsTaskClosedMethod = _fsharpAsyncStartAsTaskGenericMethod\n            .MakeGenericMethod(awaiterResultType);\n        var coerceToAwaitableParam = Expression.Parameter(typeof(object));\n        coerceToAwaitableExpression = Expression.Lambda(\n            Expression.Convert(\n                Expression.Call(\n                    startAsTaskClosedMethod,\n                    Expression.Convert(coerceToAwaitableParam, possibleFSharpAsyncType),\n                    Expression.MakeMemberAccess(null, _fsharpOptionOfTaskCreationOptionsNoneProperty),\n                    Expression.MakeMemberAccess(null, _fsharpOptionOfCancellationTokenNoneProperty)),\n                typeof(object)),\n            coerceToAwaitableParam);\n\n        return true;\n    }\n\n    private static bool IsFSharpAsyncOpenGenericType(Type possibleFSharpAsyncGenericType)\n    {\n        var typeFullName = possibleFSharpAsyncGenericType?.FullName;\n        if (!string.Equals(typeFullName, \"Microsoft.FSharp.Control.FSharpAsync`1\", StringComparison.Ordinal))\n            return false;\n\n        lock (_fsharpValuesCacheLock)\n        {\n            if (_fsharpCoreAssembly != null)\n                // Since we've already found the real FSharpAsync.Core assembly, we just have\n                // to check that the supplied FSharpAsync`1 type is the one from that assembly.\n                return possibleFSharpAsyncGenericType.Assembly == _fsharpCoreAssembly;\n            // We'll keep trying to find the FSharp types/values each time any type called\n            // FSharpAsync`1 is supplied.\n            return TryPopulateFSharpValueCaches(possibleFSharpAsyncGenericType);\n        }\n    }\n\n    private static bool TryPopulateFSharpValueCaches(Type possibleFSharpAsyncGenericType)\n    {\n        var assembly = possibleFSharpAsyncGenericType.Assembly;\n        var fsharpOptionType = assembly.GetType(\"Microsoft.FSharp.Core.FSharpOption`1\");\n        var fsharpAsyncType = assembly.GetType(\"Microsoft.FSharp.Control.FSharpAsync\");\n\n        if (fsharpOptionType == null || fsharpAsyncType == null) return false;\n\n        // Get a reference to FSharpOption<TaskCreationOptions>.None\n        var fsharpOptionOfTaskCreationOptionsType = fsharpOptionType\n            .MakeGenericType(typeof(TaskCreationOptions));\n        _fsharpOptionOfTaskCreationOptionsNoneProperty = fsharpOptionOfTaskCreationOptionsType\n            .GetRuntimeProperty(\"None\");\n\n        // Get a reference to FSharpOption<CancellationToken>.None\n        var fsharpOptionOfCancellationTokenType = fsharpOptionType\n            .MakeGenericType(typeof(CancellationToken));\n        _fsharpOptionOfCancellationTokenNoneProperty = fsharpOptionOfCancellationTokenType\n            .GetRuntimeProperty(\"None\");\n\n        // Get a reference to FSharpAsync.StartAsTask<>\n        var fsharpAsyncMethods = fsharpAsyncType\n            .GetRuntimeMethods()\n            .Where(m => m.Name.Equals(\"StartAsTask\", StringComparison.Ordinal));\n        foreach (var candidateMethodInfo in fsharpAsyncMethods)\n        {\n            var parameters = candidateMethodInfo.GetParameters();\n            if (parameters.Length == 3\n                && TypesHaveSameIdentity(parameters[0].ParameterType, possibleFSharpAsyncGenericType)\n                && parameters[1].ParameterType == fsharpOptionOfTaskCreationOptionsType\n                && parameters[2].ParameterType == fsharpOptionOfCancellationTokenType)\n            {\n                // This really does look like the correct method (and hence assembly).\n                _fsharpAsyncStartAsTaskGenericMethod = candidateMethodInfo;\n                _fsharpCoreAssembly = assembly;\n                break;\n            }\n        }\n\n        return _fsharpCoreAssembly != null;\n    }\n\n    private static bool TypesHaveSameIdentity(Type type1, Type type2)\n    {\n        return type1.Assembly == type2.Assembly\n               && string.Equals(type1.Namespace, type2.Namespace, StringComparison.Ordinal)\n               && string.Equals(type1.Name, type2.Name, StringComparison.Ordinal);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/PublisherSentFailedException.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\n\nnamespace DotNetCore.CAP.Internal;\n\npublic class PublisherSentFailedException : Exception\n{\n    public PublisherSentFailedException(string message) : base(message)\n    {\n    }\n\n    public PublisherSentFailedException(string message, Exception? ex) : base(message, ex)\n    {\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/ScheduledMediumMessageQueue.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Persistence;\n\nnamespace DotNetCore.CAP.Internal;\n\npublic class ScheduledMediumMessageQueue\n{\n    private readonly SortedSet<(long, MediumMessage)> _queue = new(Comparer<(long, MediumMessage)>.Create((a, b) =>\n    {\n        int result = a.Item1.CompareTo(b.Item1);\n        return result == 0 ? String.Compare(a.Item2.DbId, b.Item2.DbId, StringComparison.Ordinal) : result;\n    }));\n\n    private readonly SemaphoreSlim _semaphore = new(0);\n    private readonly object _lock = new();\n\n    public void Enqueue(MediumMessage message, long sendTime)\n    {\n        lock (_lock)\n        {\n            _queue.Add((sendTime, message));\n        }\n        \n        _semaphore.Release();\n    }\n    \n    public int Count\n    {\n        get\n        {\n            lock (_lock)\n            {\n                return _queue.Count;\n            }\n        }\n    }\n    \n    public IEnumerable<MediumMessage> UnorderedItems\n    {\n        get\n        {\n            lock (_lock)\n            {\n                return _queue.Select(x => x.Item2).ToList();\n            }\n        }\n    }\n    \n    public async IAsyncEnumerable<MediumMessage> GetConsumingEnumerable([EnumeratorCancellation] CancellationToken cancellationToken = default)\n    {\n        while (!cancellationToken.IsCancellationRequested)\n        {\n            await _semaphore.WaitAsync(cancellationToken);\n\n            (long, MediumMessage)? nextItem = null;\n\n            lock (_lock)\n            {\n                if (_queue.Count > 0)\n                {\n                    var topMessage = _queue.First();\n                    var timeLeft = topMessage.Item1 - DateTime.Now.Ticks;\n                    if (timeLeft < 500000) // 50ms\n                    {\n                        nextItem = topMessage;\n                        _queue.Remove(topMessage);\n                    }\n                }\n            }\n\n            if (nextItem is not null)\n            {\n                yield return nextItem.Value.Item2;\n            }\n            else\n            {\n                // Re-release the semaphore if no item is ready yet\n                _semaphore.Release();\n                await Task.Delay(50, cancellationToken);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/StatusName.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nnamespace DotNetCore.CAP.Internal;\n\n/// <summary>\n/// The message status name.\n/// </summary>\npublic enum StatusName\n{\n    Failed = -1,\n    Scheduled,\n    Succeeded,\n\n    Delayed,\n    Queued\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/SubscriberExecutionFailedException.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\n\nnamespace DotNetCore.CAP.Internal;\n\ninternal class SubscriberExecutionFailedException : Exception\n{\n    private readonly Exception _originException;\n\n    public SubscriberExecutionFailedException(string message, Exception ex) : base(message, ex)\n    {\n        _originException = ex;\n    }\n\n    public override string? StackTrace => _originException.StackTrace;\n\n    public override string? Source => _originException.Source;\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Internal/TopicAttribute.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\n\nnamespace DotNetCore.CAP.Internal;\n\n/// <inheritdoc />\n/// <summary>\n/// An abstract attribute that for kafka attribute or rabbit mq attribute\n/// </summary>\n[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)]\npublic abstract class TopicAttribute : Attribute\n{\n    protected TopicAttribute(string name, bool isPartial = false)\n    {\n        Name = name;\n        IsPartial = isPartial;\n    }\n\n    /// <summary>\n    /// Topic or exchange route key name.\n    /// </summary>\n    public string Name { get; }\n\n    /// <summary>\n    /// Defines whether this attribute defines a topic subscription partial.\n    /// The defined topic will be combined with a topic subscription defined on class level,\n    /// which results for example in subscription on \"class.method\".\n    /// </summary>\n    public bool IsPartial { get; }\n\n    /// <summary>\n    /// Default group name is CapOptions setting.(Assembly name)\n    /// Kafka --> groups.id\n    /// RabbitMQ --> queue.name\n    /// </summary>\n    public string Group { get; set; } = default!;\n\n    /// <summary>\n    /// Limit the number of messages consumed concurrently.\n    /// If you set this value but don't specify the Group, we will automatically create a Group using the Name.\n    /// </summary>\n    public byte GroupConcurrent { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Messages/FailedInfo.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\n\nnamespace DotNetCore.CAP.Messages;\n\n/// <summary>\n/// Contains information about a message that has failed processing and exceeded the retry threshold.\n/// This class is used when invoking the <see cref=\"CapOptions.FailedThresholdCallback\"/> callback.\n/// </summary>\npublic class FailedInfo\n{\n    /// <summary>\n    /// Gets or sets the service provider for the current scope.\n    /// This allows the callback to resolve dependencies from the dependency injection container.\n    /// </summary>\n    public IServiceProvider ServiceProvider { get; set; } = default!;\n\n    /// <summary>\n    /// Gets or sets the message type indicating whether this was a published or subscribed message.\n    /// <see cref=\"MessageType.Publish\"/> for messages that failed to be sent to the broker.\n    /// <see cref=\"MessageType.Subscribe\"/> for messages that failed to be processed by subscribers.\n    /// </summary>\n    public MessageType MessageType { get; set; }\n\n    /// <summary>\n    /// Gets or sets the message object that failed processing.\n    /// Contains the headers and value data that caused the failure.\n    /// </summary>\n    public Message Message { get; set; } = default!;\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Messages/Headers.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nnamespace DotNetCore.CAP.Messages;\n\n/// <summary>\n/// Defines the standard header names used in CAP messages.\n/// These headers carry metadata and system information that controls message routing, tracking, and processing.\n/// </summary>\npublic static class Headers\n{\n    /// <summary>\n    /// Unique identifier for the message.\n    /// Can be set explicitly when publishing a message, or automatically assigned by CAP.\n    /// This ID is used to track and correlate messages throughout their lifecycle.\n    /// Value: \"cap-msg-id\"\n    /// </summary>\n    public const string MessageId = \"cap-msg-id\";\n\n    /// <summary>\n    /// The topic or message name that identifies what kind of message this is.\n    /// Used for routing to the correct subscribers.\n    /// Value: \"cap-msg-name\"\n    /// </summary>\n    public const string MessageName = \"cap-msg-name\";\n\n    /// <summary>\n    /// The consumer group that should receive this message.\n    /// In Kafka, this maps to the consumer group; in RabbitMQ, it maps to the queue name.\n    /// Value: \"cap-msg-group\"\n    /// </summary>\n    public const string Group = \"cap-msg-group\";\n\n    /// <summary>\n    /// The .NET type name of the message value/payload.\n    /// Used during deserialization to reconstruct the original object type.\n    /// Value: \"cap-msg-type\"\n    /// </summary>\n    public const string Type = \"cap-msg-type\";\n\n    /// <summary>\n    /// Correlation ID for linking related messages in a message flow or saga pattern.\n    /// Allows tracing a chain of messages across different topics and services.\n    /// Value: \"cap-corr-id\"\n    /// </summary>\n    public const string CorrelationId = \"cap-corr-id\";\n\n    /// <summary>\n    /// Sequence number for ordering correlated messages.\n    /// Indicates the position of this message in a correlated sequence.\n    /// Value: \"cap-corr-seq\"\n    /// </summary>\n    public const string CorrelationSequence = \"cap-corr-seq\";\n\n    /// <summary>\n    /// Name of the subscriber callback handler that should process the response to this message.\n    /// Used in request-response patterns where a subscriber needs to send a reply.\n    /// Value: \"cap-callback-name\"\n    /// </summary>\n    public const string CallbackName = \"cap-callback-name\";\n\n    /// <summary>\n    /// Identifier of the application instance that executed or is executing the message.\n    /// Useful in distributed systems to track which instance processed a message.\n    /// Value: \"cap-exec-instance-id\"\n    /// </summary>\n    public const string ExecutionInstanceId = \"cap-exec-instance-id\";\n\n    /// <summary>\n    /// Timestamp indicating when the message was sent/published, in UTC ISO 8601 format.\n    /// Value: \"cap-senttime\"\n    /// </summary>\n    public const string SentTime = \"cap-senttime\";\n\n    /// <summary>\n    /// Timestamp indicating when a delayed message should be published, in UTC ISO 8601 format.\n    /// This header is only present for messages scheduled for delayed delivery.\n    /// Value: \"cap-delaytime\"\n    /// </summary>\n    public const string DelayTime = \"cap-delaytime\";\n\n    /// <summary>\n    /// Exception information if the message processing failed.\n    /// Contains the exception type name and message formatted as \"ExceptionTypeName-->ExceptionMessage\".\n    /// Value: \"cap-exception\"\n    /// </summary>\n    public const string Exception = \"cap-exception\";\n\n    /// <summary>\n    /// W3C Trace Context parent trace ID for distributed tracing and OpenTelemetry integration.\n    /// Enables correlation of messages with the broader application trace.\n    /// Value: \"traceparent\"\n    /// </summary>\n    public const string TraceParent = \"traceparent\"; \n}"
  },
  {
    "path": "src/DotNetCore.CAP/Messages/Message.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\n\nnamespace DotNetCore.CAP.Messages;\n\n/// <summary>\n/// Represents a message in the CAP system, containing metadata headers and the message content value.\n/// Messages are the fundamental unit of communication in CAP's publish-subscribe model.\n/// </summary>\n/// <remarks>\n/// A message consists of:\n/// <list type=\"bullet\">\n/// <item><description>Headers: Metadata about the message (ID, name, group, correlation tracking, etc.)</description></item>\n/// <item><description>Value: The actual message payload that may be serialized to/from JSON</description></item>\n/// </list>\n/// The class requires a parameterless constructor and public property setters for System.Text.Json serialization support.\n/// </remarks>\npublic class Message\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"Message\"/> class with an empty headers dictionary.\n    /// This constructor is required for System.Text.Json deserialization.\n    /// </summary>\n    public Message()\n    {\n        Headers = new Dictionary<string, string?>();\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"Message\"/> class with specified headers and value.\n    /// </summary>\n    /// <param name=\"headers\">\n    /// A dictionary of message metadata headers (e.g., MessageId, MessageName, Group).\n    /// This dictionary is used directly, not copied.\n    /// </param>\n    /// <param name=\"value\">\n    /// The message payload or content. Can be any serializable object or null.\n    /// </param>\n    /// <exception cref=\"ArgumentNullException\">Thrown if <paramref name=\"headers\"/> is null.</exception>\n    public Message(IDictionary<string, string?> headers, object? value)\n    {\n        Headers = headers ?? throw new ArgumentNullException(nameof(headers));\n        Value = value;\n    }\n\n    /// <summary>\n    /// Gets or sets the message metadata headers as a dictionary of string key-value pairs.\n    /// Headers contain system information (MessageId, MessageName, etc.) and custom application data.\n    /// </summary>\n    public IDictionary<string, string?> Headers { get; set; }\n\n    /// <summary>\n    /// Gets or sets the message payload or content.\n    /// This is the actual data being transmitted and may be serialized as JSON or other formats.\n    /// </summary>\n    public object? Value { get; set; }\n}\n\n/// <summary>\n/// Provides extension methods for working with <see cref=\"Message\"/> objects,\n/// including header access, metadata retrieval, and exception handling.\n/// </summary>\npublic static class MessageExtensions\n{\n    /// <summary>\n    /// Retrieves the unique message identifier from the message headers.\n    /// </summary>\n    /// <param name=\"message\">The message to retrieve the ID from.</param>\n    /// <returns>The message ID stored in the <see cref=\"Headers.MessageId\"/> header.</returns>\n    /// <exception cref=\"KeyNotFoundException\">Thrown if the MessageId header is not present.</exception>\n    public static string GetId(this Message message)\n    {\n        return message.Headers[Headers.MessageId]!;\n    }\n\n    /// <summary>\n    /// Retrieves the message name or topic from the message headers.\n    /// The message name identifies the topic, exchange, or subject the message relates to.\n    /// </summary>\n    /// <param name=\"message\">The message to retrieve the name from.</param>\n    /// <returns>The message name stored in the <see cref=\"Headers.MessageName\"/> header.</returns>\n    /// <exception cref=\"KeyNotFoundException\">Thrown if the MessageName header is not present.</exception>\n    public static string GetName(this Message message)\n    {\n        return message.Headers[Headers.MessageName]!;\n    }\n\n    /// <summary>\n    /// Attempts to retrieve the callback subscriber name from the message headers.\n    /// The callback name identifies which subscriber should process the response.\n    /// </summary>\n    /// <param name=\"message\">The message to retrieve the callback name from.</param>\n    /// <returns>The callback subscriber name, or null if not specified in the headers.</returns>\n    public static string? GetCallbackName(this Message message)\n    {\n        message.Headers.TryGetValue(Headers.CallbackName, out var value);\n        return value;\n    }\n\n    /// <summary>\n    /// Attempts to retrieve the consumer group name from the message headers.\n    /// The group name identifies which subscriber group should consume the message.\n    /// </summary>\n    /// <param name=\"message\">The message to retrieve the group from.</param>\n    /// <returns>The consumer group name, or null if not specified in the headers.</returns>\n    public static string? GetGroup(this Message message)\n    {\n        message.Headers.TryGetValue(Headers.Group, out var value);\n        return value;\n    }\n\n    /// <summary>\n    /// Retrieves the correlation sequence number from the message headers.\n    /// This number is used for ordering and tracking correlated message sequences.\n    /// </summary>\n    /// <param name=\"message\">The message to retrieve the correlation sequence from.</param>\n    /// <returns>\n    /// The correlation sequence number, or 0 if the header is not present.\n    /// </returns>\n    public static int GetCorrelationSequence(this Message message)\n    {\n        if (message.Headers.TryGetValue(Headers.CorrelationSequence, out var value)) return int.Parse(value!);\n\n        return 0;\n    }\n\n    /// <summary>\n    /// Attempts to retrieve the execution instance ID from the message headers.\n    /// This ID tracks which application instance executed the message processing.\n    /// </summary>\n    /// <param name=\"message\">The message to retrieve the execution instance ID from.</param>\n    /// <returns>The execution instance ID, or null if not specified in the headers.</returns>\n    public static string? GetExecutionInstanceId(this Message message)\n    {\n        message.Headers.TryGetValue(Headers.ExecutionInstanceId, out var value);\n        return value;\n    }\n\n    /// <summary>\n    /// Determines whether the message has an associated exception record.\n    /// This indicates that processing of the message encountered an error.\n    /// </summary>\n    /// <param name=\"message\">The message to check for an exception.</param>\n    /// <returns>true if the message has an exception header; otherwise false.</returns>\n    public static bool HasException(this Message message)\n    {\n        return message.Headers.ContainsKey(Headers.Exception);\n    }\n\n    /// <summary>\n    /// Adds or updates the exception information in the message headers.\n    /// The exception is formatted as \"ExceptionTypeName-->ExceptionMessage\".\n    /// </summary>\n    /// <param name=\"message\">The message to add the exception to.</param>\n    /// <param name=\"ex\">The exception to record in the message.</param>\n    public static void AddOrUpdateException(this Message message, Exception ex)\n    {\n        var msg = $\"{ex.GetType().Name}-->{ex.Message}\";\n\n        message.Headers[Headers.Exception] = msg;\n    }\n\n    /// <summary>\n    /// Removes the exception information from the message headers.\n    /// Use this to clear error information after handling or retrying a failed message.\n    /// </summary>\n    /// <param name=\"message\">The message to remove the exception from.</param>\n    public static void RemoveException(this Message message)\n    {\n        message.Headers.Remove(Headers.Exception);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Messages/MessageType.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nnamespace DotNetCore.CAP.Messages;\n\n/// <summary>\n/// Specifies the type of message in the CAP system.\n/// </summary>\npublic enum MessageType\n{\n    /// <summary>\n    /// Indicates a message that was published by the application and is waiting for delivery to subscribers.\n    /// These are outgoing messages.\n    /// </summary>\n    Publish,\n\n    /// <summary>\n    /// Indicates a message that was received by the subscriber from the message broker.\n    /// These are incoming messages.\n    /// </summary>\n    Subscribe\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Messages/TransportMessage.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Runtime.InteropServices;\n\nnamespace DotNetCore.CAP.Messages;\n\n/// <summary>\n/// Represents a message in transit between the message broker and application.\n/// This struct encapsulates the message headers (metadata) and body (serialized content) as received from or sent to a broker.\n/// </summary>\n/// <remarks>\n/// This is a value type optimized for performance when passing messages through the message processing pipeline.\n/// Unlike <see cref=\"Message\"/>, this struct works with raw byte data rather than deserialized objects,\n/// making it suitable for transport-level operations.\n/// </remarks>\n[StructLayout(LayoutKind.Auto)]\npublic readonly struct TransportMessage\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"TransportMessage\"/> struct with the specified headers and body.\n    /// </summary>\n    /// <param name=\"headers\">\n    /// A dictionary of message metadata headers (MessageId, MessageName, Group, etc.).\n    /// </param>\n    /// <param name=\"body\">\n    /// The raw message body as bytes. This is typically a UTF-8 encoded JSON string.\n    /// </param>\n    /// <exception cref=\"ArgumentNullException\">Thrown if <paramref name=\"headers\"/> is null.</exception>\n    public TransportMessage(IDictionary<string, string?> headers, ReadOnlyMemory<byte> body)\n    {\n        Headers = headers ?? throw new ArgumentNullException(nameof(headers));\n        Body = body;\n    }\n\n    /// <summary>\n    /// Gets the metadata headers of this message.\n    /// Headers contain system information such as message ID, name, group, and custom application data.\n    /// </summary>\n    public IDictionary<string, string?> Headers { get; }\n\n    /// <summary>\n    /// Gets the raw message body as a read-only byte buffer.\n    /// This typically contains UTF-8 encoded JSON or other serialized content.\n    /// </summary>\n    public ReadOnlyMemory<byte> Body { get; }\n\n    /// <summary>\n    /// Retrieves the unique message identifier from the message headers.\n    /// </summary>\n    /// <returns>The message ID stored in the <see cref=\"Messages.Headers.MessageId\"/> header.</returns>\n    /// <exception cref=\"KeyNotFoundException\">Thrown if the MessageId header is not present.</exception>\n    public string GetId()\n    {\n        return Headers[Messages.Headers.MessageId]!;\n    }\n\n    /// <summary>\n    /// Retrieves the message name or topic from the message headers.\n    /// </summary>\n    /// <returns>The message name stored in the <see cref=\"Messages.Headers.MessageName\"/> header.</returns>\n    /// <exception cref=\"KeyNotFoundException\">Thrown if the MessageName header is not present.</exception>\n    public string GetName()\n    {\n        return Headers[Messages.Headers.MessageName]!;\n    }\n\n    /// <summary>\n    /// Attempts to retrieve the consumer group name from the message headers.\n    /// </summary>\n    /// <returns>\n    /// The consumer group name if present, or null if the <see cref=\"Messages.Headers.Group\"/> header is not set.\n    /// </returns>\n    public string? GetGroup()\n    {\n        return Headers.TryGetValue(Messages.Headers.Group, out var value) ? value : null;\n    }\n\n    /// <summary>\n    /// Attempts to retrieve the correlation ID from the message headers.\n    /// The correlation ID links related messages in a message flow or saga pattern.\n    /// </summary>\n    /// <returns>\n    /// The correlation ID if present, or null if the <see cref=\"Messages.Headers.CorrelationId\"/> header is not set.\n    /// </returns>\n    public string? GetCorrelationId()\n    {\n        return Headers.TryGetValue(Messages.Headers.CorrelationId, out var value) ? value : null;\n    }\n\n    /// <summary>\n    /// Attempts to retrieve the execution instance ID from the message headers.\n    /// This ID identifies which application instance executed the message.\n    /// </summary>\n    /// <returns>\n    /// The execution instance ID if present, or null if the <see cref=\"Messages.Headers.ExecutionInstanceId\"/> header is not set.\n    /// </returns>\n    public string? GetExecutionInstanceId()\n    {\n        return Headers.TryGetValue(Messages.Headers.ExecutionInstanceId, out var value) ? value : null;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Monitoring/IMonitoringApi.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Persistence;\n\nnamespace DotNetCore.CAP.Monitoring;\n\npublic interface IMonitoringApi\n{\n    Task<MediumMessage?> GetPublishedMessageAsync(long id);\n\n    Task<MediumMessage?> GetReceivedMessageAsync(long id);\n\n    Task<StatisticsDto> GetStatisticsAsync();\n\n    Task<PagedQueryResult<MessageDto>> GetMessagesAsync(MessageQueryDto queryDto);\n\n    ValueTask<int> PublishedFailedCount();\n\n    ValueTask<int> PublishedSucceededCount();\n\n    ValueTask<int> ReceivedFailedCount();\n\n    ValueTask<int> ReceivedSucceededCount();\n\n    Task<IDictionary<DateTime, int>> HourlySucceededJobs(MessageType type);\n\n    Task<IDictionary<DateTime, int>> HourlyFailedJobs(MessageType type);\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Monitoring/MessageDto.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\n\nnamespace DotNetCore.CAP.Monitoring;\n\npublic class MessageDto\n{\n    public string Id { get; set; } = default!;\n\n    public string Version { get; set; } = default!;\n\n    public string? Group { get; set; }\n\n    public string Name { get; set; } = default!;\n\n    public string? Content { get; set; }\n\n    public DateTime Added { get; set; }\n\n    public DateTime? ExpiresAt { get; set; }\n\n    public int Retries { get; set; }\n\n    public string StatusName { get; set; } = default!;\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Monitoring/MessageQueryDto.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing DotNetCore.CAP.Messages;\n\nnamespace DotNetCore.CAP.Monitoring;\n\npublic class MessageQueryDto\n{\n    public MessageType MessageType { get; set; }\n\n    public string? Group { get; set; }\n\n    public string? Name { get; set; }\n\n    public string? Content { get; set; }\n\n    public string? StatusName { get; set; }\n\n    public int CurrentPage { get; set; }\n\n    public int PageSize { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Monitoring/PagedQueryResult.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Collections.Generic;\n\nnamespace DotNetCore.CAP.Monitoring;\n\npublic class PagedQueryResult<T>\n{\n    public IList<T>? Items { get; set; }\n\n    public long Totals { get; set; }\n\n    public int PageIndex { get; set; }\n\n    public int PageSize { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Monitoring/StatisticsDto.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nnamespace DotNetCore.CAP.Monitoring;\n\npublic class StatisticsDto\n{\n    public int Servers { get; set; }\n\n    public int Subscribers { get; set; }\n\n    public int PublishedSucceeded { get; set; }\n\n    public int PublishedDelayed { get; set; }\n\n    public int ReceivedSucceeded { get; set; }\n\n    public int PublishedFailed { get; set; }\n    public int ReceivedFailed { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/OperateResult.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\n\nnamespace DotNetCore.CAP;\n\n/// <summary>\n/// Represents the result of a message operation (publish or consume), including success/failure status and optional error details.\n/// This struct is used throughout CAP to standardize how operation outcomes are reported.\n/// </summary>\n/// <remarks>\n/// The <see cref=\"OperateResult\"/> can represent:\n/// <list type=\"bullet\">\n/// <item><description>Successful operations with <see cref=\"Succeeded\"/> = true.</description></item>\n/// <item><description>Failed operations with <see cref=\"Succeeded\"/> = false, along with an <see cref=\"Exception\"/> and optional <see cref=\"OperateError\"/> details.</description></item>\n/// </list>\n/// Use the static <see cref=\"Success\"/> property for successful results, or the static <see cref=\"Failed\"/> method for failures.\n/// </remarks>\npublic struct OperateResult : IEqualityComparer<OperateResult>\n{\n    private readonly OperateError? _operateError = null;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"OperateResult\"/> struct with the specified status and optional error information.\n    /// </summary>\n    /// <param name=\"succeeded\">A value indicating whether the operation succeeded.</param>\n    /// <param name=\"exception\">The exception that occurred during the operation, or null if successful.</param>\n    /// <param name=\"error\">Additional error details, or null if no structured error information is available.</param>\n    public OperateResult(bool succeeded, Exception? exception = null, OperateError? error = null)\n    {\n        Succeeded = succeeded;\n        Exception = exception;\n        _operateError = error;\n    }\n\n    /// <summary>\n    /// Gets or sets a value indicating whether the operation succeeded.\n    /// </summary>\n    public bool Succeeded { get; set; }\n\n    /// <summary>\n    /// Gets or sets the exception that occurred during the operation.\n    /// This is typically populated when <see cref=\"Succeeded\"/> is false.\n    /// </summary>\n    public Exception? Exception { get; set; }\n\n    /// <summary>\n    /// Gets a static <see cref=\"OperateResult\"/> representing a successful operation.\n    /// </summary>\n    public static OperateResult Success => new(true);\n\n    /// <summary>\n    /// Creates an <see cref=\"OperateResult\"/> representing a failed operation.\n    /// </summary>\n    /// <param name=\"ex\">The exception that caused the failure.</param>\n    /// <param name=\"errors\">Optional structured error information describing the failure.</param>\n    /// <returns>A failed <see cref=\"OperateResult\"/> containing the exception and error details.</returns>\n    public static OperateResult Failed(Exception ex, OperateError? errors = null)\n    {\n        return new(false, ex, errors);\n    }\n\n    /// <summary>\n    /// Returns a string representation of the operation result.\n    /// </summary>\n    /// <returns>\n    /// \"Succeeded\" if the operation was successful; otherwise \"Failed\" with the error code.\n    /// </returns>\n    public override string ToString()\n    {\n        return Succeeded ? \"Succeeded\" : $\"Failed : {_operateError?.Code}\";\n    }\n\n    /// <summary>\n    /// Determines whether two <see cref=\"OperateResult\"/> instances are equal based on their success status.\n    /// </summary>\n    /// <param name=\"x\">The first result to compare.</param>\n    /// <param name=\"y\">The second result to compare.</param>\n    /// <returns>true if both results have the same success status; otherwise false.</returns>\n    public bool Equals(OperateResult x, OperateResult y)\n    {\n        return x.Succeeded == y.Succeeded;\n    }\n\n    /// <summary>\n    /// Serves as the default hash function for the <see cref=\"OperateResult\"/> struct.\n    /// </summary>\n    /// <param name=\"obj\">The result to compute the hash code for.</param>\n    /// <returns>A hash code combining the error, success status, and exception information.</returns>\n    public int GetHashCode(OperateResult obj)\n    {\n        return HashCode.Combine(obj._operateError, obj.Succeeded, obj.Exception);\n    }\n}\n\n/// <summary>\n/// Encapsulates structured error information from a failed operation.\n/// This record provides a standardized way to report operation errors with code and description.\n/// </summary>\npublic record struct OperateError\n{\n    /// <summary>\n    /// Gets or sets the error code identifying the type or source of the error.\n    /// This might be a string representation of a numeric error code, a category name, or other identifier.\n    /// </summary>\n    public string Code { get; set; }\n\n    /// <summary>\n    /// Gets or sets a human-readable description of the error.\n    /// This typically explains what went wrong and may include suggestions for resolution.\n    /// </summary>\n    public string Description { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Persistence/IDataStorage.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Monitoring;\n\nnamespace DotNetCore.CAP.Persistence;\n\npublic interface IDataStorage\n{\n    Task<bool> AcquireLockAsync(string key, TimeSpan ttl, string instance, CancellationToken token = default);\n\n    Task ReleaseLockAsync(string key, string instance, CancellationToken token = default);\n\n    Task RenewLockAsync(string key, TimeSpan ttl, string instance, CancellationToken token = default);\n\n    Task ChangePublishStateToDelayedAsync(string[] ids);\n\n    Task ChangePublishStateAsync(MediumMessage message, StatusName state, object? transaction = null);\n\n    Task ChangeReceiveStateAsync(MediumMessage message, StatusName state);\n\n    Task<MediumMessage> StoreMessageAsync(string name, Message content, object? transaction = null);\n\n    Task StoreReceivedExceptionMessageAsync(string name, string group, string content);\n\n    Task<MediumMessage> StoreReceivedMessageAsync(string name, string group, Message content);\n\n    Task<int> DeleteExpiresAsync(string table, DateTime timeout, int batchCount = 1000, CancellationToken token = default);\n\n    Task<IEnumerable<MediumMessage>> GetPublishedMessagesOfNeedRetry(TimeSpan lookbackSeconds);\n\n    Task ScheduleMessagesOfDelayedAsync(Func<object, IEnumerable<MediumMessage>, Task> scheduleTask, CancellationToken token = default);\n\n    Task<IEnumerable<MediumMessage>> GetReceivedMessagesOfNeedRetry(TimeSpan lookbackSeconds);\n\n    Task<int> DeleteReceivedMessageAsync(long id);\n\n    Task<int> DeletePublishedMessageAsync(long id);\n\n    //dashboard api\n    IMonitoringApi GetMonitoringApi();\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP/Persistence/IStorageInitializer.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace DotNetCore.CAP.Persistence;\n\npublic interface IStorageInitializer\n{\n    Task InitializeAsync(CancellationToken cancellationToken);\n\n    string GetPublishedTableName();\n\n    string GetReceivedTableName();\n\n    string GetLockTableName();\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Persistence/MediumMessage.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP.Messages;\n\nnamespace DotNetCore.CAP.Persistence;\n\npublic class MediumMessage\n{\n    public string DbId { get; set; } = default!;\n\n    public Message Origin { get; set; } = default!;\n\n    public string Content { get; set; } = default!;\n\n    public DateTime Added { get; set; }\n\n    public DateTime? ExpiresAt { get; set; }\n\n    public int Retries { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Processor/IDispatcher.Default.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Channels;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.Processor;\n\npublic class Dispatcher : IDispatcher\n{\n    private readonly ISubscribeExecutor _executor;\n    private readonly ILogger<Dispatcher> _logger;\n    private readonly CapOptions _options;\n    private readonly IMessageSender _sender;\n    private readonly IDataStorage _storage;\n    private readonly ScheduledMediumMessageQueue _schedulerQueue = new();\n    private readonly bool _enableParallelExecute;\n    private readonly bool _enableParallelSend;\n    private readonly int _publishChannelSize;\n\n    private CancellationTokenSource? _tasksCts;\n    private Channel<MediumMessage> _publishedChannel = default!;\n    private Channel<(MediumMessage, ConsumerExecutorDescriptor?)> _receivedChannel = default!;\n    private bool _disposed;\n\n    public Dispatcher(\n        ILogger<Dispatcher> logger,\n        IMessageSender sender,\n        IOptions<CapOptions> options,\n        ISubscribeExecutor executor,\n        IDataStorage storage)\n    {\n        _logger = logger;\n        _sender = sender;\n        _options = options.Value;\n        _executor = executor;\n        _storage = storage;\n        _enableParallelExecute = _options.EnableSubscriberParallelExecute;\n        _enableParallelSend = _options.EnablePublishParallelSend;\n        _publishChannelSize = Environment.ProcessorCount * 500;\n    }\n\n    #region Public Methods\n\n    public async ValueTask StartAsync(CancellationToken stoppingToken)\n    {\n        ResetStateIfNeeded();\n\n        stoppingToken.ThrowIfCancellationRequested();\n        _tasksCts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken, CancellationToken.None);\n\n        InitializePublishedChannel();\n        await StartSendingTaskAsync().ConfigureAwait(false);\n\n        if (_enableParallelExecute)\n        {\n            InitializeReceivedChannel();\n            await StartProcessingTasksAsync().ConfigureAwait(false);\n        }\n\n        _ = StartSchedulerTaskAsync().ConfigureAwait(false);\n    }\n\n    public async Task EnqueueToScheduler(MediumMessage message, DateTime publishTime, object? transaction = null)\n    {\n        message.ExpiresAt = publishTime;\n\n        var timeSpan = publishTime - DateTime.Now;\n        var statusName = timeSpan <= TimeSpan.FromMinutes(1) ? StatusName.Queued : StatusName.Delayed;\n\n        await _storage.ChangePublishStateAsync(message, statusName, transaction).ConfigureAwait(false);\n\n        if (statusName == StatusName.Queued)\n        {\n            _schedulerQueue.Enqueue(message, publishTime.Ticks);\n        }\n    }\n\n    public async ValueTask EnqueueToPublish(MediumMessage message)\n    {\n        try\n        {\n            if (IsCancellationRequested())\n            {\n                _logger.LogWarning(\"The message has been persisted, but CAP is currently stopped. It will be attempted to be sent once CAP becomes available.\");\n                return;\n            }\n\n            if (ShouldUseParallelSend(message))\n            {\n                await WriteToChannelAsync(_publishedChannel, message).ConfigureAwait(false);\n            }\n            else\n            {\n                await SendMessageDirectlyAsync(message).ConfigureAwait(false);\n            }\n        }\n        catch (OperationCanceledException)\n        {\n            // Expected during shutdown\n        }\n    }\n\n    public async ValueTask EnqueueToExecute(MediumMessage message, ConsumerExecutorDescriptor? descriptor = null)\n    {\n        try\n        {\n            if (IsCancellationRequested())\n            {\n                return;\n            }\n\n            if (ShouldUseParallelExecute(message))\n            {\n                await WriteToChannelAsync(_receivedChannel, (message, descriptor)).ConfigureAwait(false);\n            }\n            else\n            {\n                await _executor.ExecuteAsync(message, descriptor, _tasksCts!.Token).ConfigureAwait(false);\n            }\n        }\n        catch (OperationCanceledException)\n        {\n            // Expected during shutdown\n        }\n        catch (Exception e)\n        {\n            _logger.LogError(e, \"An exception occurred when invoke subscriber. MessageId:{MessageId}\", message.DbId);\n        }\n    }\n\n    public void Dispose()\n    {\n        if (_disposed)\n        {\n            return;\n        }\n\n        _disposed = true;\n        _tasksCts?.Dispose();\n    }\n\n    #endregion\n\n    #region Initialization Methods\n\n    private void ResetStateIfNeeded()\n    {\n        if (_disposed || (_tasksCts != null && _tasksCts.IsCancellationRequested))\n        {\n            _tasksCts?.Dispose();\n            _tasksCts = null;\n            _disposed = false;\n        }\n    }\n\n    private void InitializePublishedChannel()\n    {\n        _publishedChannel = Channel.CreateBounded<MediumMessage>(new BoundedChannelOptions(_publishChannelSize)\n        {\n            AllowSynchronousContinuations = true,\n            SingleReader = true,\n            SingleWriter = !_enableParallelSend,\n            FullMode = BoundedChannelFullMode.Wait\n        });\n    }\n\n    private void InitializeReceivedChannel()\n    {\n        var bufferSize = _options.SubscriberParallelExecuteThreadCount * _options.SubscriberParallelExecuteBufferFactor;\n        var isSingleReader = _options.SubscriberParallelExecuteThreadCount == 1;\n\n        _receivedChannel = Channel.CreateBounded<(MediumMessage, ConsumerExecutorDescriptor?)>(\n        new BoundedChannelOptions(bufferSize)\n        {\n            AllowSynchronousContinuations = true,\n            SingleReader = isSingleReader,\n            SingleWriter = true,\n            FullMode = BoundedChannelFullMode.Wait\n        });\n    }\n\n    #endregion\n\n    #region Task Startup Methods\n\n    private async Task StartSendingTaskAsync()\n    {\n        await Task.Run(SendingAsync, _tasksCts!.Token).ConfigureAwait(false);\n    }\n\n    private async Task StartProcessingTasksAsync()\n    {\n        var processingTasks = Enumerable\n            .Range(0, _options.SubscriberParallelExecuteThreadCount)\n            .Select(_ => Task.Run(ProcessingAsync, _tasksCts!.Token))\n            .ToArray();\n\n        await Task.WhenAll(processingTasks).ConfigureAwait(false);\n    }\n\n    private Task StartSchedulerTaskAsync()\n    {\n        return Task.Run(async () =>\n        {\n            RegisterSchedulerCancellationHandler();\n\n            while (!_tasksCts!.Token.IsCancellationRequested)\n            {\n                try\n                {\n                    await ProcessScheduledMessagesAsync().ConfigureAwait(false);\n                    _tasksCts.Token.WaitHandle.WaitOne(100);\n                }\n                catch (OperationCanceledException)\n                {\n                    // Expected during shutdown\n                }\n                catch (Exception ex)\n                {\n                    _logger.LogError(ex,\n                        \"Delay message publishing failed unexpectedly, which will stop future scheduled \" +\n                        \"messages from publishing. See more details here: https://github.com/dotnetcore/CAP/issues/1637. \" +\n                        \"Exception: {Message}\",\n                        ex.Message);\n                    throw;\n                }\n            }\n        }, _tasksCts!.Token);\n    }\n\n    #endregion\n\n    #region Scheduler Methods\n\n    private void RegisterSchedulerCancellationHandler()\n    {\n        _tasksCts!.Token.Register(() =>\n        {\n            try\n            {\n                if (_schedulerQueue.Count == 0)\n                {\n                    return;\n                }\n\n                var messageIds = _schedulerQueue.UnorderedItems.Select(x => x.DbId).ToArray();\n                _storage.ChangePublishStateToDelayedAsync(messageIds)\n                        .ConfigureAwait(false)\n                        .GetAwaiter()\n                        .GetResult();\n                _logger.LogDebug(\"Update storage to delayed success of delayed message in memory queue!\");\n            }\n            catch (Exception e)\n            {\n                _logger.LogWarning(e, \"Update storage fails of delayed message in memory queue!\");\n            }\n        });\n    }\n\n    private async Task ProcessScheduledMessagesAsync()\n    {\n        await foreach (var nextMessage in _schedulerQueue.GetConsumingEnumerable(_tasksCts!.Token))\n        {\n            _tasksCts.Token.ThrowIfCancellationRequested();\n\n            if (ShouldUseParallelSend(nextMessage))\n            {\n                await WriteToChannelAsync(_publishedChannel, nextMessage).ConfigureAwait(false);\n            }\n            else\n            {\n                await SendScheduledMessageDirectlyAsync(nextMessage).ConfigureAwait(false);\n            }\n        }\n    }\n\n    private async Task SendScheduledMessageDirectlyAsync(MediumMessage message)\n    {\n        try\n        {\n            var result = await _sender.SendAsync(message).ConfigureAwait(false);\n            if (!result.Succeeded)\n            {\n                _logger.LogError(\"Delay message sending failed. MessageId: {MessageId} \", message.DbId);\n            }\n        }\n        catch (Exception ex)\n        {\n            _logger.LogError(ex, \"Error sending scheduled message. MessageId: {MessageId}\", message.DbId);\n        }\n    }\n\n    #endregion\n\n    #region Background Workers - Sending\n\n    private async ValueTask SendingAsync()\n    {\n        try\n        {\n            while (await _publishedChannel.Reader.WaitToReadAsync(_tasksCts!.Token).ConfigureAwait(false))\n            {\n                if (_enableParallelSend)\n                {\n                    await SendBatchParallelAsync().ConfigureAwait(false);\n                }\n                else\n                {\n                    await SendBatchSequentialAsync().ConfigureAwait(false);\n                }\n            }\n        }\n        catch (OperationCanceledException)\n        {\n            // Expected during shutdown\n        }\n    }\n\n    private async Task SendBatchParallelAsync()\n    {\n        var batchSize = Math.Max(1, _publishChannelSize / 50);\n        var tasks = new List<Task>(batchSize);\n\n        for (var i = 0; i < batchSize && _publishedChannel.Reader.TryRead(out var message); i++)\n        {\n            tasks.Add(SendMessageAsync(message));\n        }\n\n        if (tasks.Count > 0)\n        {\n            await Task.WhenAll(tasks).ConfigureAwait(false);\n        }\n    }\n\n    private async Task SendBatchSequentialAsync()\n    {\n        while (_publishedChannel.Reader.TryRead(out var message))\n        {\n            await SendMessageAsync(message).ConfigureAwait(false);\n        }\n    }\n\n    private async Task SendMessageAsync(MediumMessage message)\n    {\n        try\n        {\n            var result = await _sender.SendAsync(message).ConfigureAwait(false);\n            if (!result.Succeeded)\n            {\n                _logger.MessagePublishException(message.Origin.GetId(), result.ToString(), result.Exception);\n            }\n        }\n        catch (Exception ex)\n        {\n            _logger.LogError(ex, \"An exception occurred when sending a message to the transport. Id:{MessageId}\", message.DbId);\n        }\n    }\n\n    private async Task SendMessageDirectlyAsync(MediumMessage message)\n    {\n        var result = await _sender.SendAsync(message).ConfigureAwait(false);\n        if (!result.Succeeded)\n        {\n            _logger.MessagePublishException(message.Origin.GetId(), result.ToString(), result.Exception);\n        }\n    }\n\n    #endregion\n\n    #region Background Workers - Processing\n\n    private async ValueTask ProcessingAsync()\n    {\n        try\n        {\n            while (await _receivedChannel.Reader.WaitToReadAsync(_tasksCts!.Token).ConfigureAwait(false))\n            {\n                while (_receivedChannel.Reader.TryRead(out var messageData))\n                {\n                    await ProcessReceivedMessageAsync(messageData).ConfigureAwait(false);\n                }\n            }\n        }\n        catch (OperationCanceledException)\n        {\n            // Expected during shutdown\n        }\n    }\n\n    private async Task ProcessReceivedMessageAsync((MediumMessage, ConsumerExecutorDescriptor?) messageData)\n    {\n        try\n        {\n            var (message, descriptor) = messageData;\n            await _executor.ExecuteAsync(message, descriptor, _tasksCts!.Token).ConfigureAwait(false);\n        }\n        catch (OperationCanceledException)\n        {\n            // Expected during shutdown\n        }\n        catch (Exception e)\n        {\n            _logger.LogError(e, \"An exception occurred when invoke subscriber. MessageId:{MessageId}\", messageData.Item1.DbId);\n        }\n    }\n\n    #endregion\n\n    #region Helper Methods\n\n    private bool IsCancellationRequested()\n    {\n        return _tasksCts?.IsCancellationRequested ?? true;\n    }\n\n    private bool ShouldUseParallelSend(MediumMessage message)\n    {\n        return _enableParallelSend && message.Retries == 0;\n    }\n\n    private bool ShouldUseParallelExecute(MediumMessage message)\n    {\n        return _enableParallelExecute && message.Retries == 0;\n    }\n\n    private async ValueTask WriteToChannelAsync<T>(Channel<T> channel, T item)\n    {\n        if (!channel.Writer.TryWrite(item))\n        {\n            while (await channel.Writer.WaitToWriteAsync(_tasksCts!.Token).ConfigureAwait(false))\n            {\n                if (channel.Writer.TryWrite(item))\n                {\n                    break;\n                }\n            }\n        }\n    }\n\n    #endregion\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\n\nnamespace DotNetCore.CAP.Processor;\n\npublic class CapProcessingServer : IProcessingServer\n{\n    private CancellationTokenSource _cts;\n    private readonly ILogger _logger;\n    private readonly ILoggerFactory _loggerFactory;\n    private readonly IServiceProvider _provider;\n\n    private Task? _compositeTask;\n    private ProcessingContext _context = default!;\n    private bool _disposed;\n\n    public CapProcessingServer(\n        ILogger<CapProcessingServer> logger,\n        ILoggerFactory loggerFactory,\n        IServiceProvider provider)\n    {\n        _logger = logger;\n        _loggerFactory = loggerFactory;\n        _provider = provider;\n        _cts = new CancellationTokenSource();\n    }\n\n    public ValueTask StartAsync(CancellationToken stoppingToken)\n    {\n        // If already disposed and restarting, recreate the CancellationTokenSource\n        if (_disposed || _cts.IsCancellationRequested)\n        {\n            _cts?.Dispose();\n            _cts = new CancellationTokenSource();\n            _disposed = false;\n        }\n\n        stoppingToken.Register(() => _cts.Cancel());\n\n        _logger.ServerStarting();\n\n        _context = new ProcessingContext(_provider, _cts.Token);\n\n        var processorTasks = GetProcessors()\n            .Select(InfiniteRetry)\n            .Select(p => p.ProcessAsync(_context));\n         _compositeTask = Task.WhenAll(processorTasks);\n\n        return ValueTask.CompletedTask;\n    }\n\n    public void Dispose()\n    {\n        if (_disposed) return;\n\n        try\n        {\n            _disposed = true;\n\n            _logger.ServerShuttingDown();\n            _cts.Cancel();\n\n            _compositeTask?.Wait((int)TimeSpan.FromSeconds(10).TotalMilliseconds);\n        }\n        catch (AggregateException ex)\n        {\n            var innerEx = ex.InnerExceptions[0];\n            if (!(innerEx is OperationCanceledException)) _logger.ExpectedOperationCanceledException(innerEx);\n        }\n        catch (Exception ex)\n        {\n            _logger.LogWarning(ex, \"An exception was occurred when disposing.\");\n        }\n        finally\n        {\n            _logger.LogInformation(\"### CAP shutdown!\");\n            GC.SuppressFinalize(this);\n        }\n    }\n\n    private IProcessor InfiniteRetry(IProcessor inner)\n    {\n        return new InfiniteRetryProcessor(inner, _loggerFactory);\n    }\n\n    private IProcessor[] GetProcessors()\n    {\n        var returnedProcessors = new List<IProcessor>\n        {\n            _provider.GetRequiredService<TransportCheckProcessor>(),\n            _provider.GetRequiredService<MessageNeedToRetryProcessor>(),\n            _provider.GetRequiredService<MessageDelayedProcessor>(),\n            _provider.GetRequiredService<CollectorProcessor>()\n        };\n\n        return returnedProcessors.ToArray();\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Processor/IProcessor.Collector.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Persistence;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.Processor;\n\npublic class CollectorProcessor : IProcessor\n{\n    private const int ItemBatch = 1000;\n    private readonly TimeSpan _delay = TimeSpan.FromSeconds(1);\n    private readonly ILogger _logger;\n    private readonly IServiceProvider _serviceProvider;\n\n    private readonly string[] _tableNames;\n    private readonly TimeSpan _waitingInterval;\n\n    public CollectorProcessor(ILogger<CollectorProcessor> logger, IOptions<CapOptions> options,\n        IServiceProvider serviceProvider)\n    {\n        _logger = logger;\n        _serviceProvider = serviceProvider;\n        _waitingInterval = TimeSpan.FromSeconds(options.Value.CollectorCleaningInterval);\n\n        var initializer = _serviceProvider.GetRequiredService<IStorageInitializer>();\n\n        _tableNames = new[] { initializer.GetPublishedTableName(), initializer.GetReceivedTableName() };\n    }\n\n    public virtual async Task ProcessAsync(ProcessingContext context)\n    {\n        foreach (var table in _tableNames)\n        {\n            _logger.LogDebug($\"Collecting expired data from table: {table}\");\n\n            int deletedCount;\n            var time = DateTime.Now;\n            do\n            {\n                try\n                {\n                    deletedCount = await _serviceProvider.GetRequiredService<IDataStorage>()\n                        .DeleteExpiresAsync(table, time, ItemBatch, context.CancellationToken).ConfigureAwait(false);\n\n                    if (deletedCount != 0)\n                    {\n                        _logger.LogDebug($\"Successfully deleted {deletedCount} expired items from table '{table}'.\");\n\n                        await context.WaitAsync(_delay).ConfigureAwait(false);\n                        context.ThrowIfStopping();\n                    }\n                }\n                catch (Exception ex)\n                {\n                    _logger.LogError(ex, $\"An error occurred while attempting to delete expired data from table '{table}':{ex.Message}\");\n                    throw;\n                }\n\n            } while (deletedCount != 0);\n        }\n\n        await context.WaitAsync(_waitingInterval).ConfigureAwait(false);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Processor/IProcessor.Delayed.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Data.Common;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\n\nnamespace DotNetCore.CAP.Processor;\n\npublic class MessageDelayedProcessor : IProcessor\n{\n    private readonly ILogger<MessageDelayedProcessor> _logger;\n    private readonly IDispatcher _dispatcher;\n    private readonly TimeSpan _waitingInterval;\n\n    public MessageDelayedProcessor(ILogger<MessageDelayedProcessor> logger, IDispatcher dispatcher)\n    {\n        _logger = logger;\n        _dispatcher = dispatcher;\n        _waitingInterval = TimeSpan.FromSeconds(60);\n    }\n\n    public virtual async Task ProcessAsync(ProcessingContext context)\n    {\n        if (context == null) throw new ArgumentNullException(nameof(context));\n\n        var storage = context.Provider.GetRequiredService<IDataStorage>();\n\n        await ProcessDelayedAsync(storage, context).ConfigureAwait(false);\n\n        await context.WaitAsync(_waitingInterval).ConfigureAwait(false);\n    }\n\n    private async Task ProcessDelayedAsync(IDataStorage connection, ProcessingContext context)\n    {\n        try\n        {\n            async Task ScheduleTask(object transaction, IEnumerable<MediumMessage> messages)\n            {\n                foreach (var message in messages)\n                {\n                    await _dispatcher.EnqueueToScheduler(message, message.ExpiresAt!.Value, transaction).ConfigureAwait(false);\n                }\n            }\n\n            await connection.ScheduleMessagesOfDelayedAsync(ScheduleTask, context.CancellationToken).ConfigureAwait(false);\n        }\n        catch (DbException ex)\n        {\n            _logger.LogWarning(ex, \"Get delayed messages from storage failed. Retrying...\");\n        }\n        catch (Exception ex)\n        {\n            _logger.LogError(ex, \"Schedule delayed message failed!\");\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Processor/IProcessor.InfiniteRetry.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\n\nnamespace DotNetCore.CAP.Processor;\n\npublic class InfiniteRetryProcessor : IProcessor\n{\n    private readonly IProcessor _inner;\n    private readonly ILogger _logger;\n\n    public InfiniteRetryProcessor(\n        IProcessor inner,\n        ILoggerFactory loggerFactory)\n    {\n        _inner = inner;\n        _logger = loggerFactory.CreateLogger<InfiniteRetryProcessor>();\n    }\n\n    public async Task ProcessAsync(ProcessingContext context)\n    {\n        while (!context.IsStopping)\n            try\n            {\n                await _inner.ProcessAsync(context).ConfigureAwait(false);\n            }\n            catch (OperationCanceledException)\n            {\n                //ignore\n            }\n            catch (Exception ex)\n            {\n                _logger.LogWarning(ex, \"Processor '{ProcessorName}' failed. Retrying...\", _inner.ToString());\n                await context.WaitAsync(TimeSpan.FromSeconds(2)).ConfigureAwait(false);\n            }\n    }\n\n    public override string? ToString()\n    {\n        return _inner.ToString();\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Processor/IProcessor.NeedRetry.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\r\n// Licensed under the MIT License. See License.txt in the project root for license information.\r\n\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Threading.Tasks;\r\nusing DotNetCore.CAP.Internal;\r\nusing DotNetCore.CAP.Persistence;\r\nusing DotNetCore.CAP.Transport;\r\nusing Microsoft.Extensions.DependencyInjection;\r\nusing Microsoft.Extensions.Logging;\r\nusing Microsoft.Extensions.Options;\r\n\r\nnamespace DotNetCore.CAP.Processor;\r\n\r\npublic class MessageNeedToRetryProcessor : IProcessor\r\n{\r\n    private const int MinSuggestedValueForFallbackWindowLookbackSeconds = 30;\r\n    private readonly ILogger<MessageNeedToRetryProcessor> _logger;\r\n    private readonly IDispatcher _dispatcher;\r\n    private readonly TimeSpan _waitingInterval;\r\n    private readonly IOptions<CapOptions> _options;\r\n    private readonly IDataStorage _dataStorage;\r\n    private readonly TimeSpan _ttl;\r\n    private readonly TimeSpan _lookbackSeconds;\r\n    private readonly string _instance;\r\n    private Task? _failedRetryConsumeTask;\r\n\r\n    public MessageNeedToRetryProcessor(IOptions<CapOptions> options, ILogger<MessageNeedToRetryProcessor> logger,\r\n        IDispatcher dispatcher, IDataStorage dataStorage)\r\n    {\r\n        _options = options;\r\n        _logger = logger;\r\n        _dispatcher = dispatcher;\r\n        _waitingInterval = TimeSpan.FromSeconds(options.Value.FailedRetryInterval);\r\n        _lookbackSeconds = TimeSpan.FromSeconds(options.Value.FallbackWindowLookbackSeconds);\r\n        _dataStorage = dataStorage;\r\n        _ttl = _waitingInterval.Add(TimeSpan.FromSeconds(10));\r\n\r\n        _instance = string.Concat(Helper.GetInstanceHostname(), \"_\", Util.GenerateWorkerId(1023));\r\n\r\n        CheckSafeOptionsSet();\r\n    }\r\n\r\n    public virtual async Task ProcessAsync(ProcessingContext context)\r\n    {\r\n        ArgumentNullException.ThrowIfNull(context);\r\n\r\n        var storage = context.Provider.GetRequiredService<IDataStorage>();\r\n\r\n        _ = Task.Run(() => ProcessPublishedAsync(storage, context));\r\n\r\n        if (_options.Value.UseStorageLock && _failedRetryConsumeTask is { IsCompleted: false })\r\n        {\r\n            await _dataStorage.RenewLockAsync($\"received_retry_{_options.Value.Version}\", _ttl, _instance, context.CancellationToken);\r\n\r\n            await context.WaitAsync(_waitingInterval).ConfigureAwait(false);\r\n\r\n            return;\r\n        }\r\n\r\n        _failedRetryConsumeTask = Task.Run(() => ProcessReceivedAsync(storage, context));\r\n\r\n        _ = _failedRetryConsumeTask.ContinueWith(_ => { _failedRetryConsumeTask = null; });\r\n\r\n        await context.WaitAsync(_waitingInterval).ConfigureAwait(false);\r\n    }\r\n\r\n    private async Task ProcessPublishedAsync(IDataStorage connection, ProcessingContext context)\r\n    {\r\n        context.ThrowIfStopping();\r\n\r\n        if (_options.Value.UseStorageLock && !await connection.AcquireLockAsync($\"publish_retry_{_options.Value.Version}\", _ttl, _instance, context.CancellationToken))\r\n            return;\r\n\r\n        var messages = await GetSafelyAsync(connection.GetPublishedMessagesOfNeedRetry, _lookbackSeconds).ConfigureAwait(false);\r\n\r\n        foreach (var message in messages)\r\n        {\r\n            context.ThrowIfStopping();\r\n\r\n            await _dispatcher.EnqueueToPublish(message).ConfigureAwait(false);\r\n        }\r\n\r\n        if (_options.Value.UseStorageLock)\r\n            await connection.ReleaseLockAsync($\"publish_retry_{_options.Value.Version}\", _instance, context.CancellationToken);\r\n    }\r\n\r\n    private async Task ProcessReceivedAsync(IDataStorage connection, ProcessingContext context)\r\n    {\r\n        context.ThrowIfStopping();\r\n\r\n        if (_options.Value.UseStorageLock && !await connection.AcquireLockAsync($\"received_retry_{_options.Value.Version}\", _ttl, _instance, context.CancellationToken))\r\n            return;\r\n\r\n        var messages = await GetSafelyAsync(connection.GetReceivedMessagesOfNeedRetry, _lookbackSeconds).ConfigureAwait(false);\r\n\r\n        foreach (var message in messages)\r\n        {\r\n            context.ThrowIfStopping();\r\n\r\n            await _dispatcher.EnqueueToExecute(message).ConfigureAwait(false);\r\n        }\r\n\r\n        if (_options.Value.UseStorageLock)\r\n            await connection.ReleaseLockAsync($\"received_retry_{_options.Value.Version}\", _instance, context.CancellationToken);\r\n    }\r\n\r\n    private async Task<IEnumerable<T>> GetSafelyAsync<T>(Func<TimeSpan, Task<IEnumerable<T>>> getMessagesAsync, TimeSpan lookbackSeconds)\r\n    {\r\n        try\r\n        {\r\n            return await getMessagesAsync(lookbackSeconds).ConfigureAwait(false);\r\n        }\r\n        catch (Exception ex)\r\n        {\r\n            _logger.LogWarning(1, ex, \"Get messages from storage failed. Retrying...\");\r\n\r\n            return Enumerable.Empty<T>();\r\n        }\r\n    }\r\n\r\n    private void CheckSafeOptionsSet()\r\n    {\r\n        if (_lookbackSeconds < TimeSpan.FromSeconds(MinSuggestedValueForFallbackWindowLookbackSeconds))\r\n        {\r\n            _logger.LogWarning(\"The provided FallbackWindowLookbackSeconds of {currentSetFallbackWindowLookbackSeconds} is set to a value lower than {minSuggestedSeconds} seconds. This might cause unwanted unsafe behavior if the consumer takes more than the provided FallbackWindowLookbackSeconds to execute. \", _options.Value.FallbackWindowLookbackSeconds, MinSuggestedValueForFallbackWindowLookbackSeconds);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Processor/IProcessor.TransportCheck.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing Microsoft.Extensions.Logging;\n\nnamespace DotNetCore.CAP.Processor;\n\npublic class TransportCheckProcessor : IProcessor\n{\n    private readonly ILogger<TransportCheckProcessor> _logger;\n    private readonly IConsumerRegister _register;\n    private readonly TimeSpan _waitingInterval;\n\n    public TransportCheckProcessor(ILogger<TransportCheckProcessor> logger, IConsumerRegister register)\n    {\n        _logger = logger;\n        _register = register;\n        _waitingInterval = TimeSpan.FromSeconds(30);\n    }\n\n    public virtual async Task ProcessAsync(ProcessingContext context)\n    {\n        if (context == null) throw new ArgumentNullException(nameof(context));\n\n        context.ThrowIfStopping();\n\n        _logger.LogDebug(\"Transport connection checking...\");\n\n        if (!_register.IsHealthy())\n        {\n            _logger.LogWarning(\"Transport connection is unhealthy, reconnection...\");\n\n            await _register.ReStartAsync();\n        }\n        else\n        {\n            _logger.LogDebug(\"Transport connection healthy!\");\n        }\n\n        await context.WaitAsync(_waitingInterval).ConfigureAwait(false);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Processor/IProcessor.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Threading.Tasks;\n\nnamespace DotNetCore.CAP.Processor;\n\npublic interface IProcessor\n{\n    Task ProcessAsync(ProcessingContext context);\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Processor/ProcessingContext.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace DotNetCore.CAP.Processor;\n\npublic class ProcessingContext : IDisposable\n{\n    private IServiceScope? _scope;\n\n    private ProcessingContext(ProcessingContext other)\n    {\n        Provider = other.Provider;\n        CancellationToken = other.CancellationToken;\n    }\n\n    public ProcessingContext(\n        IServiceProvider provider,\n        CancellationToken cancellationToken)\n    {\n        Provider = provider;\n        CancellationToken = cancellationToken;\n    }\n\n    public IServiceProvider Provider { get; private set; }\n\n    public CancellationToken CancellationToken { get; }\n\n    public bool IsStopping => CancellationToken.IsCancellationRequested;\n\n    public void Dispose()\n    {\n        _scope?.Dispose();\n    }\n\n    public void ThrowIfStopping()\n    {\n        CancellationToken.ThrowIfCancellationRequested();\n    }\n\n    public ProcessingContext CreateScope()\n    {\n        var serviceScope = Provider.CreateScope();\n\n        return new ProcessingContext(this)\n        {\n            _scope = serviceScope,\n            Provider = serviceScope.ServiceProvider\n        };\n    }\n\n    public Task WaitAsync(TimeSpan timeout)\n    {\n        return Task.Delay(timeout, CancellationToken);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Serialization/ISerializer.JsonUtf8.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Text.Json;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Messages;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.Serialization;\n\npublic class JsonUtf8Serializer : ISerializer\n{\n    private readonly JsonSerializerOptions _jsonSerializerOptions;\n\n    public JsonUtf8Serializer(IOptions<CapOptions> capOptions)\n    {\n        _jsonSerializerOptions = capOptions.Value.JsonSerializerOptions;\n    }\n\n    public ValueTask<TransportMessage> SerializeAsync(Message message)\n    {\n        if (message == null) throw new ArgumentNullException(nameof(message));\n\n        if (message.Value == null) return new ValueTask<TransportMessage>(new TransportMessage(message.Headers, null));\n\n        var jsonBytes = JsonSerializer.SerializeToUtf8Bytes(message.Value, _jsonSerializerOptions);\n\n        return new ValueTask<TransportMessage>(new TransportMessage(message.Headers, jsonBytes));\n    }\n\n    public ValueTask<Message> DeserializeAsync(TransportMessage transportMessage, Type? valueType)\n    {\n        if (valueType == null || transportMessage.Body.Length == 0)\n            return new ValueTask<Message>(new Message(transportMessage.Headers, null));\n\n        var obj = JsonSerializer.Deserialize(transportMessage.Body.Span, valueType, _jsonSerializerOptions);\n\n        return new ValueTask<Message>(new Message(transportMessage.Headers, obj));\n    }\n\n    public string Serialize(Message message)\n    {\n        return JsonSerializer.Serialize(message, _jsonSerializerOptions);\n    }\n\n    public Message? Deserialize(string json)\n    {\n        return JsonSerializer.Deserialize<Message>(json, _jsonSerializerOptions);\n    }\n\n    public object? Deserialize(object value, Type valueType)\n    {\n        if (value is JsonElement jsonElement) return jsonElement.Deserialize(valueType, _jsonSerializerOptions);\n\n        throw new NotSupportedException(\"Type is not of type JsonElement\");\n    }\n\n    public bool IsJsonType(object jsonObject)\n    {\n        return jsonObject is JsonElement;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Serialization/ISerializer.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Messages;\n\nnamespace DotNetCore.CAP.Serialization;\n\npublic interface ISerializer\n{\n    /// <summary>\n    /// Serializes the given <see cref=\"Message\" /> into a string\n    /// </summary>\n    string Serialize(Message message);\n\n    /// <summary>\n    /// Serializes the given <see cref=\"Message\" /> into a <see cref=\"TransportMessage\" />\n    /// </summary>\n    ValueTask<TransportMessage> SerializeAsync(Message message);\n\n    /// <summary>\n    /// Deserialize the given string into a <see cref=\"Message\" />\n    /// </summary>\n    Message? Deserialize(string json);\n\n    /// <summary>\n    /// Deserialize the given <see cref=\"TransportMessage\" /> back into a <see cref=\"Message\" />\n    /// </summary>\n    ValueTask<Message> DeserializeAsync(TransportMessage transportMessage, Type? valueType);\n\n    /// <summary>\n    /// Deserialize the given object with the given Type into an object\n    /// </summary>\n    object? Deserialize(object value, Type valueType);\n\n    /// <summary>\n    /// Check if the given object is of Json type, e.g. JToken or JsonElement\n    /// depending on the type of serializer implemented\n    /// </summary>\n    /// <example>\n    ///     <code>\n    /// // Example implementation for System.Text.Json\n    /// public bool IsJsonType(object jsonObject)\n    /// {\n    ///    return jsonObject is JsonElement;\n    /// }\n    /// </code>\n    /// </example>\n    bool IsJsonType(object jsonObject);\n}"
  },
  {
    "path": "src/DotNetCore.CAP/SubscriberNotFoundException.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\n\nnamespace DotNetCore.CAP;\n\npublic class SubscriberNotFoundException : Exception\n{\n    public SubscriberNotFoundException(string message) : base(message)\n    {\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Transport/BrokerAddress.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Linq;\n\nnamespace DotNetCore.CAP.Transport;\n\n/// <summary>\n/// Represents the address information of a message broker, including its name (type) and network endpoint.\n/// </summary>\n/// <remarks>\n/// This struct encapsulates the broker identification and connection information.\n/// The <c>ToString()</c> method formats the address as \"Name$Endpoint\", which can be parsed back using the string constructor.\n/// </remarks>\npublic struct BrokerAddress\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"BrokerAddress\"/> struct by parsing a combined address string.\n    /// </summary>\n    /// <remarks>\n    /// The address string is expected in the format \"BrokerName$Endpoint\" where the \"$\" character acts as a delimiter.\n    /// If no \"$\" is found, the entire string is treated as the endpoint and the name is left empty.\n    /// </remarks>\n    /// <param name=\"address\">\n    /// A combined address string in the format \"BrokerName$Endpoint\" (e.g., \"RabbitMQ$localhost:5672\").\n    /// </param>\n    public BrokerAddress(string address)\n    {\n        if (address.Contains(\"$\"))\n        {\n            var parts = address.Split('$');\n\n            Name = parts[0];\n            Endpoint = string.Join(string.Empty, parts.Skip(1));\n        }\n        else\n        {\n            Name = string.Empty;\n            Endpoint = address;\n        }\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"BrokerAddress\"/> struct with explicit name and endpoint values.\n    /// </summary>\n    /// <param name=\"name\">\n    /// The broker type name (e.g., \"RabbitMQ\", \"Kafka\", \"AzureServiceBus\").\n    /// Can be empty or null for generic addresses.\n    /// </param>\n    /// <param name=\"endpoint\">\n    /// The network endpoint or connection address of the broker (e.g., \"localhost:5672\", \"kafka:9092\").\n    /// If null, it is treated as an empty string.\n    /// </param>\n    public BrokerAddress(string name, string? endpoint)\n    {\n        Name = name;\n        Endpoint = endpoint ?? String.Empty;\n    }\n\n    /// <summary>\n    /// Gets or sets the broker type name (e.g., \"RabbitMQ\", \"Kafka\", \"AzureServiceBus\").\n    /// </summary>\n    public string Name { get; set; }\n\n    /// <summary>\n    /// Gets or sets the network endpoint or connection address of the broker.\n    /// </summary>\n    public string Endpoint { get; set; }\n\n    /// <summary>\n    /// Returns the string representation of the broker address in the format \"Name$Endpoint\".\n    /// </summary>\n    /// <returns>A string combining the broker name and endpoint separated by \"$\".</returns>\n    public override string ToString()\n    {\n        return Name + \"$\" + Endpoint;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Transport/IConsumerClient.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Messages;\n\nnamespace DotNetCore.CAP.Transport;\n\n/// <inheritdoc />\n/// <summary>\n/// Message queue consumer client interface that defines operations for consuming messages from various message brokers\n/// </summary>\npublic interface IConsumerClient : IAsyncDisposable\n{\n    /// <summary>\n    /// Gets the broker address information that this consumer is connected to\n    /// </summary>\n    BrokerAddress BrokerAddress { get; }\n\n    /// <summary>\n    /// Creates (if necessary) and retrieves topic identifiers from the message broker\n    /// </summary>\n    /// <param name=\"topicNames\">Names of the requested topics to fetch</param>\n    /// <returns>A collection of topic identifiers returned by the broker</returns>\n    Task<ICollection<string>> FetchTopicsAsync(IEnumerable<string> topicNames)\n    {\n        return Task.FromResult<ICollection<string>>(topicNames.ToList());\n    }\n\n    /// <summary>\n    /// Subscribes to a set of topics in the message broker\n    /// </summary>\n    /// <param name=\"topics\">Collection of topic identifiers to subscribe to</param>\n    /// <returns>A task that represents the asynchronous subscribe operation</returns>\n    Task SubscribeAsync(IEnumerable<string> topics);\n\n    /// <summary>\n    /// Starts listening for messages from the subscribed topics\n    /// </summary>\n    /// <param name=\"timeout\">Maximum time to wait when polling for messages</param>\n    /// <param name=\"cancellationToken\">Token to cancel the listening operation</param>\n    /// <returns>A task that represents the asynchronous listening operation</returns>\n    Task ListeningAsync(TimeSpan timeout, CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Manually commits message offset when the message consumption is complete\n    /// </summary>\n    /// <param name=\"sender\">The message or context object to commit</param>\n    /// <returns>A task that represents the asynchronous commit operation</returns>\n    Task CommitAsync(object? sender);\n\n    /// <summary>\n    /// Rejects the message and optionally returns it to the queue for reprocessing\n    /// </summary>\n    /// <param name=\"sender\">The message or context object to reject</param>\n    /// <returns>A task that represents the asynchronous reject operation</returns>\n    Task RejectAsync(object? sender);\n\n    /// <summary>\n    /// Callback that is invoked when a message is received from the broker\n    /// </summary>\n    public Func<TransportMessage, object?, Task>? OnMessageCallback { get; set; }\n\n    /// <summary>\n    /// Callback that is invoked when logging events occur in the consumer client\n    /// </summary>\n    public Action<LogMessageEventArgs>? OnLogCallback { get; set; }\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP/Transport/IConsumerClientFactory.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Threading.Tasks;\n\nnamespace DotNetCore.CAP.Transport;\n\n/// <summary>\n/// Factory interface for creating instances of <see cref=\"IConsumerClient\"/>.\n/// </summary>\npublic interface IConsumerClientFactory\n{\n    /// <summary>\n    /// Asynchronously creates a new <see cref=\"IConsumerClient\"/> instance.\n    /// </summary>\n    /// <param name=\"groupName\">The name of the message group.</param>\n    /// <param name=\"groupConcurrent\">The maximum number of concurrent messages to consume.</param>\n    /// <returns>A task that represents the asynchronous operation. The task result contains the created <see cref=\"IConsumerClient\"/> instance.</returns>\n    Task<IConsumerClient> CreateAsync(string groupName, byte groupConcurrent);\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP/Transport/IDispatcher.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Persistence;\n\nnamespace DotNetCore.CAP.Transport;\n\npublic interface IDispatcher : IProcessingServer\n{\n    ValueTask EnqueueToPublish(MediumMessage message);\n\n    ValueTask EnqueueToExecute(MediumMessage message, ConsumerExecutorDescriptor? descriptor = null);\n\n    Task EnqueueToScheduler(MediumMessage message, DateTime publishTime, object? transaction = null);\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Transport/ITransport.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Messages;\n\nnamespace DotNetCore.CAP.Transport;\n\npublic interface ITransport\n{\n    BrokerAddress BrokerAddress { get; }\n\n    Task<OperateResult> SendAsync(TransportMessage message);\n}"
  },
  {
    "path": "src/DotNetCore.CAP/Transport/MqLogType.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\n\nnamespace DotNetCore.CAP.Transport;\n\n/// <summary>\n/// Defines log event types reported by message brokers and transport implementations.\n/// These events allow applications to monitor broker and consumer health, connectivity issues, and other diagnostics.\n/// </summary>\npublic enum MqLogType\n{\n    /// <summary>\n    /// Consumer subscription was cancelled (RabbitMQ).\n    /// Typically indicates the consumer was unsubscribed or the connection was terminated.\n    /// </summary>\n    ConsumerCancelled,\n\n    /// <summary>\n    /// Consumer successfully registered and is ready to receive messages (RabbitMQ).\n    /// </summary>\n    ConsumerRegistered,\n\n    /// <summary>\n    /// Consumer unregistered from the message broker (RabbitMQ).\n    /// </summary>\n    ConsumerUnregistered,\n\n    /// <summary>\n    /// Consumer connection to the broker was shut down (RabbitMQ).\n    /// </summary>\n    ConsumerShutdown,\n\n    /// <summary>\n    /// An error occurred during message consumption (Kafka).\n    /// </summary>\n    ConsumeError,\n\n    /// <summary>\n    /// Consumer is retrying after a consumption failure (Kafka).\n    /// </summary>\n    ConsumeRetries,\n\n    /// <summary>\n    /// Failed to establish or maintain connection to the broker server (Kafka).\n    /// </summary>\n    ServerConnError,\n\n    /// <summary>\n    /// An exception was received from the message broker (Azure Service Bus).\n    /// </summary>\n    ExceptionReceived,\n\n    /// <summary>\n    /// An asynchronous error event occurred (NATS).\n    /// </summary>\n    AsyncErrorEvent,\n\n    /// <summary>\n    /// Failed to connect or connection error occurred (NATS).\n    /// </summary>\n    ConnectError,\n\n    /// <summary>\n    /// An invalid ID format was detected during message processing (Amazon SQS).\n    /// </summary>\n    InvalidIdFormat,\n\n    /// <summary>\n    /// A message is not currently in flight, preventing visibility timeout change (Amazon SQS).\n    /// </summary>\n    MessageNotInflight,\n\n    /// <summary>\n    /// An error occurred during message consumption (Redis Streams).\n    /// </summary>\n    RedisConsumeError\n}\n\n/// <summary>\n/// Contains event arguments for message broker log events.\n/// These events are used to notify subscribers about broker health, connectivity, and operational status.\n/// </summary>\npublic class LogMessageEventArgs : EventArgs\n{\n    /// <summary>\n    /// Gets or sets the reason or detailed description of the log event.\n    /// This typically contains error messages, consumer IDs, or other contextual information.\n    /// </summary>\n    public string? Reason { get; set; }\n\n    /// <summary>\n    /// Gets or sets the type of log event that occurred (e.g., ConsumerCancelled, ServerConnError, etc.).\n    /// </summary>\n    public MqLogType LogType { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AmazonSQS/AmazonPolicyExtensions.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Amazon.Auth.AccessControlPolicy;\n\nnamespace DotNetCore.CAP.AmazonSQS;\n\npublic static class AmazonPolicyExtensions\n{\n    /// <summary>\n    /// Check to see if the policy for the queue has already given permission to the topic.\n    /// </summary>\n    /// <param name=\"policy\"></param>\n    /// <param name=\"topicArn\"></param>\n    /// <param name=\"sqsQueueArn\"></param>\n    /// <returns></returns>\n    public static bool HasSqsPermission(this Policy policy, string topicArn, string sqsQueueArn)\n    {\n        foreach (var statement in policy.Statements)\n        {\n            var containsResource = statement.Resources.Any(r => r.Id.Equals(sqsQueueArn));\n\n            if (!containsResource) continue;\n\n            foreach (var condition in statement.Conditions)\n            {\n                if ((string.Equals(condition.Type, ConditionFactory.StringComparisonType.StringLike.ToString(),\n                         StringComparison.OrdinalIgnoreCase) ||\n                     string.Equals(condition.Type, ConditionFactory.StringComparisonType.StringEquals.ToString(),\n                         StringComparison.OrdinalIgnoreCase) ||\n                     string.Equals(condition.Type, ConditionFactory.ArnComparisonType.ArnEquals.ToString(),\n                         StringComparison.OrdinalIgnoreCase) ||\n                     string.Equals(condition.Type, ConditionFactory.ArnComparisonType.ArnLike.ToString(),\n                         StringComparison.OrdinalIgnoreCase)) &&\n                    string.Equals(condition.ConditionKey, ConditionFactory.SOURCE_ARN_CONDITION_KEY,\n                        StringComparison.OrdinalIgnoreCase) &&\n                    condition.Values.Contains(topicArn))\n                    return true;\n            }\n        }\n\n        return false;\n    }\n\n    /// <summary>\n    /// Add statement to the SQS policy that gives the SNS topics access to send a message to the queue.\n    /// </summary>\n    /// <code>\n    /// {\n    ///     \"Version\": \"2012-10-17\",\n    ///     \"Statement\": [\n    ///     {\n    ///         \"Effect\": \"Allow\",\n    ///         \"Principal\": {\n    ///             \"AWS\": \"*\"\n    ///         },\n    ///         \"Action\": \"sqs:SendMessage\",\n    ///         \"Resource\": \"arn:aws:sqs:us-east-1:MyQueue\",\n    ///         \"Condition\": {\n    ///             \"ArnLike\": {\n    ///                 \"aws:SourceArn\": [\n    ///                 \"arn:aws:sns:us-east-1:FirstTopic\",\n    ///                 \"arn:aws:sns:us-east-1:SecondTopic\"\n    ///                     ]\n    ///             }\n    ///         }\n    ///     }]\n    /// }\n    /// </code>\n    /// <param name=\"policy\"></param>\n    /// <param name=\"topicArns\"></param>\n    /// <param name=\"sqsQueueArn\"></param>\n    public static void AddSqsPermissions(this Policy policy, IEnumerable<string> topicArns, string sqsQueueArn)\n    {\n        var statement = new Statement(Statement.StatementEffect.Allow);\n        statement.Actions.Add(new ActionIdentifier(\"sqs:SendMessage\"));\n        statement.Resources.Add(new Resource(sqsQueueArn));\n        statement.Principals.Add(new Principal(\"*\"));\n        foreach (var topicArn in topicArns)\n        {\n            statement.Conditions.Add(ConditionFactory.NewSourceArnCondition(topicArn));\n        }\n\n        policy.Statements.Add(statement);\n    }\n\n    /// <summary>\n    /// Compact SQS access policy\n    /// </summary>\n    /// <para>\n    /// Transforms policies with multiple similar statements:\n    /// <code>\n    /// {\n    ///     \"Version\": \"2012-10-17\",\n    ///     \"Statement\": [\n    ///     {\n    ///         \"Effect\": \"Allow\",\n    ///         \"Principal\": {\n    ///             \"AWS\": \"*\"\n    ///         },\n    ///         \"Action\": \"sqs:SendMessage\",\n    ///         \"Resource\": \"arn:aws:sqs:us-east-1:MyQueue-v1\",\n    ///         \"Condition\": {\n    ///             \"ArnLike\": {\n    ///                 \"aws:SourceArn\": \"arn:aws:sns:us-east-1:MyQueue-FirstTopic\"\n    ///             }\n    ///         }\n    ///     },\n    ///     {\n    ///         \"Effect\": \"Allow\",\n    ///         \"Principal\": {\n    ///             \"AWS\": \"*\"\n    ///         },\n    ///         \"Action\": \"sqs:SendMessage\",\n    ///         \"Resource\": \"arn:aws:sqs:us-east-1:MyQueue-v1\",\n    ///         \"Condition\": {\n    ///             \"ArnLike\": {\n    ///                 \"aws:SourceArn\": \"arn:aws:sns:us-east-1:MyQueue-SecondTopic\"\n    ///             }\n    ///         }\n    ///     },\n    ///     {\n    ///         \"Effect\": \"Allow\",\n    ///         \"Principal\": {\n    ///             \"AWS\": \"*\"\n    ///         },\n    ///         \"Action\": \"sqs:SendMessage\",\n    ///         \"Resource\": \"arn:aws:sqs:us-east-1:MyQueue-v1\",\n    ///         \"Condition\": {\n    ///             \"ArnLike\": {\n    ///                 \"aws:SourceArn\": \"arn:aws:sns:us-east-1:MyQueue2-FirstTopic\"\n    ///             }\n    ///         }\n    ///     },]\n    /// }\n    /// </code>\n    /// into compacted single statement:\n    /// <code>\n    /// {\n    ///     \"Version\": \"2012-10-17\",\n    ///     \"Statement\": [\n    ///     {\n    ///         \"Effect\": \"Allow\",\n    ///         \"Principal\": {\n    ///             \"AWS\": \"*\"\n    ///         },\n    ///         \"Action\": \"sqs:SendMessage\",\n    ///         \"Resource\": \"arn:aws:sqs:us-east-1:MyQueue-v1\",\n    ///         \"Condition\": {\n    ///             \"ArnLike\": {\n    ///                 \"aws:SourceArn\": [\n    ///                     \"arn:aws:sns:us-east-1:MyQueue-*\",\n    ///                     \"arn:aws:sns:us-east-1:MyQueue2-FirstTopic\"\n    ///                 ]\n    ///             }\n    ///         }\n    ///     }]\n    /// }\n    /// </code>\n    /// </para>\n    /// <param name=\"policy\"></param>\n    /// <param name=\"sqsQueueArn\"></param>\n    public static void CompactSqsPermissions(this Policy policy, string sqsQueueArn)\n    {\n        var statementsToCompact = policy.Statements\n            .Where(s => s.Effect == Statement.StatementEffect.Allow)\n            .Where(s => s.Actions.All(a => string.Equals(a.ActionName, \"sqs:SendMessage\", StringComparison.OrdinalIgnoreCase)))\n            .Where(s => s.Resources.All(r => string.Equals(r.Id, sqsQueueArn, StringComparison.OrdinalIgnoreCase)))\n            .Where(s => s.Principals.All(r => string.Equals(r.Id, \"*\", StringComparison.OrdinalIgnoreCase)))\n            .ToList();\n\n        var groupName = GetGroupName(sqsQueueArn);\n        if (groupName != null) groupName = $\":{groupName}-\";\n        if (statementsToCompact.Count < 2 && groupName == null) return;\n\n        var topicArns = new HashSet<string>();\n        foreach (var statement in statementsToCompact)\n        {\n            policy.Statements.Remove(statement);\n            foreach (var topicArn in statement.Conditions.SelectMany(c => c.Values))\n            {\n                topicArns.Add(\n                    groupName != null && topicArn.Contains(groupName, StringComparison.InvariantCultureIgnoreCase)\n                        ? $\"{GetArnGroupPrefix(topicArn)}-*\"\n                        : topicArn);\n            }\n        }\n\n        policy.AddSqsPermissions(topicArns.OrderBy(a => a), sqsQueueArn);\n    }\n\n    /// <summary>\n    /// Extract group prefix from ARN\n    /// For example for ARN:\n    /// arn:aws:sns:us-east-1:MyQueue-FirstTopic\n    /// group prefix will be extracted:\n    /// arn:aws:sns:us-east-1:MyQueue\n    /// </summary>\n    /// <param name=\"arn\">Source ARN</param>\n    /// <returns>Group prefix or null if group not present</returns>\n    private static string? GetArnGroupPrefix(string arn)\n    {\n        const char separator = '-';\n        if (string.IsNullOrEmpty(arn) || !arn.Contains(separator)) return null;\n\n        var groupPaths = arn.Split(separator);\n        if (groupPaths.Length < 2) return null;\n\n        return string.Join(separator, groupPaths.Take(groupPaths.Length - 1));\n    }\n\n    /// <summary>\n    /// Extract group name from ARN\n    /// For example for ARN:\n    /// arn:aws:sns:us-east-1:MyQueue-FirstTopic\n    /// group name will be extracted:\n    /// MyQueue\n    /// </summary>\n    /// <param name=\"arn\">Source ARN</param>\n    /// <returns>Group name or null if group not present</returns>\n    private static string? GetGroupName(string arn)\n    {\n        const char separator = ':';\n        if (string.IsNullOrEmpty(arn) || !arn.Contains(separator)) return null;\n\n        var name = arn.Split(separator).LastOrDefault();\n        if (string.IsNullOrEmpty(name)) return null;\n\n        return GetArnGroupPrefix(name);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AmazonSQS/AmazonSQSConsumerClient.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Text.Json;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Amazon.Auth.AccessControlPolicy;\nusing Amazon.SimpleNotificationService;\nusing Amazon.SimpleNotificationService.Model;\nusing Amazon.SQS;\nusing Amazon.SQS.Model;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.AmazonSQS;\n\ninternal sealed class AmazonSQSConsumerClient : IConsumerClient\n{\n    private static readonly object ConnectionLock = new();\n    private readonly AmazonSQSOptions _amazonSQSOptions;\n    private readonly SemaphoreSlim _semaphore;\n    private readonly string _groupId;\n    private readonly byte _groupConcurrent;\n    private string _queueUrl = string.Empty;\n\n    private IAmazonSimpleNotificationService? _snsClient;\n    private IAmazonSQS? _sqsClient;\n\n    public AmazonSQSConsumerClient(string groupId, byte groupConcurrent, IOptions<AmazonSQSOptions> options)\n    {\n        _groupId = groupId;\n        _groupConcurrent = groupConcurrent;\n        _amazonSQSOptions = options.Value;\n        _semaphore = new SemaphoreSlim(groupConcurrent);\n    }\n\n    public Func<TransportMessage, object?, Task>? OnMessageCallback { get; set; }\n\n    public Action<LogMessageEventArgs>? OnLogCallback { get; set; }\n\n    public BrokerAddress BrokerAddress => new(\"aws_sqs\", _queueUrl);\n\n    public async Task<ICollection<string>> FetchTopicsAsync(IEnumerable<string> topicNames)\n    {\n        if (topicNames == null) throw new ArgumentNullException(nameof(topicNames));\n\n        await ConnectAsync(true, false).ConfigureAwait(false);\n\n        var topicArns = new List<string>();\n        foreach (var topic in topicNames)\n        {\n            var createTopicRequest = new CreateTopicRequest(topic.NormalizeForAws());\n\n            var createTopicResponse = await _snsClient!.CreateTopicAsync(createTopicRequest).ConfigureAwait(false);\n\n            topicArns.Add(createTopicResponse.TopicArn);\n        }\n\n        await GenerateSqsAccessPolicyAsync(topicArns).ConfigureAwait(false);\n\n        return topicArns;\n    }\n\n    public async Task SubscribeAsync(IEnumerable<string> topics)\n    {\n        if (topics == null) throw new ArgumentNullException(nameof(topics));\n\n        await ConnectAsync().ConfigureAwait(false);\n\n        await SubscribeToTopics(topics).ConfigureAwait(false);\n    }\n\n    public async Task ListeningAsync(TimeSpan timeout, CancellationToken cancellationToken)\n    {\n        await ConnectAsync().ConfigureAwait(false);\n\n        var request = new ReceiveMessageRequest(_queueUrl)\n        {\n            WaitTimeSeconds = 5,\n            MaxNumberOfMessages = 1\n        };\n\n        while (true)\n        {\n            var response = await _sqsClient!.ReceiveMessageAsync(request, cancellationToken).ConfigureAwait(false);\n\n            if (response?.Messages?.Count == 1)\n            {\n                if (_groupConcurrent > 0)\n                {\n                    await _semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);\n                    _ = Task.Run(() => ConsumeAsync(), cancellationToken).ConfigureAwait(false);\n                }\n                else\n                {\n                    await ConsumeAsync().ConfigureAwait(false);\n                }\n\n                Task ConsumeAsync()\n                {\n                    var messageObj = JsonSerializer.Deserialize<SQSReceivedMessage>(response.Messages[0].Body);\n\n                    var header = messageObj!.MessageAttributes.ToDictionary(x => x.Key, x => x.Value.Value);\n                    var body = messageObj.Message;\n\n                    var message = new TransportMessage(header, body != null ? Encoding.UTF8.GetBytes(body) : null);\n\n                    message.Headers[Headers.Group] = _groupId;\n\n                    return OnMessageCallback!(message, response.Messages[0].ReceiptHandle);\n                }\n            }\n            else\n            {\n                cancellationToken.ThrowIfCancellationRequested();\n                cancellationToken.WaitHandle.WaitOne(timeout);\n            }\n        }\n    }\n\n    public async Task CommitAsync(object? sender)\n    {\n        try\n        {\n            await _sqsClient!.DeleteMessageAsync(_queueUrl, (string)sender!).ConfigureAwait(false);\n            _semaphore.Release();\n        }\n        catch (ReceiptHandleIsInvalidException ex)\n        {\n            InvalidIdFormatLog(ex.Message);\n        }\n    }\n\n    public async Task RejectAsync(object? sender)\n    {\n        try\n        {\n            await _sqsClient!.ChangeMessageVisibilityAsync(_queueUrl, (string)sender!, 3).ConfigureAwait(false);\n            _semaphore.Release();\n        }\n        catch (MessageNotInflightException ex)\n        {\n            MessageNotInflightLog(ex.Message);\n        }\n    }\n\n\n    public ValueTask DisposeAsync()\n    {\n        _sqsClient?.Dispose();\n        _snsClient?.Dispose();\n        return ValueTask.CompletedTask;\n    }\n\n    // Asynchronous version of Connect to avoid blocking threads during queue creation\n    private async Task ConnectAsync(bool initSNS = true, bool initSQS = true)\n    {\n        // Fast path if already initialized for requested resources\n        if ((initSNS && _snsClient == null) || (initSQS && _sqsClient == null))\n        {\n            if (_snsClient == null && initSNS)\n            {\n                lock (ConnectionLock)\n                {\n                    if (_snsClient == null)\n                    {\n                        if (string.IsNullOrWhiteSpace(_amazonSQSOptions.SNSServiceUrl))\n                            _snsClient = _amazonSQSOptions.Credentials != null\n                                ? new AmazonSimpleNotificationServiceClient(_amazonSQSOptions.Credentials,\n                                    _amazonSQSOptions.Region)\n                                : new AmazonSimpleNotificationServiceClient(_amazonSQSOptions.Region);\n                        else\n                            _snsClient = _amazonSQSOptions.Credentials != null\n                                ? new AmazonSimpleNotificationServiceClient(_amazonSQSOptions.Credentials,\n                                    new AmazonSimpleNotificationServiceConfig { ServiceURL = _amazonSQSOptions.SNSServiceUrl })\n                                : new AmazonSimpleNotificationServiceClient(new AmazonSimpleNotificationServiceConfig\n                                { ServiceURL = _amazonSQSOptions.SNSServiceUrl });\n                    }\n                }\n            }\n\n            if (_sqsClient == null && initSQS)\n            {\n                lock (ConnectionLock)\n                {\n                    if (_sqsClient == null)\n                    {\n                        if (string.IsNullOrWhiteSpace(_amazonSQSOptions.SQSServiceUrl))\n                            _sqsClient = _amazonSQSOptions.Credentials != null\n                                ? new AmazonSQSClient(_amazonSQSOptions.Credentials, _amazonSQSOptions.Region)\n                                : new AmazonSQSClient(_amazonSQSOptions.Region);\n                        else\n                            _sqsClient = _amazonSQSOptions.Credentials != null\n                                ? new AmazonSQSClient(_amazonSQSOptions.Credentials,\n                                    new AmazonSQSConfig { ServiceURL = _amazonSQSOptions.SQSServiceUrl })\n                                : new AmazonSQSClient(new AmazonSQSConfig { ServiceURL = _amazonSQSOptions.SQSServiceUrl });\n                    }\n                }\n\n                if (string.IsNullOrWhiteSpace(_queueUrl))\n                {\n                    // Create or get existing queue URL asynchronously\n                    var queueResponse = await _sqsClient!.CreateQueueAsync(_groupId.NormalizeForAws()).ConfigureAwait(false);\n                    _queueUrl = queueResponse.QueueUrl;\n                }\n            }\n        }\n    }\n\n    #region private methods\n\n    private void InvalidIdFormatLog(string exceptionMessage)\n    {\n        var logArgs = new LogMessageEventArgs\n        {\n            LogType = MqLogType.InvalidIdFormat,\n            Reason = exceptionMessage\n        };\n\n        OnLogCallback!(logArgs);\n    }\n\n    private void MessageNotInflightLog(string exceptionMessage)\n    {\n        var logArgs = new LogMessageEventArgs\n        {\n            LogType = MqLogType.MessageNotInflight,\n            Reason = exceptionMessage\n        };\n\n        OnLogCallback!(logArgs);\n    }\n\n    private async Task GenerateSqsAccessPolicyAsync(IEnumerable<string> topicArns)\n    {\n        await ConnectAsync(false, true).ConfigureAwait(false);\n\n        var queueAttributes = await _sqsClient!.GetAttributesAsync(_queueUrl).ConfigureAwait(false);\n\n        var sqsQueueArn = queueAttributes[\"QueueArn\"];\n\n        var policy = queueAttributes.TryGetValue(\"Policy\", out var policyStr) && !string.IsNullOrEmpty(policyStr)\n            ? Policy.FromJson(policyStr)\n            : new Policy();\n\n        var topicArnsToAllow = topicArns\n            .Where(a => !policy.HasSqsPermission(a, sqsQueueArn))\n            .ToList();\n\n        if (!topicArnsToAllow.Any()) return;\n\n        policy.AddSqsPermissions(topicArnsToAllow, sqsQueueArn);\n        policy.CompactSqsPermissions(sqsQueueArn);\n\n        var setAttributes = new Dictionary<string, string> { { \"Policy\", policy.ToJson() } };\n        await _sqsClient.SetAttributesAsync(_queueUrl, setAttributes).ConfigureAwait(false);\n    }\n\n    private async Task SubscribeToTopics(IEnumerable<string> topics)\n    {\n        var queueAttributes = await _sqsClient!.GetAttributesAsync(_queueUrl).ConfigureAwait(false);\n\n        var sqsQueueArn = queueAttributes[\"QueueArn\"];\n        foreach (var topicArn in topics)\n        {\n            await _snsClient!.SubscribeAsync(new SubscribeRequest\n            {\n                TopicArn = topicArn,\n                Protocol = \"sqs\",\n                Endpoint = sqsQueueArn\n            })\n                .ConfigureAwait(false);\n        }\n    }\n\n    #endregion\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AmazonSQS/AmazonSQSConsumerClientFactory.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.AmazonSQS;\n\ninternal sealed class AmazonSQSConsumerClientFactory : IConsumerClientFactory\n{\n    private readonly IOptions<AmazonSQSOptions> _amazonSQSOptions;\n\n    public AmazonSQSConsumerClientFactory(IOptions<AmazonSQSOptions> amazonSQSOptions)\n    {\n        _amazonSQSOptions = amazonSQSOptions;\n    }\n\n    public Task<IConsumerClient> CreateAsync(string groupName, byte groupConcurrent)\n    {\n        try\n        {\n            var client = new AmazonSQSConsumerClient(groupName, groupConcurrent, _amazonSQSOptions);\n            return Task.FromResult<IConsumerClient>(client);\n        }\n        catch (Exception e)\n        {\n            throw new BrokerConnectionException(e);\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AmazonSQS/CAP.AmazonSQSOptions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing Amazon;\nusing Amazon.Runtime;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\n// ReSharper disable once InconsistentNaming\npublic class AmazonSQSOptions\n{\n    public RegionEndpoint Region { get; set; } = default!;\n\n    public AWSCredentials? Credentials { get; set; }\n\n    /// <summary>\n    /// Overrides Service Url deduced from AWS Region. To use in local development environments like localstack.\n    /// </summary>\n    public string? SNSServiceUrl { get; set; }\n\n    /// <summary>\n    /// Overrides Service Url deduced from AWS Region. To use in local development environments like localstack.\n    /// </summary>\n    public string? SQSServiceUrl { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AmazonSQS/CAP.AmazonSQSOptionsExtension.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP.AmazonSQS;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.DependencyInjection;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\ninternal sealed class AmazonSQSOptionsExtension : ICapOptionsExtension\n{\n    private readonly Action<AmazonSQSOptions> _configure;\n\n    public AmazonSQSOptionsExtension(Action<AmazonSQSOptions> configure)\n    {\n        _configure = configure;\n    }\n\n    public void AddServices(IServiceCollection services)\n    {\n        services.AddSingleton(new CapMessageQueueMakerService(\"Amazon SQS\"));\n\n        services.Configure(_configure);\n        services.AddSingleton<ITransport, AmazonSQSTransport>();\n        services.AddSingleton<IConsumerClientFactory, AmazonSQSConsumerClientFactory>();\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AmazonSQS/CAP.Options.Extensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing Amazon;\nusing DotNetCore.CAP;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.Extensions.DependencyInjection;\n\npublic static class CapOptionsExtensions\n{\n    public static CapOptions UseAmazonSQS(this CapOptions options, RegionEndpoint region)\n    {\n        return options.UseAmazonSQS(opt => { opt.Region = region; });\n    }\n\n    public static CapOptions UseAmazonSQS(this CapOptions options, Action<AmazonSQSOptions> configure)\n    {\n        if (configure == null) throw new ArgumentNullException(nameof(configure));\n\n        options.RegisterExtension(new AmazonSQSOptionsExtension(configure));\n\n        return options;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AmazonSQS/DotNetCore.CAP.AmazonSQS.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  \n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\t<Nullable>enable</Nullable>\n    <PackageTags>$(PackageTags);AmazonSQS;SQS</PackageTags>\n  </PropertyGroup>\n  \n  <PropertyGroup>\n\t<GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <NoWarn>1701;1702;1705;CS1591</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"AWSSDK.SimpleNotificationService\" Version=\"4.0.2.5\" />\n    <PackageReference Include=\"AWSSDK.SQS\" Version=\"4.0.2.3\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n  </ItemGroup>\n \n</Project>"
  },
  {
    "path": "src/DotNetCore.CAP.AmazonSQS/ITransport.AmazonSQS.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Amazon.SimpleNotificationService;\nusing Amazon.SimpleNotificationService.Model;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.AmazonSQS;\n\ninternal sealed class AmazonSQSTransport : ITransport\n{\n    private readonly ILogger _logger;\n    private readonly SemaphoreSlim _semaphore = new(1, 1);\n    private readonly IOptions<AmazonSQSOptions> _sqsOptions;\n    private IAmazonSimpleNotificationService? _snsClient;\n    private IDictionary<string, string>? _topicArnMaps;\n\n    public AmazonSQSTransport(ILogger<AmazonSQSTransport> logger, IOptions<AmazonSQSOptions> sqsOptions)\n    {\n        _logger = logger;\n        _sqsOptions = sqsOptions;\n    }\n\n    public BrokerAddress BrokerAddress => new(\"AmazonSQS\", string.Empty);\n\n    public async Task<OperateResult> SendAsync(TransportMessage message)\n    {\n        try\n        {\n            await FetchExistingTopicArns();\n\n            if (TryGetOrCreateTopicArn(message.GetName().NormalizeForAws(), out var arn))\n            {\n                string? bodyJson = null;\n                if (message.Body.Length > 0) bodyJson = Encoding.UTF8.GetString(message.Body.Span);\n\n                var attributes = message.Headers.Where(x => x.Value != null).ToDictionary(x => x.Key,\n                    x => new MessageAttributeValue\n                    {\n                        StringValue = x.Value,\n                        DataType = \"String\"\n                    });\n\n                var request = new PublishRequest(arn, bodyJson)\n                {\n                    MessageAttributes = attributes\n                };\n\n                await _snsClient!.PublishAsync(request);\n\n                _logger.LogDebug($\"SNS topic message [{message.GetName().NormalizeForAws()}] has been published.\");\n                return OperateResult.Success;\n            }\n\n            var errorMessage = $\"Can't be found SNS topics for [{message.GetName().NormalizeForAws()}]\";\n            _logger.LogWarning(errorMessage);\n\n            return OperateResult.Failed(\n                new PublisherSentFailedException(errorMessage),\n                new OperateError\n                {\n                    Code = \"SNS\",\n                    Description = $\"Can't be found SNS topics for [{message.GetName().NormalizeForAws()}]\"\n                });\n        }\n        catch (Exception ex)\n        {\n            var wrapperEx = new PublisherSentFailedException(ex.Message, ex);\n            var errors = new OperateError\n            {\n                Code = ex.HResult.ToString(),\n                Description = ex.Message\n            };\n\n            return OperateResult.Failed(wrapperEx, errors);\n        }\n    }\n\n    private async Task FetchExistingTopicArns()\n    {\n        if (_topicArnMaps != null) return;\n\n        await _semaphore.WaitAsync();\n\n        try\n        {\n            if (string.IsNullOrWhiteSpace(_sqsOptions.Value.SNSServiceUrl))\n                _snsClient = _sqsOptions.Value.Credentials != null\n                    ? new AmazonSimpleNotificationServiceClient(_sqsOptions.Value.Credentials, _sqsOptions.Value.Region)\n                    : new AmazonSimpleNotificationServiceClient(_sqsOptions.Value.Region);\n            else\n                _snsClient = _sqsOptions.Value.Credentials != null\n                    ? new AmazonSimpleNotificationServiceClient(_sqsOptions.Value.Credentials,\n                        new AmazonSimpleNotificationServiceConfig { ServiceURL = _sqsOptions.Value.SNSServiceUrl })\n                    : new AmazonSimpleNotificationServiceClient(new AmazonSimpleNotificationServiceConfig\n                        { ServiceURL = _sqsOptions.Value.SNSServiceUrl });\n\n            if (_topicArnMaps == null)\n            {\n                _topicArnMaps = new Dictionary<string, string>();\n\n                string? nextToken = null;\n                do\n                {\n                    var topics = nextToken == null\n                        ? await _snsClient.ListTopicsAsync()\n                        : await _snsClient.ListTopicsAsync(nextToken);\n                    topics.Topics.ForEach(x =>\n                    {\n                        var name = x.TopicArn.Split(':').Last();\n                        _topicArnMaps.Add(name, x.TopicArn);\n                    });\n                    nextToken = topics.NextToken;\n                } while (!string.IsNullOrEmpty(nextToken));\n            }\n        }\n        catch (Exception e)\n        {\n            _logger.LogError(e, \"Init topics from aws sns error!\");\n        }\n        finally\n        {\n            _semaphore.Release();\n        }\n    }\n\n    private bool TryGetOrCreateTopicArn(string topicName, [NotNullWhen(true)] out string? topicArn)\n    {\n        topicArn = null;\n        if (_topicArnMaps!.TryGetValue(topicName, out topicArn)) return true;\n\n        var response = _snsClient!.CreateTopicAsync(topicName).GetAwaiter().GetResult();\n\n        if (string.IsNullOrEmpty(response.TopicArn)) return false;\n\n        topicArn = response.TopicArn;\n\n        _topicArnMaps.Add(topicName, topicArn);\n        return true;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AmazonSQS/SQSReceivedMessage.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Collections.Generic;\n\nnamespace DotNetCore.CAP.AmazonSQS;\n\ninternal class SQSReceivedMessage\n{\n    public string? Message { get; set; }\n\n    public Dictionary<string, SQSReceivedMessageAttributes> MessageAttributes { get; set; } = default!;\n}\n\ninternal class SQSReceivedMessageAttributes\n{\n    public string? Type { get; set; }\n\n    public string? Value { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AmazonSQS/TopicNormalizer.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\n\nnamespace DotNetCore.CAP.AmazonSQS;\n\ninternal static class TopicNormalizer\n{\n    public static string NormalizeForAws(this string origin)\n    {\n        if (origin.Length > 256)\n            throw new ArgumentOutOfRangeException(nameof(origin) + \" character string length must between 1~256!\");\n        return origin.Replace(\".\", \"-\").Replace(\":\", \"_\");\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AzureServiceBus/AzureServiceBusConsumerClient.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Azure.Messaging.ServiceBus;\nusing Azure.Messaging.ServiceBus.Administration;\nusing DotNetCore.CAP.AzureServiceBus.Helpers;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.AzureServiceBus;\n\ninternal sealed class AzureServiceBusConsumerClient : IConsumerClient\n{\n    private readonly AzureServiceBusOptions _asbOptions;\n    private readonly SemaphoreSlim _connectionLock = new(1, 1);\n    private readonly ILogger _logger;\n    private readonly IServiceProvider _serviceProvider;\n    private readonly string _subscriptionName;\n    private readonly byte _groupConcurrent;\n    private readonly SemaphoreSlim _semaphore;\n\n    private ServiceBusAdministrationClient? _administrationClient;\n    private ServiceBusClient? _serviceBusClient;\n    private ServiceBusProcessorFacade? _serviceBusProcessor;\n\n    public AzureServiceBusConsumerClient(\n        ILogger logger,\n        string subscriptionName,\n        byte groupConcurrent,\n        IOptions<AzureServiceBusOptions> options,\n        IServiceProvider serviceProvider)\n    {\n        _logger = logger;\n        _subscriptionName = subscriptionName;\n        _groupConcurrent = groupConcurrent;\n        _semaphore = new SemaphoreSlim(groupConcurrent);\n        _serviceProvider = serviceProvider;\n        _asbOptions = options.Value ?? throw new ArgumentNullException(nameof(options));\n    }\n\n    public Func<TransportMessage, object?, Task>? OnMessageCallback { get; set; }\n\n    public Action<LogMessageEventArgs>? OnLogCallback { get; set; }\n\n    public BrokerAddress BrokerAddress => ServiceBusHelpers.GetBrokerAddress(_asbOptions.ConnectionString, _asbOptions.Namespace);\n\n    public async Task SubscribeAsync(IEnumerable<string> topics)\n    {\n        if (topics == null) throw new ArgumentNullException(nameof(topics));\n\n        await ConnectAsync();\n\n        if (!_asbOptions.AutoProvision) \n            return;\n\n        topics = topics.Concat(_asbOptions!.SQLFilters?.Select(o => o.Key) ?? []);\n\n        var allRules = _administrationClient!.GetRulesAsync(_asbOptions!.TopicPath, _subscriptionName).ToEnumerable();\n        var allRuleNames = allRules.Select(o => o.Name);\n\n        foreach (var newRule in topics.Except(allRuleNames))\n        {\n            var isSqlRule = _asbOptions.SQLFilters?.FirstOrDefault(o => o.Key == newRule).Value is not null;\n\n            RuleFilter? currentRuleToAdd = default;\n\n            if (isSqlRule)\n            {\n                var sqlExpression = _asbOptions.SQLFilters?.FirstOrDefault(o => o.Key == newRule).Value;\n                currentRuleToAdd = new SqlRuleFilter(sqlExpression);\n            }\n            else\n            {\n                var correlationRule = new CorrelationRuleFilter\n                {\n                    Subject = newRule\n                };\n\n                foreach (var correlationHeader in _asbOptions.DefaultCorrelationHeaders)\n                {\n                    correlationRule.ApplicationProperties.Add(correlationHeader.Key, correlationHeader.Value);\n                }\n\n                currentRuleToAdd = correlationRule;\n            }\n\n            await _administrationClient.CreateRuleAsync(_asbOptions.TopicPath, _subscriptionName,\n                 new CreateRuleOptions\n                 {\n                     Name = newRule,\n                     Filter = currentRuleToAdd\n                 });\n\n            _logger.LogInformation(\"Azure Service Bus add rule: {RuleName}\", newRule);\n        }\n\n        foreach (var oldRule in allRuleNames.Except(topics))\n        {\n            await _administrationClient.DeleteRuleAsync(_asbOptions.TopicPath, _subscriptionName, oldRule);\n\n            _logger.LogInformation(\"Azure Service Bus remove rule: {RuleName}\", oldRule);\n        }\n    }\n\n    public async Task ListeningAsync(TimeSpan timeout, CancellationToken cancellationToken)\n    {\n        await ConnectAsync();\n\n        if (_serviceBusProcessor!.IsSessionProcessor)\n        {\n            _serviceBusProcessor!.ProcessSessionMessageAsync += _serviceBusProcessor_ProcessSessionMessageAsync;\n        }\n        else\n        {\n            _serviceBusProcessor!.ProcessMessageAsync += _serviceBusProcessor_ProcessMessageAsync;\n        }\n\n        _serviceBusProcessor.ProcessErrorAsync += _serviceBusProcessor_ProcessErrorAsync;\n\n        await _serviceBusProcessor.StartProcessingAsync(cancellationToken);\n    }\n\n    public async Task CommitAsync(object? sender)\n    {\n        var commitInput = (AzureServiceBusConsumerCommitInput)sender!;\n        if (!_serviceBusProcessor!.AutoCompleteMessages)\n            await commitInput.CompleteMessageAsync();\n        _semaphore.Release();\n    }\n\n    public async Task RejectAsync(object? sender)\n    {\n        var commitInput = (AzureServiceBusConsumerCommitInput)sender!;\n        await commitInput.AbandonMessageAsync();\n        _semaphore.Release();\n    }\n\n    public async ValueTask DisposeAsync()\n    {\n        if (!_serviceBusProcessor!.IsProcessing)\n            await _serviceBusProcessor.DisposeAsync();\n    }\n\n    private Task _serviceBusProcessor_ProcessErrorAsync(ProcessErrorEventArgs args)\n    {\n        var exceptionMessage =\n            $\"- Identifier: {args.Identifier}\" + Environment.NewLine +\n            $\"- Entity Path: {args.EntityPath}\" + Environment.NewLine +\n            $\"- Executing ErrorSource: {args.ErrorSource}\" + Environment.NewLine +\n            $\"- Exception: {args.Exception}\";\n\n        var logArgs = new LogMessageEventArgs\n        {\n            LogType = MqLogType.ExceptionReceived,\n            Reason = exceptionMessage\n        };\n\n        OnLogCallback!(logArgs);\n\n        return Task.CompletedTask;\n    }\n\n    private async Task _serviceBusProcessor_ProcessMessageAsync(ProcessMessageEventArgs arg)\n    {\n        var context = ConvertMessage(arg.Message);\n\n        if (_groupConcurrent > 0)\n        {\n            await _semaphore.WaitAsync();\n            _ = Task.Run(() => OnMessageCallback!(context, new AzureServiceBusConsumerCommitInput(arg))).ConfigureAwait(false);\n        }\n        else\n        {\n            await OnMessageCallback!(context, new AzureServiceBusConsumerCommitInput(arg));\n        }\n    }\n\n    private async Task _serviceBusProcessor_ProcessSessionMessageAsync(ProcessSessionMessageEventArgs arg)\n    {\n        var context = ConvertMessage(arg.Message);\n\n        await OnMessageCallback!(context, new AzureServiceBusConsumerCommitInput(arg));\n    }\n\n    public async Task ConnectAsync()\n    {\n        if (_serviceBusProcessor != null) return;\n\n        await _connectionLock.WaitAsync();\n\n        try\n        {\n            if (_serviceBusProcessor == null)\n            {\n\n                _serviceBusClient = _asbOptions.TokenCredential is not null ?\n                    new ServiceBusClient(_asbOptions.Namespace, _asbOptions.TokenCredential) :\n                    new ServiceBusClient(_asbOptions.ConnectionString);\n\n                if (_asbOptions.AutoProvision)\n                {\n                    if (_asbOptions.TokenCredential != null)\n                    {\n                        _administrationClient =\n                            new ServiceBusAdministrationClient(_asbOptions.Namespace, _asbOptions.TokenCredential);\n                    }\n                    else\n                    {\n                        _administrationClient = new ServiceBusAdministrationClient(_asbOptions.ConnectionString);\n                    }\n\n                    var topicConfigs =\n                        _asbOptions.CustomProducers.Select(producer =>\n                                (topicPaths: producer.TopicPath, subscribe: producer.CreateSubscription))\n                            .Append((topicPaths: _asbOptions.TopicPath, subscribe: true))\n                            .GroupBy(n => n.topicPaths, StringComparer.OrdinalIgnoreCase)\n                            .Select(n => (topicPaths: n.Key, subscribe: n.Max(o => o.subscribe)));\n\n                    foreach (var (topicPath, subscribe) in topicConfigs)\n                    {\n                        if (!await _administrationClient.TopicExistsAsync(topicPath))\n                        {\n                            await _administrationClient.CreateTopicAsync(topicPath);\n                            _logger.LogInformation(\"Azure Service Bus created topic: {TopicPath}\", topicPath);\n                        }\n\n                        if (subscribe && !await _administrationClient.SubscriptionExistsAsync(topicPath, _subscriptionName))\n                        {\n                            var subscriptionDescription =\n                                new CreateSubscriptionOptions(topicPath, _subscriptionName)\n                                {\n                                    RequiresSession = _asbOptions.EnableSessions,\n                                    AutoDeleteOnIdle = _asbOptions.SubscriptionAutoDeleteOnIdle,\n                                    LockDuration = _asbOptions.SubscriptionMessageLockDuration,\n                                    DefaultMessageTimeToLive = _asbOptions.SubscriptionDefaultMessageTimeToLive,\n                                    MaxDeliveryCount = _asbOptions.SubscriptionMaxDeliveryCount,\n                                };\n\n                            await _administrationClient.CreateSubscriptionAsync(subscriptionDescription);\n\n                            _logger.LogInformation(\n                                $\"Azure Service Bus topic {topicPath} created subscription: {_subscriptionName}\");\n                        }\n                    }\n                }\n\n                _serviceBusProcessor = !_asbOptions.EnableSessions\n                    ? new ServiceBusProcessorFacade(\n                        serviceBusProcessor: _serviceBusClient.CreateProcessor(_asbOptions.TopicPath,\n                            _subscriptionName,\n                            new ServiceBusProcessorOptions\n                            {\n                                AutoCompleteMessages = _asbOptions.AutoCompleteMessages,\n                                MaxConcurrentCalls = _asbOptions.MaxConcurrentCalls,\n                                MaxAutoLockRenewalDuration = _asbOptions.MaxAutoLockRenewalDuration,\n                            }))\n                    : new ServiceBusProcessorFacade(\n                        serviceBusSessionProcessor: _serviceBusClient.CreateSessionProcessor(_asbOptions.TopicPath,\n                            _subscriptionName,\n                            new ServiceBusSessionProcessorOptions\n                            {\n                                AutoCompleteMessages = _asbOptions.AutoCompleteMessages,\n                                MaxConcurrentCallsPerSession = _asbOptions.MaxConcurrentCalls,\n                                MaxAutoLockRenewalDuration = _asbOptions.MaxAutoLockRenewalDuration,\n                                MaxConcurrentSessions = _asbOptions.MaxConcurrentSessions,\n                                SessionIdleTimeout = _asbOptions.SessionIdleTimeout,\n                            }));\n            }\n        }\n        finally\n        {\n            _connectionLock.Release();\n        }\n    }\n\n    #region private methods\n\n    private TransportMessage ConvertMessage(ServiceBusReceivedMessage message)\n    {\n        var headers = message.ApplicationProperties\n            .ToDictionary(x => x.Key, y => y.Value?.ToString());\n\n        headers[Headers.Group] = _subscriptionName;\n\n        if (_asbOptions.CustomHeadersBuilder != null)\n        {\n            var customHeaders = _asbOptions.CustomHeadersBuilder(message, _serviceProvider);\n            foreach (var customHeader in customHeaders)\n            {\n                var added = headers.TryAdd(customHeader.Key, customHeader.Value);\n\n                if (!added)\n                    _logger.LogWarning(\"Not possible to add the custom header {Header}. A value with the same key already exists in the Message headers.\",customHeader.Key);\n            }\n        }\n\n        return new TransportMessage(headers, message.Body);\n    }\n\n    #endregion private methods\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AzureServiceBus/AzureServiceBusConsumerClientFactory.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.AzureServiceBus;\n\ninternal sealed class AzureServiceBusConsumerClientFactory : IConsumerClientFactory\n{\n    private readonly IOptions<AzureServiceBusOptions> _asbOptions;\n    private readonly ILoggerFactory _loggerFactory;\n    private readonly IServiceProvider _serviceProvider;\n\n    public AzureServiceBusConsumerClientFactory(\n        ILoggerFactory loggerFactory,\n        IOptions<AzureServiceBusOptions> asbOptions,\n        IServiceProvider serviceProvider)\n    {\n        _loggerFactory = loggerFactory;\n        _asbOptions = asbOptions;\n        _serviceProvider = serviceProvider;\n    }\n\n    public async Task<IConsumerClient> CreateAsync(string groupName, byte groupConcurrent)\n    {\n        try\n        {\n            var logger = _loggerFactory.CreateLogger(typeof(AzureServiceBusConsumerClient));\n            var client = new AzureServiceBusConsumerClient(logger, groupName, groupConcurrent, _asbOptions, _serviceProvider);\n            await client.ConnectAsync();\n            return client;\n        }\n        catch (Exception e)\n        {\n            throw new BrokerConnectionException(e);\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AzureServiceBus/AzureServiceBusConsumerCommitInput.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Threading.Tasks;\nusing Azure.Messaging.ServiceBus;\n\nnamespace DotNetCore.CAP.AzureServiceBus;\n\npublic class AzureServiceBusConsumerCommitInput\n{\n    public AzureServiceBusConsumerCommitInput(ProcessMessageEventArgs processMessageEventArgs)\n    {\n        ProcessMessageArgs = processMessageEventArgs;\n    }\n\n    public AzureServiceBusConsumerCommitInput(ProcessSessionMessageEventArgs processSessionMessageArgs)\n    {\n        ProcessSessionMessageArgs = processSessionMessageArgs;\n    }\n\n    private ProcessMessageEventArgs? ProcessMessageArgs { get; }\n    private ProcessSessionMessageEventArgs? ProcessSessionMessageArgs { get; }\n\n    private ServiceBusReceivedMessage Message => ProcessMessageArgs?.Message ?? ProcessSessionMessageArgs!.Message;\n\n    public Task CompleteMessageAsync()\n    {\n        return ProcessMessageArgs != null\n            ? ProcessMessageArgs.CompleteMessageAsync(Message)\n            : ProcessSessionMessageArgs!.CompleteMessageAsync(Message);\n    }\n\n    public Task AbandonMessageAsync()\n    {\n        return ProcessMessageArgs != null\n            ? ProcessMessageArgs.AbandonMessageAsync(Message)\n            : ProcessSessionMessageArgs!.AbandonMessageAsync(Message);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AzureServiceBus/AzureServiceBusHeaders.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nnamespace DotNetCore.CAP.AzureServiceBus;\n\npublic static class AzureServiceBusHeaders\n{\n    public const string SessionId = \"cap-session-id\";\n\n    /// <summary>\n    /// The scheduled enqueue time as DateTimeOffset. This value is for delayed message sending.\n    /// It is utilized to delay messages sending to a specific time in the future.\n    /// </summary>\n    /// <remarks>\n    /// See https://docs.microsoft.com/en-us/azure/service-bus-messaging/message-sequencing#scheduled-messages for details.\n    /// </remarks>\n    public const string ScheduledEnqueueTimeUtc = \"cap-scheduled-enqueue-time-utc\";\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AzureServiceBus/CAP.AzureServiceBusOptions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing Azure.Core;\nusing Azure.Messaging.ServiceBus;\nusing DotNetCore.CAP.AzureServiceBus;\nusing DotNetCore.CAP.AzureServiceBus.Producer;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\n/// <summary>\n/// Provides programmatic configuration for the CAP Azure Service Bus project.\n/// </summary>\npublic class AzureServiceBusOptions\n{\n    /// <summary>\n    /// TopicPath default value for CAP.\n    /// </summary>\n    public const string DefaultTopicPath = \"cap\";\n\n    /// <summary>\n    /// Azure Service Bus Namespace connection string. Must not contain topic information.\n    /// </summary>\n    public string ConnectionString { get; set; } = default!;\n\n    /// <summary>\n    /// Namespace of service bus , Needs to be set when using with TokenCredential Property\n    /// </summary>\n    public string Namespace { get; set; } = default!;\n\n    /// <summary>\n    /// When set to <c>true</c> (default), CAP will automatically create topics, subscriptions,\n    /// and rules using the <see cref=\"Azure.Messaging.ServiceBus.Administration.ServiceBusAdministrationClient\"/>.\n    /// Set to <c>false</c> to skip automatic provisioning, which is useful when the admin API\n    /// is unavailable (e.g., Azure Service Bus Emulator).\n    /// </summary>\n    public bool AutoProvision { get; set; } = true;\n\n    /// <summary>\n    /// Whether Service Bus sessions are enabled. If enabled, all messages must contain a\n    /// <see cref=\"AzureServiceBusHeaders.SessionId\" /> header. Defaults to false.\n    /// </summary>\n    public bool EnableSessions { get; set; } = false;\n\n    /// <summary>\n    /// The name of the topic relative to the service namespace base address.\n    /// </summary>\n    public string TopicPath { get; set; } = DefaultTopicPath;\n\n    /// <summary>\n    /// The <see cref=\"TimeSpan\" /> idle interval after which the subscription is automatically deleted.\n    /// </summary>\n    /// <remarks>The minimum duration is 5 minutes. Default value is <see cref=\"TimeSpan.MaxValue\" />.</remarks>\n    public TimeSpan SubscriptionAutoDeleteOnIdle { get; set; } = TimeSpan.MaxValue;\n\n    /// <summary>\n    /// Duration of a peek lock receive. i.e., the amount of time that the message is locked by a given receiver so that\n    /// no other receiver receives the same message.\n    /// </summary>\n    /// <remarks>Max value is 5 minutes. Default value is 60 seconds.</remarks>\n    public TimeSpan SubscriptionMessageLockDuration { get; set; } = TimeSpan.FromSeconds(60);\n\n    /// <summary>\n    /// The default time to live value for the messages. This is the duration after which the message expires.\n    /// </summary>\n    /// <remarks>\n    /// This is the default value used when <see cref=\"ServiceBusMessage.TimeToLive\"/> is not set on a\n    ///  message itself. Messages older than their TimeToLive value will expire and no longer be retained in the message store.\n    ///  Subscribers will be unable to receive expired messages.\n    /// Default value is <see cref=\"TimeSpan.MaxValue\"/>.\n    /// </remarks>\n    public TimeSpan SubscriptionDefaultMessageTimeToLive { get; set; } = TimeSpan.MaxValue;\n\n    /// <summary>\n    /// The maximum delivery count of a message before it is dead-lettered.\n    /// </summary>\n    /// <remarks>\n    /// The delivery count is increased when a message is received in <see cref=\"ServiceBusReceiveMode.PeekLock\"/> mode\n    /// and didn't complete the message before the message lock expired.\n    /// Default value is 10. Minimum value is 1.\n    /// </remarks>\n    public int SubscriptionMaxDeliveryCount { get; set; } = 10;\n\n    /// <summary>\n    /// Gets a value that indicates whether the processor should automatically complete messages after the message handler has\n    /// completed processing.\n    /// If the message handler triggers an exception, the message will not be automatically completed.\n    /// </summary>\n    public bool AutoCompleteMessages { get; set; } = false;\n\n    /// <summary>\n    /// Adds additional correlation properties to all correlation filters.\n    /// https://learn.microsoft.com/en-us/azure/service-bus-messaging/topic-filters#correlation-filters\n    /// </summary>\n    public IDictionary<string, string> DefaultCorrelationHeaders { get; } = new Dictionary<string, string>();\n\n    /// <summary>\n    /// Gets the maximum number of concurrent calls to the ProcessMessageAsync message handler the processor should initiate.\n    /// </summary>\n    /// <remarks>Default values is 1.</remarks>\n    public int MaxConcurrentCalls { get; set; } = 1;\n\n    /// <summary>\n    /// The maximum amount of time to wait for a message to be received for the\n    ///  currently active session. After this time has elapsed, the processor will close the session\n    ///  and attempt to process another session.\n    /// </summary>\n    /// <remarks>Not applicable when <see cref=\"EnableSessions\"/> is false.</remarks>\n    public TimeSpan? SessionIdleTimeout { get; set; }\n\n    /// <summary>\n    /// The maximum number of sessions that can be processed concurrently by the processor.\n    /// </summary>\n    /// <remarks>\n    /// Not applicable when <see cref=\"EnableSessions\"/> is false.\n    /// The default value is 8.\n    /// </remarks>\n    public int MaxConcurrentSessions { get; set; } = 8;\n\n    /// <summary>\n    /// The maximum duration within which the lock will be renewed automatically.\n    /// </summary>\n    /// <remarks>\n    /// This value should be greater than the longest message lock duration; for example, the LockDuration Property.\n    /// To specify an infinite duration, use <see cref=\"Timeout.InfiniteTimeSpan\"/>.\n    /// The default value is 5 minutes.\n    /// </remarks>\n    public TimeSpan MaxAutoLockRenewalDuration { get; set; } = TimeSpan.FromMinutes(5);\n\n    /// <summary>\n    /// Represents the Azure Active Directory token provider for Azure Managed Service Identity integration.\n    /// </summary>\n    public TokenCredential? TokenCredential { get; set; }\n\n    /// <summary>\n    /// Use this function to write additional headers from the original ASB Message or any Custom Header, i.e. to allow\n    /// compatibility with heterogeneous systems, into <see cref=\"CapHeader\" />\n    /// </summary>\n    public Func<ServiceBusReceivedMessage, IServiceProvider, List<KeyValuePair<string, string>>>? CustomHeadersBuilder\n    {\n        get;\n        set;\n    }\n\n    /// <summary>\n    /// Custom SQL Filters for topic subscription , more about SQL Filters and its rules\n    /// Key: Rule Name , Value: SQL Expression\n    /// https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-messaging-sql-filter\n    /// </summary>\n    public List<KeyValuePair<string, string>>? SQLFilters { get; set; }\n\n    internal ICollection<IServiceBusProducerDescriptor> CustomProducers { get; set; } =\n        new List<IServiceBusProducerDescriptor>();\n\n    public AzureServiceBusOptions ConfigureCustomProducer<T>(\n        Action<ServiceBusProducerDescriptorBuilder<T>> configuration)\n    {\n        var builder = new ServiceBusProducerDescriptorBuilder<T>();\n        configuration(builder);\n        CustomProducers.Add(builder.Build());\n\n        return this;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AzureServiceBus/CAP.AzureServiceBusOptionsExtension.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP.AzureServiceBus;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.DependencyInjection;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\ninternal sealed class AzureServiceBusOptionsExtension : ICapOptionsExtension\n{\n    private readonly Action<AzureServiceBusOptions> _configure;\n\n    public AzureServiceBusOptionsExtension(Action<AzureServiceBusOptions> configure)\n    {\n        _configure = configure;\n    }\n\n    public void AddServices(IServiceCollection services)\n    {\n        services.AddSingleton(new CapMessageQueueMakerService(\"Azure Service Bus\"));\n\n        services.Configure(_configure);\n\n        services.AddSingleton<IConsumerClientFactory, AzureServiceBusConsumerClientFactory>();\n        services.AddSingleton<ITransport, AzureServiceBusTransport>();\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AzureServiceBus/CAP.Options.Extensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.Extensions.DependencyInjection;\n\npublic static class CapOptionsExtensions\n{\n    /// <summary>\n    /// Configuration to use Azure Service Bus in CAP.\n    /// </summary>\n    /// <param name=\"options\">CAP configuration options</param>\n    /// <param name=\"connectionString\">Connection string for namespace or the entity.</param>\n    public static CapOptions UseAzureServiceBus(this CapOptions options, string connectionString)\n    {\n        if (connectionString == null) throw new ArgumentNullException(nameof(connectionString));\n\n        return options.UseAzureServiceBus(opt => { opt.ConnectionString = connectionString; });\n    }\n\n    /// <summary>\n    /// Configuration to use Azure Service Bus in CAP.\n    /// </summary>\n    /// <param name=\"options\">CAP configuration options</param>\n    /// <param name=\"configure\">Provides programmatic configuration for the Azure Service Bus.</param>\n    public static CapOptions UseAzureServiceBus(this CapOptions options, Action<AzureServiceBusOptions> configure)\n    {\n        if (configure == null) throw new ArgumentNullException(nameof(configure));\n\n        options.RegisterExtension(new AzureServiceBusOptionsExtension(configure));\n\n        return options;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AzureServiceBus/DotNetCore.CAP.AzureServiceBus.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\t<Nullable>enable</Nullable>\n    <PackageTags>$(PackageTags);AzureServiceBus</PackageTags>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <WarningsAsErrors>NU1605;NU1701</WarningsAsErrors>\n    <NoWarn>NU1701;CS1591</NoWarn>\n    <DocumentationFile>bin\\$(Configuration)\\netstandard2.1\\DotNetCore.CAP.AzureServiceBus.xml</DocumentationFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Remove=\"Azure.Messaging.ServiceBus\" />\n    <None Remove=\"System.Linq.Async\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Azure.Messaging.ServiceBus\" Version=\"7.20.1\" />\n    <PackageReference Include=\"System.Linq.Async\" Version=\"6.0.3\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n  </ItemGroup>\n  <ItemGroup>\n    <AssemblyAttribute Include=\"System.Runtime.CompilerServices.InternalsVisibleToAttribute\">\n      <_Parameter1>DotNetCore.CAP.AzureServiceBus.Test</_Parameter1>\n    </AssemblyAttribute>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/DotNetCore.CAP.AzureServiceBus/Helpers/ServiceBusHelpers.cs",
    "content": "using System;\nusing DotNetCore.CAP.Transport;\n\nnamespace DotNetCore.CAP.AzureServiceBus.Helpers;\n\npublic static class ServiceBusHelpers\n{\n    public static BrokerAddress GetBrokerAddress(string? connectionString, string? @namespace)\n    {\n        var host = (@namespace, connectionString) switch\n        {\n            _ when string.IsNullOrWhiteSpace(@namespace) && string.IsNullOrWhiteSpace(connectionString)\n                => throw new ArgumentException(\"Either connection string or namespace are required.\"),\n            _ when string.IsNullOrWhiteSpace(connectionString)\n                   || (!string.IsNullOrWhiteSpace(@namespace) && !string.IsNullOrWhiteSpace(connectionString))\n                => @namespace!,\n            _ when string.IsNullOrWhiteSpace(@namespace)\n                => TryGetEndpointFromConnectionString(connectionString, out var extractedValue)\n                    ? extractedValue!\n                    : throw new InvalidOperationException(\"Unable to extract namespace from connection string.\"),\n            _ => throw new InvalidOperationException(\"Unhandled case in switch expression.\")\n        };\n\n        return new BrokerAddress(\"servicebus\", host);\n    }\n\n\n    private static bool TryGetEndpointFromConnectionString(string? connectionString, out string? @namespace)\n    {\n        @namespace = string.Empty;\n\n        if (string.IsNullOrWhiteSpace(connectionString))\n            return false;\n\n        var keyValuePairs = connectionString.Split(';');\n\n        foreach (var kvp in keyValuePairs)\n        {\n            if (!kvp.StartsWith(\"Endpoint\", StringComparison.InvariantCultureIgnoreCase)) continue;\n            \n            var endpointParts = kvp.Split('=');\n\n            if (endpointParts.Length != 2) continue;\n\n            var uri = new Uri(endpointParts[1]);\n            \n            // Namespace is the host part without the .servicebus.windows.net\n            @namespace = uri.ToString();\n\n            return true;\n        }\n\n        return false;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AzureServiceBus/ITransport.AzureServiceBus.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Concurrent;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Azure.Messaging.ServiceBus;\nusing DotNetCore.CAP.AzureServiceBus.Helpers;\nusing DotNetCore.CAP.AzureServiceBus.Producer;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.AzureServiceBus;\n\ninternal class AzureServiceBusTransport : ITransport, IServiceBusProducerDescriptorFactory\n{\n    private readonly IOptions<AzureServiceBusOptions> _asbOptions;\n    private readonly SemaphoreSlim _connectionLock = new(1, 1);\n\n    private readonly ILogger _logger;\n    private readonly ConcurrentDictionary<string, ServiceBusSender?> _senders = new();\n\n    private ServiceBusClient? _client;\n\n    public AzureServiceBusTransport(\n        ILogger<AzureServiceBusTransport> logger,\n        IOptions<AzureServiceBusOptions> asbOptions)\n    {\n        _logger = logger;\n        _asbOptions = asbOptions;\n    }\n\n    /// <summary>\n    /// Creates a producer descriptor for the given message. If there's no custom producer configuration for the\n    /// message type, one will be created using defaults configured in the AzureServiceBusOptions (e.g. TopicPath).\n    /// </summary>\n    /// <param name=\"transportMessage\"></param>\n    /// <returns></returns>\n    public IServiceBusProducerDescriptor CreateProducerForMessage(TransportMessage transportMessage)\n    {\n        return _asbOptions.Value\n                   .CustomProducers\n                   .SingleOrDefault(p => p.MessageTypeName == transportMessage.GetName())\n               ??\n               new ServiceBusProducerDescriptor(\n                   transportMessage.GetName(),\n                   _asbOptions.Value.TopicPath);\n    }\n\n    public BrokerAddress BrokerAddress => ServiceBusHelpers.GetBrokerAddress(_asbOptions.Value.ConnectionString, _asbOptions.Value.Namespace);\n\n    public async Task<OperateResult> SendAsync(TransportMessage transportMessage)\n    {\n        try\n        {\n            var producer = CreateProducerForMessage(transportMessage);\n            var sender = GetSenderForProducer(producer);\n\n            var message = new ServiceBusMessage(transportMessage.Body.ToArray())\n            {\n                MessageId = transportMessage.GetId(),\n                Subject = transportMessage.GetName(),\n                CorrelationId = transportMessage.GetCorrelationId()\n            };\n\n            if (_asbOptions.Value.EnableSessions || producer.EnableSessions)\n            {\n                transportMessage.Headers.TryGetValue(AzureServiceBusHeaders.SessionId, out var sessionId);\n                message.SessionId = string.IsNullOrEmpty(sessionId) ? transportMessage.GetId() : sessionId;\n            }\n\n            if (\n                transportMessage.Headers.TryGetValue(AzureServiceBusHeaders.ScheduledEnqueueTimeUtc,\n                    out var scheduledEnqueueTimeUtcString)\n                && DateTimeOffset.TryParse(scheduledEnqueueTimeUtcString, out var scheduledEnqueueTimeUtc))\n                message.ScheduledEnqueueTime = scheduledEnqueueTimeUtc.UtcDateTime;\n\n            foreach (var header in transportMessage.Headers)\n            {\n                message.ApplicationProperties.Add(header.Key, header.Value);\n            }\n\n            await sender.SendMessageAsync(message).ConfigureAwait(false);\n\n            _logger.LogDebug($\"Azure Service Bus message [{transportMessage.GetName()}] has been published.\");\n\n            return OperateResult.Success;\n        }\n        catch (Exception ex)\n        {\n            var wrapperEx = new PublisherSentFailedException(ex.Message, ex);\n\n            return OperateResult.Failed(wrapperEx);\n        }\n    }\n\n\n    /// <summary>\n    /// Gets the Topic Client for the specified producer. If it does not exist, a new one is created and added to the Topic\n    /// Client dictionary.\n    /// </summary>\n    /// <param name=\"producerDescriptor\"></param>\n    /// <returns>\n    ///     <see cref=\"ServiceBusSender\" />\n    /// </returns>\n    private ServiceBusSender GetSenderForProducer(IServiceBusProducerDescriptor producerDescriptor)\n    {\n        if (_senders.TryGetValue(producerDescriptor.TopicPath, out var sender) && sender != null)\n        {\n            _logger.LogTrace(\"Topic {TopicPath} connection already present as a Publish destination.\",\n                producerDescriptor.TopicPath);\n\n            return sender;\n        }\n\n        _connectionLock.Wait();\n\n        try\n        {\n            _client ??= _asbOptions.Value.TokenCredential is null\n                ? new ServiceBusClient(_asbOptions.Value.ConnectionString)\n                : new ServiceBusClient(_asbOptions.Value.Namespace, _asbOptions.Value.TokenCredential);\n\n            var newSender = _client.CreateSender(producerDescriptor.TopicPath);\n            _senders.AddOrUpdate(\n                producerDescriptor.TopicPath,\n                newSender,\n                (_, _) => newSender);\n\n            return newSender;\n        }\n        finally\n        {\n            _connectionLock.Release();\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AzureServiceBus/Producer/IServiceBusProducerDescriptor.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\n\nnamespace DotNetCore.CAP.AzureServiceBus.Producer;\n\npublic interface IServiceBusProducerDescriptor\n{\n    string TopicPath { get; }\n    string MessageTypeName { get; }\n    bool CreateSubscription { get; }\n    bool EnableSessions { get; }\n}\n\npublic class ServiceBusProducerDescriptor : IServiceBusProducerDescriptor\n{\n    public ServiceBusProducerDescriptor(Type type, string topicPath, bool createSubscription = true, bool enableSessions = false)\n    {\n        MessageTypeName = type.Name;\n        TopicPath = topicPath;\n        CreateSubscription = createSubscription;\n        EnableSessions = enableSessions;\n    }\n\n    public ServiceBusProducerDescriptor(string typeName, string topicPath, bool createSubscription = true, bool enableSessions = false)\n    {\n        MessageTypeName = typeName;\n        TopicPath = topicPath;\n        CreateSubscription = createSubscription;\n        EnableSessions = enableSessions;\n    }\n\n    public string TopicPath { get; set; }\n\n    public string MessageTypeName { get; }\n    public bool CreateSubscription { get; internal set; }\n    public bool EnableSessions { get; internal set; }\n}\n\npublic class ServiceBusProducerDescriptor<T> : ServiceBusProducerDescriptor\n{\n    public ServiceBusProducerDescriptor(string topicPath, bool createSubscription = true, bool enableSessions = false) : base(typeof(T), topicPath, createSubscription, enableSessions)\n    {\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AzureServiceBus/Producer/IServiceBusProducerDescriptorFactory.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing DotNetCore.CAP.Messages;\n\nnamespace DotNetCore.CAP.AzureServiceBus.Producer;\n\npublic interface IServiceBusProducerDescriptorFactory\n{\n    IServiceBusProducerDescriptor CreateProducerForMessage(TransportMessage transportMessage);\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AzureServiceBus/Producer/ServiceBusProducerDescriptorBuilder.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\n\nnamespace DotNetCore.CAP.AzureServiceBus.Producer;\n\npublic class ServiceBusProducerDescriptorBuilder<T>\n{\n    private string TopicPath { get; set; } = null!;\n    private bool CreateSubscription { get; set; }\n    private bool EnableSessions { get; set; }\n\n    public ServiceBusProducerDescriptorBuilder<T> UseTopic(string topicPath)\n    {\n        TopicPath = topicPath;\n        return this;\n    }\n\n    public ServiceBusProducerDescriptorBuilder<T> WithSubscription()\n    {\n        CreateSubscription = true;\n        return this;\n    }\n\n    public ServiceBusProducerDescriptorBuilder<T> WithSessions()\n    {\n        EnableSessions = true;\n        return this;\n    }\n\n    public ServiceBusProducerDescriptor<T> Build()\n    {\n        return new ServiceBusProducerDescriptor<T>(TopicPath, CreateSubscription, EnableSessions);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.AzureServiceBus/ServiceBusProcessorFacade.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Azure.Messaging.ServiceBus;\n\nnamespace DotNetCore.CAP.AzureServiceBus;\n\npublic class ServiceBusProcessorFacade : IAsyncDisposable\n{\n    private readonly ServiceBusProcessor? _serviceBusProcessor;\n    private readonly ServiceBusSessionProcessor? _serviceBusSessionProcessor;\n\n    public bool IsSessionProcessor { get; }\n\n    public bool IsProcessing => IsSessionProcessor\n        ? _serviceBusSessionProcessor!.IsProcessing\n        : _serviceBusProcessor!.IsProcessing;\n\n    public bool AutoCompleteMessages => IsSessionProcessor\n        ? _serviceBusSessionProcessor!.AutoCompleteMessages\n        : _serviceBusProcessor!.AutoCompleteMessages;\n\n    public ServiceBusProcessorFacade(ServiceBusProcessor? serviceBusProcessor = null,\n        ServiceBusSessionProcessor? serviceBusSessionProcessor = null)\n    {\n        if (serviceBusProcessor is null && serviceBusSessionProcessor is null)\n        {\n            throw new ArgumentNullException(nameof(serviceBusProcessor),\n                \"Either serviceBusProcessor or serviceBusSessionProcessor must be provided\");\n        }\n\n        _serviceBusProcessor = serviceBusProcessor;\n        _serviceBusSessionProcessor = serviceBusSessionProcessor;\n\n        IsSessionProcessor = _serviceBusSessionProcessor is not null;\n    }\n\n    public Task StartProcessingAsync(CancellationToken cancellationToken = default)\n    {\n        return IsSessionProcessor\n            ? _serviceBusSessionProcessor!.StartProcessingAsync(cancellationToken)\n            : _serviceBusProcessor!.StartProcessingAsync(cancellationToken);\n    }\n\n    public event Func<ProcessMessageEventArgs, Task> ProcessMessageAsync\n    {\n        add => _serviceBusProcessor!.ProcessMessageAsync += value;\n\n        remove => _serviceBusProcessor!.ProcessMessageAsync -= value;\n    }\n\n    public event Func<ProcessSessionMessageEventArgs, Task> ProcessSessionMessageAsync\n    {\n        add => _serviceBusSessionProcessor!.ProcessMessageAsync += value;\n\n        remove => _serviceBusSessionProcessor!.ProcessMessageAsync -= value;\n    }\n\n    public event Func<ProcessErrorEventArgs, Task> ProcessErrorAsync\n    {\n        add\n        {\n            if (IsSessionProcessor)\n            {\n                _serviceBusSessionProcessor!.ProcessErrorAsync += value;\n            }\n            else\n            {\n                _serviceBusProcessor!.ProcessErrorAsync += value;\n            }\n        }\n\n        remove\n        {\n            if (IsSessionProcessor)\n            {\n                _serviceBusSessionProcessor!.ProcessErrorAsync -= value;\n            }\n            else\n            {\n                _serviceBusProcessor!.ProcessErrorAsync -= value;\n            }\n        }\n    }\n\n\n    public async ValueTask DisposeAsync()\n    {\n        if (_serviceBusProcessor is not null) await _serviceBusProcessor.DisposeAsync();\n        if (_serviceBusSessionProcessor is not null) await _serviceBusSessionProcessor.DisposeAsync();\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/CAP.BuilderExtension.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\n#nullable enable\nusing System;\nusing System.IO;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing System.Text;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Dashboard;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Routing;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.FileProviders;\n\n[assembly: InternalsVisibleTo(\"DotNetCore.CAP.Dashboard.K8s\")]\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\npublic static class CapBuilderExtension\n{\n    private const string EmbeddedFileNamespace = \"DotNetCore.CAP.Dashboard.wwwroot.dist\";\n\n    internal static IApplicationBuilder UseCapDashboard(this IApplicationBuilder app)\n    {\n        if (app == null) throw new ArgumentNullException(nameof(app));\n\n        var provider = app.ApplicationServices;\n\n        var options = provider.GetService<DashboardOptions>();\n\n        if (options != null)\n        {\n            app.UseStaticFiles(new StaticFileOptions\n            {\n                RequestPath = options.PathMatch,\n                FileProvider = new EmbeddedFileProvider(options.GetType().Assembly, EmbeddedFileNamespace)\n            });\n\n            var endpointRouteBuilder = (IEndpointRouteBuilder)app.Properties[\"__EndpointRouteBuilder\"]!;\n\n            endpointRouteBuilder.MapGet(\n                pattern: options.PathMatch, \n                requestDelegate: httpContext =>\n            {\n                var path = httpContext.Request.Path.Value;\n                \n                var redirectUrl = string.IsNullOrEmpty(path) || path.EndsWith(\"/\")\n                    ? \"index.html\"\n                    : $\"{path.Split('/').Last()}/index.html\";\n                \n                httpContext.Response.StatusCode = 301;\n                httpContext.Response.Headers[\"Location\"] = redirectUrl;\n                return Task.CompletedTask;\n            }).AllowAnonymousIf(options.AllowAnonymousExplicit, options.AuthorizationPolicy);\n\n            endpointRouteBuilder.MapGet(\n                pattern: options.PathMatch + \"/index.html\", \n                requestDelegate: async httpContext =>\n            {\n                httpContext.Response.StatusCode = 200;\n                httpContext.Response.ContentType = \"text/html;charset=utf-8\";\n\n                await using var stream = options.GetType().Assembly.GetManifestResourceStream(EmbeddedFileNamespace + \".index.html\");\n                \n                if (stream == null) throw new InvalidOperationException();\n\n                using var sr = new StreamReader(stream);\n                var htmlBuilder = new StringBuilder(await sr.ReadToEndAsync());\n                htmlBuilder.Replace(\"%(servicePrefix)\", options.PathBase + options.PathMatch + \"/api\");\n                htmlBuilder.Replace(\"%(pollingInterval)\", options.StatsPollingInterval.ToString());\n                await httpContext.Response.WriteAsync(htmlBuilder.ToString(), Encoding.UTF8);\n            }).AllowAnonymousIf(options.AllowAnonymousExplicit, options.AuthorizationPolicy);\n\n            new RouteActionProvider(endpointRouteBuilder, options).MapDashboardRoutes();\n        }\n\n        return app;\n    }\n\n    internal static IEndpointConventionBuilder AllowAnonymousIf(this IEndpointConventionBuilder builder, bool allowAnonymous, params string?[] authorizationPolicies)\n    {\n        if (allowAnonymous) return builder.AllowAnonymous();\n        \n        var validAuthorizationPolicies = authorizationPolicies\n            .Where(policy => !string.IsNullOrEmpty(policy))!\n            .ToArray<string>();\n        \n        if (!validAuthorizationPolicies.Any())\n        {\n            throw new InvalidOperationException(\"If Dashboard Options does not explicitly allow anonymous requests, the Authorization Policy must be configured.\");\n        }\n        \n        return builder.RequireAuthorization(validAuthorizationPolicies);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/CAP.DashboardOptions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\n// ReSharper disable once CheckNamespace\n\n#nullable enable\nnamespace DotNetCore.CAP;\n\n/// <summary>\n/// Represents all the option you can use to configure the dashboard.\n/// </summary>\npublic class DashboardOptions\n{\n    public DashboardOptions()\n    {\n        PathBase = string.Empty;\n        PathMatch = \"/cap\";\n        StatsPollingInterval = 2000;\n        AllowAnonymousExplicit = true;\n    }\n\n    /// <summary>\n    /// When behind the proxy, specify the base path to allow spa call prefix.\n    /// </summary>\n    public string PathBase { get; set; }\n\n    /// <summary>\n    /// Path prefix to match from url path.\n    /// </summary>\n    public string PathMatch { get; set; }\n\n    /// <summary>\n    /// The interval the /stats endpoint should be polled with.\n    /// </summary>\n    public int StatsPollingInterval { get; set; }\n\n    /// <summary>\n    /// Explicitly allows anonymous access for the CAP dashboard API, passing AllowAnonymous to the ASP.NET Core global authorization filter.\n    /// </summary>\n    public bool AllowAnonymousExplicit { get; set; }\n    \n    /// <summary>\n    /// Authorization policy for the Dashboard. Required if <see cref=\"AllowAnonymousExplicit\"/> is false.\n    /// </summary>\n    public string? AuthorizationPolicy { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/CAP.DashboardOptionsExtensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP;\nusing DotNetCore.CAP.Dashboard;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace DotNetCore.CAP\n{\n    internal sealed class DashboardOptionsExtension : ICapOptionsExtension\n    {\n        private readonly Action<DashboardOptions> _options;\n\n        public DashboardOptionsExtension(Action<DashboardOptions> option)\n        {\n            _options = option;\n        }\n\n        public void AddServices(IServiceCollection services)\n        {\n            var dashboardOptions = new DashboardOptions();\n            _options?.Invoke(dashboardOptions);\n            services.AddTransient<IStartupFilter, CapStartupFilter>();\n            services.AddSingleton(dashboardOptions);\n            services.AddSingleton<CapMetricsEventListener>();\n        }\n    }\n\n    internal sealed class CapStartupFilter : IStartupFilter\n    {\n        public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)\n        {\n            return app =>\n            {\n                next(app);\n\n                app.UseCapDashboard();\n            };\n        }\n    }\n}\n\nnamespace Microsoft.Extensions.DependencyInjection\n{\n    public static class CapOptionsExtensions\n    {\n        public static CapOptions UseDashboard(this CapOptions capOptions)\n        {\n            return capOptions.UseDashboard(opt => { });\n        }\n\n        public static CapOptions UseDashboard(this CapOptions capOptions, Action<DashboardOptions> options)\n        {\n            if (options == null) throw new ArgumentNullException(nameof(options));\n\n            capOptions.RegisterExtension(new DashboardOptionsExtension(options));\n\n            return capOptions;\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/CAP.MetricsEventListener.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Tracing;\nusing System.Linq;\nusing DotNetCore.CAP.Diagnostics;\n\nnamespace DotNetCore.CAP.Dashboard;\n\ninternal class CapMetricsEventListener : EventListener\n{\n    public const int HistorySize = 300;\n\n    public CapMetricsEventListener()\n    {\n        for (var i = 0; i < HistorySize; i++)\n        {\n            PublishedPerSec.Add(0);\n            InvokeSubscriberPerSec.Add(0);\n            InvokeSubscriberElapsedMs.Add(null);\n        }\n    }\n\n    public CircularBuffer<int?> PublishedPerSec { get; } = new(HistorySize);\n\n    //public Queue<double?> ConsumePerSec { get; } = new(HistorySize);\n    public CircularBuffer<int?> InvokeSubscriberPerSec { get; } = new(HistorySize);\n    public CircularBuffer<int?> InvokeSubscriberElapsedMs { get; } = new(HistorySize);\n\n    public CircularBuffer<int?>[] GetRealTimeMetrics()\n    {\n        var warpArr = new CircularBuffer<int?>[4];\n\n        var startTime = (int)DateTimeOffset.Now.AddSeconds(-300).ToUnixTimeSeconds();\n        var endTime = startTime + 300;\n\n        var timeSerials = new CircularBuffer<int?>(HistorySize);\n        for (var j = startTime; j < endTime; j++)\n        {\n            timeSerials.Add(j);\n        }\n\n        warpArr[0] = timeSerials;\n        warpArr[1] = PublishedPerSec;\n        warpArr[2] = InvokeSubscriberPerSec;\n        warpArr[3] = InvokeSubscriberElapsedMs;\n\n        return warpArr;\n    }\n\n    protected override void OnEventSourceCreated(EventSource source)\n    {\n        if (!source.Name.Equals(CapDiagnosticListenerNames.MetricListenerName)) return;\n\n        EnableEvents(source, EventLevel.LogAlways, EventKeywords.All, new Dictionary<string, string>\n        {\n            //report interval\n            [\"EventCounterIntervalSec\"] = \"1\"\n        });\n    }\n\n    protected override void OnEventWritten(EventWrittenEventArgs eventData)\n    {\n        if (!eventData.EventName!.Equals(\"EventCounters\")) return;\n\n        var payload = (IDictionary<string, object>)eventData.Payload![0]!;\n\n        var val = payload.Values.ToArray();\n\n        if ((string)val[0] == CapDiagnosticListenerNames.PublishedPerSec)\n        {\n            PublishedPerSec.Add(Convert.ToInt32(val[3]));\n        }\n        //else if ((string)val[0] == CapDiagnosticListenerNames.ConsumePerSec)\n        //{\n        //        ConsumePerSec.Dequeue();\n        //        var v = (double)val[3];\n        //        ConsumePerSec.Enqueue(v);\n        //}\n        else if ((string)val[0] == CapDiagnosticListenerNames.InvokeSubscriberPerSec)\n        {\n            InvokeSubscriberPerSec.Add(Convert.ToInt32(val[3]));\n        }\n        else if ((string)val[0] == CapDiagnosticListenerNames.InvokeSubscriberElapsedMs)\n        {\n            var v = Convert.ToInt32(val[2]);\n            InvokeSubscriberElapsedMs.Add(v == 0 ? null : v);\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/CapCache.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\n\nnamespace DotNetCore.CAP.Dashboard;\n\n#region Cache<T> class\n\n/// <summary>\n/// This is a generic cache subsystem based on key/value pairs, where key is generic, too. Key must be unique.\n/// Every cache entry has its own timeout.\n/// Cache is thread safe and will delete expired entries on its own using System.Threading.Timers (which run on\n/// <see cref=\"ThreadPool\" /> threads).\n/// </summary>\n// ReSharper disable once InheritdocConsiderUsage\n// ReSharper disable once InconsistentNaming\npublic class Cache<K, T> : IDisposable\n{\n    #region Constructor and class members\n\n    private readonly Dictionary<K, T> _cache = new();\n    private readonly Dictionary<K, Timer> _timers = new();\n    private readonly ReaderWriterLockSlim _locker = new();\n\n    #endregion\n\n    #region IDisposable implementation & Clear\n\n    private bool disposed;\n\n    /// <summary>\n    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.\n    /// </summary>\n    public void Dispose()\n    {\n        Dispose(true);\n        GC.SuppressFinalize(this);\n    }\n\n    /// <summary>\n    /// Releases unmanaged and - optionally - managed resources.\n    /// </summary>\n    /// <param name=\"disposing\">\n    /// <c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.\n    /// </param>\n    protected virtual void Dispose(bool disposing)\n    {\n        if (!disposed)\n        {\n            disposed = true;\n\n            if (disposing)\n            {\n                // Dispose managed resources.\n                Clear();\n                _locker.Dispose();\n            }\n\n            // Dispose unmanaged resources\n        }\n    }\n\n    /// <summary>\n    /// Clears the entire cache and disposes all active timers.\n    /// </summary>\n    public void Clear()\n    {\n        _locker.EnterWriteLock();\n        try\n        {\n            try\n            {\n                foreach (var t in _timers.Values)\n                {\n                    t.Dispose();\n                }\n            }\n            catch\n            {\n            }\n\n            _timers.Clear();\n            _cache.Clear();\n        }\n        finally\n        {\n            _locker.ExitWriteLock();\n        }\n    }\n\n    #endregion\n\n    #region CheckTimer\n\n    // Checks whether a specific timer already exists and adds a new one, if not \n    private void CheckTimer(K key, TimeSpan? cacheTimeout, bool restartTimerIfExists)\n    {\n        Timer timer;\n\n        if (_timers.TryGetValue(key, out timer))\n        {\n            if (restartTimerIfExists)\n                timer.Change(\n                    cacheTimeout ?? Timeout.InfiniteTimeSpan,\n                    Timeout.InfiniteTimeSpan);\n        }\n        else\n        {\n            _timers.Add(\n                key,\n                new Timer(\n                    RemoveByTimer,\n                    key,\n                    cacheTimeout ?? Timeout.InfiniteTimeSpan,\n                    Timeout.InfiniteTimeSpan));\n        }\n    }\n\n    private void RemoveByTimer(object state)\n    {\n        Remove((K)state);\n    }\n\n    #endregion\n\n    #region AddOrUpdate, Get, Remove, Exists, Clear\n\n    /// <summary>\n    /// Adds or updates the specified cache-key with the specified cacheObject and applies a specified timeout (in seconds)\n    /// to this key.\n    /// </summary>\n    /// <param name=\"key\">The cache-key to add or update.</param>\n    /// <param name=\"cacheObject\">The cache object to store.</param>\n    /// <param name=\"cacheTimeout\">\n    /// The cache timeout (lifespan) of this object. Must be 1 or greater.\n    /// Specify Timeout.Infinite to keep the entry forever.\n    /// </param>\n    /// <param name=\"restartTimerIfExists\">\n    /// (Optional). If set to <c>true</c>, the timer for this cacheObject will be reset if the object already\n    /// exists in the cache. (Default = false).\n    /// </param>\n    public void AddOrUpdate(K key, T cacheObject, TimeSpan? cacheTimeout, bool restartTimerIfExists = false)\n    {\n        if (disposed) return;\n\n        _locker.EnterWriteLock();\n        try\n        {\n            CheckTimer(key, cacheTimeout, restartTimerIfExists);\n\n            if (!_cache.ContainsKey(key))\n                _cache.Add(key, cacheObject);\n            else\n                _cache[key] = cacheObject;\n        }\n        finally\n        {\n            _locker.ExitWriteLock();\n        }\n    }\n\n    /// <summary>\n    /// Adds or updates the specified cache-key with the specified cacheObject and applies <c>Timeout.Infinite</c> to this\n    /// key.\n    /// </summary>\n    /// <param name=\"key\">The cache-key to add or update.</param>\n    /// <param name=\"cacheObject\">The cache object to store.</param>\n    public void AddOrUpdate(K key, T cacheObject)\n    {\n        AddOrUpdate(key, cacheObject, Timeout.InfiniteTimeSpan);\n    }\n\n    /// <summary>\n    /// Gets the cache entry with the specified key or returns <c>default(T)</c> if the key is not found.\n    /// </summary>\n    /// <param name=\"key\">The cache-key to retrieve.</param>\n    /// <returns>The object from the cache or <c>default(T)</c>, if not found.</returns>\n    public T this[K key] => Get(key);\n\n    /// <summary>\n    /// Gets the cache entry with the specified key or return <c>default(T)</c> if the key is not found.\n    /// </summary>\n    /// <param name=\"key\">The cache-key to retrieve.</param>\n    /// <returns>The object from the cache or <c>default(T)</c>, if not found.</returns>\n    public T Get(K key)\n    {\n        if (disposed) return default;\n\n        _locker.EnterReadLock();\n        try\n        {\n            T rv;\n            return _cache.TryGetValue(key, out rv) ? rv : default;\n        }\n        finally\n        {\n            _locker.ExitReadLock();\n        }\n    }\n\n    /// <summary>\n    /// Tries to gets the cache entry with the specified key.\n    /// </summary>\n    /// <param name=\"key\">The key.</param>\n    /// <param name=\"value\">(out) The value, if found, or <c>default(T)</c>, if not.</param>\n    /// <returns><c>True</c>, if <c>key</c> exists, otherwise <c>false</c>.</returns>\n    public bool TryGet(K key, out T value)\n    {\n        if (disposed)\n        {\n            value = default;\n            return false;\n        }\n\n        _locker.EnterReadLock();\n        try\n        {\n            return _cache.TryGetValue(key, out value);\n        }\n        finally\n        {\n            _locker.ExitReadLock();\n        }\n    }\n\n    /// <summary>\n    /// Removes a series of cache entries in a single call for all key that match the specified key pattern.\n    /// </summary>\n    /// <param name=\"keyPattern\">The key pattern to remove. The Predicate has to return true to get key removed.</param>\n    public void Remove(Predicate<K> keyPattern)\n    {\n        if (disposed) return;\n\n        _locker.EnterWriteLock();\n        try\n        {\n            var removers = (from k in _cache.Keys\n                where keyPattern(k)\n                select k).ToList();\n\n            foreach (var workKey in removers)\n            {\n                try\n                {\n                    _timers[workKey].Dispose();\n                }\n                catch\n                {\n                }\n\n                _timers.Remove(workKey);\n                _cache.Remove(workKey);\n            }\n        }\n        finally\n        {\n            _locker.ExitWriteLock();\n        }\n    }\n\n    /// <summary>\n    /// Removes the specified cache entry with the specified key.\n    /// If the key is not found, no exception is thrown, the statement is just ignored.\n    /// </summary>\n    /// <param name=\"key\">The cache-key to remove.</param>\n    public void Remove(K key)\n    {\n        if (disposed) return;\n\n        _locker.EnterWriteLock();\n        try\n        {\n            if (_cache.ContainsKey(key))\n            {\n                try\n                {\n                    _timers[key].Dispose();\n                }\n                catch\n                {\n                }\n\n                _timers.Remove(key);\n                _cache.Remove(key);\n            }\n        }\n        finally\n        {\n            _locker.ExitWriteLock();\n        }\n    }\n\n    /// <summary>\n    /// Checks if a specified key exists in the cache.\n    /// </summary>\n    /// <param name=\"key\">The cache-key to check.</param>\n    /// <returns><c>True</c> if the key exists in the cache, otherwise <c>False</c>.</returns>\n    public bool Exists(K key)\n    {\n        if (disposed) return false;\n\n        _locker.EnterReadLock();\n        try\n        {\n            return _cache.ContainsKey(key);\n        }\n        finally\n        {\n            _locker.ExitReadLock();\n        }\n    }\n\n    #endregion\n}\n\n#endregion\n\n#region Other Cache classes (derived)\n\n/// <summary>\n/// This is a generic cache subsystem based on key/value pairs, where key is a string.\n/// You can add any item to this cache as long as the key is unique, so treat keys as something like namespaces and\n/// build them with a\n/// specific system/syntax in your application.\n/// Every cache entry has its own timeout.\n/// Cache is thread safe and will delete expired entries on its own using System.Threading.Timers (which run on\n/// <see cref=\"ThreadPool\" /> threads).\n/// </summary>\n/// <summary>\n/// The non-generic Cache class instanciates a Cache{object} that can be used with any type of (mixed) contents.\n/// It also publishes a static <c>.Global</c> member, so a cache can be used even without creating a dedicated\n/// instance.\n/// The <c>.Global</c> member is lazy instanciated.\n/// </summary>\npublic class CapCache : Cache<string, object>\n{\n    #region Static Global Cache instance\n\n    private static readonly Lazy<CapCache> global = new();\n\n    /// <summary>\n    /// Gets the global shared cache instance valid for the entire process.\n    /// </summary>\n    /// <value>\n    /// The global shared cache instance.\n    /// </value>\n    public static CapCache Global => global.Value;\n\n    #endregion\n}\n\n#endregion"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/CircularBuffer.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\n\nnamespace DotNetCore.CAP.Dashboard;\n\n/// <summary>\n/// A generic circular buffer.\n/// </summary>\n/// <typeparam name=\"T\">The type of items that are buffered.</typeparam>\ninternal class CircularBuffer<T> : ICollection<T>\n{\n    // Ring of items\n    private readonly T[] _items;\n\n    // Current length, as opposed to the total capacity\n    // Current start of the list. Starts at 0, but may\n    // move forwards or wrap around back to 0 due to\n    // rotation.\n    private int _firstIndex;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"CircularBuffer{T}\" /> class.\n    /// </summary>\n    /// <param name=\"capacity\">The maximum capacity of the buffer.</param>\n    /// <exception cref=\"ArgumentOutOfRangeException\">If <paramref name=\"capacity\" /> is negative.</exception>\n    public CircularBuffer(int capacity)\n    {\n        if (capacity < 0) throw new ArgumentOutOfRangeException(nameof(capacity));\n\n        _items = new T[capacity];\n        Clear();\n    }\n\n    /// <summary>\n    /// Gets the maximum capacity of the buffer. If more items\n    /// are added than the buffer has capacity for, then\n    /// older items will be removed from the buffer with\n    /// a first-in, first-out policy.\n    /// </summary>\n    public int Capacity => _items.Length;\n\n    /// <summary>\n    /// Whether or not the buffer is at capacity.\n    /// </summary>\n    public bool IsFull => Count == Capacity;\n\n    /// <summary>\n    /// Access an item in the buffer. Indexing is based off\n    /// of the order items were added, rather than any\n    /// internal ordering the buffer may be maintaining.\n    /// </summary>\n    /// <param name=\"index\">The index of the item to access.</param>\n    /// <returns>The buffered item at index <paramref name=\"index\" />.</returns>\n    public T this[int index]\n    {\n        get\n        {\n            if (!(index >= 0 && index < Count)) throw new ArgumentOutOfRangeException(nameof(index));\n\n            return _items[WrapIndex(index)];\n        }\n    }\n\n    /// <summary>\n    /// Convert from a 0-based index to a buffer index which\n    /// has been properly offset and wrapped.\n    /// </summary>\n    /// <param name=\"zeroBasedIndex\">The index to wrap.</param>\n    /// <exception cref=\"ArgumentOutOfRangeException\">If <paramref name=\"zeroBasedIndex\" /> is out of range.</exception>\n    /// <returns>\n    /// The actual index that\n    /// <param ref=\"zeroBasedIndex\" />\n    /// maps to.\n    /// </returns>\n    private int WrapIndex(int zeroBasedIndex)\n    {\n        if (Capacity == 0 || zeroBasedIndex < 0) throw new ArgumentOutOfRangeException(nameof(zeroBasedIndex));\n\n        return (zeroBasedIndex + _firstIndex) % Capacity;\n    }\n\n    /// <summary>\n    /// Create an array of the items in the buffer. Items\n    /// will be in the same order they were added.\n    /// </summary>\n    /// <returns>The new array.</returns>\n    public T[] ToArray()\n    {\n        var result = new T[Count];\n        CopyTo(result, 0);\n        return result;\n    }\n\n    #region IEnumerable<T> implementation.\n\n    public IEnumerator<T> GetEnumerator()\n    {\n        for (var i = 0; i < Count; i++)\n        {\n            yield return _items[WrapIndex(i)];\n        }\n    }\n\n    IEnumerator IEnumerable.GetEnumerator()\n    {\n        return GetEnumerator();\n    }\n\n    #endregion\n\n    #region ICollection<T> implementation\n\n    public int Count { get; private set; }\n\n    public bool IsReadOnly => false;\n\n    /// <summary>\n    /// Adds an item to the buffer. If the buffer is already\n    /// full, the oldest item in the list will be removed,\n    /// and the new item added at the logical end of the list.\n    /// </summary>\n    /// <param name=\"item\">The item to add.</param>\n    public void Add(T item)\n    {\n        if (Capacity == 0) return;\n\n        int itemIndex;\n\n        if (IsFull)\n        {\n            itemIndex = _firstIndex;\n            _firstIndex = (_firstIndex + 1) % Capacity;\n        }\n        else\n        {\n            itemIndex = _firstIndex + Count;\n            Count++;\n        }\n\n        _items[itemIndex] = item;\n    }\n\n    public void Clear()\n    {\n        _firstIndex = 0;\n        Count = 0;\n    }\n\n    public bool Contains(T item)\n    {\n        throw new NotImplementedException();\n    }\n\n    public void CopyTo(T[] array, int arrayIndex)\n    {\n        if (array == null) throw new ArgumentNullException(nameof(array));\n\n        if (arrayIndex < 0) throw new ArgumentOutOfRangeException(nameof(arrayIndex));\n\n        if (Count > array.Length - arrayIndex) throw new ArgumentException(\"arrayIndex\");\n\n        // Iterate through the buffer in correct order.\n        foreach (var item in this)\n        {\n            array[arrayIndex++] = item;\n        }\n    }\n\n    public bool Remove(T item)\n    {\n        throw new NotImplementedException();\n    }\n\n    #endregion\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/DotNetCore.CAP.Dashboard.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<TargetFramework>net8.0</TargetFramework>\n\t\t<LangVersion>default</LangVersion>\n\t\t<Nullable>disable</Nullable>\n\t</PropertyGroup>\n\n\t<ItemGroup>\n\t\t<FrameworkReference Include=\"Microsoft.AspNetCore.App\" />\n\t\t<PackageReference Include=\"Consul\" Version=\"1.7.14.9\" />\n\t\t<SupportedPlatform Include=\"browser\" />\n\t</ItemGroup>\n\n\t<ItemGroup>\n\t\t<EmbeddedResource Include=\"wwwroot/dist/**/*\" Exclude=\"**/*/*.map\" />\n\t\t<Compile Include=\"..\\DotNetCore.CAP\\Internal\\ObjectMethodExecutor\\*.cs\" Link=\"ObjectMethodExecutor\\%(Filename)%(Extension)\" />\n\t</ItemGroup>\n\n\t<ItemGroup>\n\t\t<ProjectReference Include=\"..\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n\t</ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/GatewayProxy/GatewayProxyAgent.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Net;\nusing System.Net.Http;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Dashboard.GatewayProxy.Requester;\nusing DotNetCore.CAP.Dashboard.NodeDiscovery;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Primitives;\n\nnamespace DotNetCore.CAP.Dashboard.GatewayProxy;\n\npublic class GatewayProxyAgent\n{\n    public const string CookieNodeName = \"cap.node\";\n    public const string CookieNodeNsName = \"cap.node.ns\";\n\n    private readonly ConsulDiscoveryOptions _consulDiscoveryOptions;\n    private readonly INodeDiscoveryProvider _discoveryProvider;\n    private readonly ILogger _logger;\n\n    private readonly IHttpRequester _requester;\n    private readonly IRequestMapper _requestMapper;\n\n    public GatewayProxyAgent(\n        ILoggerFactory loggerFactory,\n        IRequestMapper requestMapper,\n        IHttpRequester requester,\n        IServiceProvider serviceProvider,\n        INodeDiscoveryProvider discoveryProvider)\n    {\n        _logger = loggerFactory.CreateLogger<GatewayProxyAgent>();\n        _requestMapper = requestMapper;\n        _requester = requester;\n        _discoveryProvider = discoveryProvider;\n        _consulDiscoveryOptions = serviceProvider.GetService<ConsulDiscoveryOptions>();\n    }\n\n    protected HttpRequestMessage DownstreamRequest { get; set; }\n\n    public async Task<bool> Invoke(HttpContext context)\n    {\n        var request = context.Request;\n        var isSwitchNode = request.Cookies.TryGetValue(CookieNodeName, out var requestNodeName);\n        if (!isSwitchNode) return false;\n\n        _logger.LogDebug(\"start calling remote endpoint...\");\n\n        Node node;\n        if (_consulDiscoveryOptions == null) // it's k8s\n        {\n            if (request.Cookies.TryGetValue(CookieNodeNsName, out var ns))\n            {\n                if (CapCache.Global.TryGet(requestNodeName + ns, out var nodeObj))\n                {\n                    node = (Node)nodeObj;\n                }\n                else\n                {\n                    node = await _discoveryProvider.GetNode(requestNodeName, ns);\n                    CapCache.Global.AddOrUpdate(requestNodeName + ns, node);\n                }\n            }\n            else\n            {\n                return false;\n            }\n        }\n        else\n        {\n            if (_consulDiscoveryOptions.NodeName == requestNodeName) return false;\n\n            if (CapCache.Global.TryGet(requestNodeName, out var nodeObj))\n            {\n                node = (Node)nodeObj;\n            }\n            else\n            {\n                node = await _discoveryProvider.GetNode(requestNodeName);\n                CapCache.Global.AddOrUpdate(requestNodeName, node);\n            }\n        }\n\n        if (node != null)\n        {\n            try\n            {\n                DownstreamRequest = await _requestMapper.Map(request);\n\n                SetDownStreamRequestUri(node, request.Path.Value, request.QueryString.Value);\n\n                var response = await _requester.GetResponse(DownstreamRequest);\n\n                await SetResponseOnHttpContext(context, response);\n\n                return true;\n            }\n            catch (Exception ex)\n            {\n                _logger.LogError(ex.Message);\n            }\n        }\n        else\n        {\n            context.Response.Cookies.Delete(CookieNodeName);\n            return false;\n        }\n\n        return false;\n    }\n\n    private async Task SetResponseOnHttpContext(HttpContext context, HttpResponseMessage response)\n    {\n        foreach (var httpResponseHeader in response.Content.Headers)\n        {\n            AddHeaderIfDoesntExist(context, httpResponseHeader);\n        }\n\n        var content = await response.Content.ReadAsByteArrayAsync();\n\n        AddHeaderIfDoesntExist(context,\n            new KeyValuePair<string, IEnumerable<string>>(\"Content-Length\", new[] { content.Length.ToString() }));\n\n        context.Response.OnStarting(state =>\n        {\n            var httpContext = (HttpContext)state;\n\n            httpContext.Response.StatusCode = (int)response.StatusCode;\n\n            return Task.CompletedTask;\n        }, context);\n\n        await using Stream stream = new MemoryStream(content);\n        if (response.StatusCode != HttpStatusCode.NotModified) await stream.CopyToAsync(context.Response.Body);\n    }\n\n    private void SetDownStreamRequestUri(Node node, string requestPath, string queryString)\n    {\n        UriBuilder uriBuilder;\n        if (node.Address.StartsWith(\"http\"))\n            uriBuilder = new UriBuilder(node.Address + requestPath + queryString);\n        else\n            uriBuilder = new UriBuilder(\"http://\", node.Address, node.Port, requestPath, queryString);\n\n        if (node.Port > 0)\n            uriBuilder.Port = node.Port;\n\n        DownstreamRequest.RequestUri = uriBuilder.Uri;\n    }\n\n    private static void AddHeaderIfDoesntExist(HttpContext context, KeyValuePair<string, IEnumerable<string>> httpResponseHeader)\n    {\n        if (!context.Response.Headers.ContainsKey(httpResponseHeader.Key))\n            context.Response.Headers.Append(httpResponseHeader.Key, new StringValues(httpResponseHeader.Value.ToArray()));\n    }\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/GatewayProxy/IRequestMapper.Default.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Net.Http;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Primitives;\n\nnamespace DotNetCore.CAP.Dashboard.GatewayProxy;\n\npublic class RequestMapper : IRequestMapper\n{\n    private const string SchemeDelimiter = \"://\";\n    private readonly string[] _unsupportedHeaders = { \"host\", \"cookie\" };\n\n    public async Task<HttpRequestMessage> Map(HttpRequest request)\n    {\n        try\n        {\n            var requestMessage = new HttpRequestMessage\n            {\n                Content = await MapContent(request),\n                Method = MapMethod(request),\n                RequestUri = MapUri(request)\n            };\n\n            MapHeaders(request, requestMessage);\n\n            return requestMessage;\n        }\n        catch (Exception ex)\n        {\n            throw new Exception($\"Error when parsing incoming request, exception: {ex.Message}\");\n        }\n    }\n\n    private string BuildAbsolute(\n        string scheme,\n        HostString host,\n        PathString pathBase = new(),\n        PathString path = new(),\n        QueryString query = new(),\n        FragmentString fragment = new())\n    {\n        if (scheme == null) throw new ArgumentNullException(nameof(scheme));\n\n        var combinedPath = pathBase.HasValue || path.HasValue ? (pathBase + path).ToString() : \"/\";\n\n        var encodedHost = host.ToString();\n        var encodedQuery = query.ToString();\n        var encodedFragment = fragment.ToString();\n\n        // PERF: Calculate string length to allocate correct buffer size for StringBuilder.\n        var length = scheme.Length + SchemeDelimiter.Length + encodedHost.Length\n                     + combinedPath.Length + encodedQuery.Length + encodedFragment.Length;\n\n        return new StringBuilder(length)\n            .Append(scheme)\n            .Append(SchemeDelimiter)\n            .Append(encodedHost)\n            .Append(combinedPath)\n            .Append(encodedQuery)\n            .Append(encodedFragment)\n            .ToString();\n    }\n\n    private string GetEncodedUrl(HttpRequest request)\n    {\n        return BuildAbsolute(request.Scheme, request.Host, request.PathBase, request.Path, request.QueryString);\n    }\n\n    private async Task<HttpContent> MapContent(HttpRequest request)\n    {\n        if (request.Body == null) return null;\n\n        var content = new ByteArrayContent(await ToByteArray(request.Body));\n\n        content.Headers.TryAddWithoutValidation(\"Content-Type\", new[] { request.ContentType });\n\n        return content;\n    }\n\n    private HttpMethod MapMethod(HttpRequest request)\n    {\n        return new HttpMethod(request.Method);\n    }\n\n    private Uri MapUri(HttpRequest request)\n    {\n        return new Uri(GetEncodedUrl(request));\n    }\n\n    private void MapHeaders(HttpRequest request, HttpRequestMessage requestMessage)\n    {\n        foreach (var header in request.Headers)\n        {\n            if (IsSupportedHeader(header))\n                requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());\n        }\n    }\n\n    private async Task<byte[]> ToByteArray(Stream stream)\n    {\n        using (stream)\n        {\n            using (var memStream = new MemoryStream())\n            {\n                await stream.CopyToAsync(memStream);\n                return memStream.ToArray();\n            }\n        }\n    }\n\n    private bool IsSupportedHeader(KeyValuePair<string, StringValues> header)\n    {\n        return !_unsupportedHeaders.Contains(header.Key.ToLower());\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/GatewayProxy/IRequestMapper.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Net.Http;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Http;\n\nnamespace DotNetCore.CAP.Dashboard.GatewayProxy;\n\npublic interface IRequestMapper\n{\n    Task<HttpRequestMessage> Map(HttpRequest request);\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/HttpClientBuilder.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net.Http;\nusing System.Threading.Tasks;\n\nnamespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester;\n\ninternal class HttpClientBuilder : IHttpClientBuilder\n{\n    private readonly Dictionary<int, Func<DelegatingHandler>> _handlers = new();\n\n    public IHttpClient Create()\n    {\n        var httpclientHandler = new HttpClientHandler();\n\n        var client = new HttpClient(CreateHttpMessageHandler(httpclientHandler));\n\n        return new HttpClientWrapper(client);\n    }\n\n    private HttpMessageHandler CreateHttpMessageHandler(HttpMessageHandler httpMessageHandler)\n    {\n        _handlers\n            .OrderByDescending(handler => handler.Key)\n            .Select(handler => handler.Value)\n            .Reverse()\n            .ToList()\n            .ForEach(handler =>\n            {\n                var delegatingHandler = handler();\n                delegatingHandler.InnerHandler = httpMessageHandler;\n                httpMessageHandler = delegatingHandler;\n            });\n        return httpMessageHandler;\n    }\n}\n\n/// <summary>\n/// This class was made to make unit testing easier when HttpClient is used.\n/// </summary>\ninternal class HttpClientWrapper : IHttpClient\n{\n    public HttpClientWrapper(HttpClient client)\n    {\n        Client = client;\n    }\n\n    public HttpClient Client { get; }\n\n    public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)\n    {\n        return Client.SendAsync(request);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/HttpClientHttpRequester.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Net.Http;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\n\nnamespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester;\n\npublic class HttpClientHttpRequester : IHttpRequester\n{\n    private readonly IHttpClientCache _cacheHandlers;\n    private readonly ILogger _logger;\n\n    public HttpClientHttpRequester(ILoggerFactory loggerFactory, IHttpClientCache cacheHandlers)\n    {\n        _logger = loggerFactory.CreateLogger<HttpClientHttpRequester>();\n        _cacheHandlers = cacheHandlers;\n    }\n\n    public async Task<HttpResponseMessage> GetResponse(HttpRequestMessage request)\n    {\n        var builder = new HttpClientBuilder();\n\n        var cacheKey = GetCacheKey(request, builder);\n\n        var httpClient = GetHttpClient(cacheKey, builder);\n\n        try\n        {\n            return await httpClient.SendAsync(request);\n        }\n        catch (Exception exception)\n        {\n            _logger.LogError(\"Error making http request, exception:\" + exception.Message);\n            throw;\n        }\n        finally\n        {\n            _cacheHandlers.Set(cacheKey, httpClient, TimeSpan.FromHours(24));\n        }\n    }\n\n    private IHttpClient GetHttpClient(string cacheKey, IHttpClientBuilder builder)\n    {\n        var httpClient = _cacheHandlers.Get(cacheKey);\n\n        if (httpClient == null) httpClient = builder.Create();\n\n        return httpClient;\n    }\n\n    private string GetCacheKey(HttpRequestMessage request, IHttpClientBuilder builder)\n    {\n        var baseUrl = $\"{request.RequestUri.Scheme}://{request.RequestUri.Authority}\";\n\n        return baseUrl;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/IHttpClient.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Net.Http;\nusing System.Threading.Tasks;\n\nnamespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester;\n\npublic interface IHttpClient\n{\n    HttpClient Client { get; }\n\n    Task<HttpResponseMessage> SendAsync(HttpRequestMessage request);\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/IHttpClientBuilder.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Net.Http;\n\nnamespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester;\n\npublic interface IHttpClientBuilder\n{\n    /// <summary>\n    /// Creates the <see cref=\"HttpClient\" />\n    /// </summary>\n    IHttpClient Create();\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/IHttpClientCache.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\n\nnamespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester;\n\npublic interface IHttpClientCache\n{\n    bool Exists(string id);\n\n    IHttpClient Get(string id);\n\n    void Remove(string id);\n\n    void Set(string id, IHttpClient handler, TimeSpan expirationTime);\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/IHttpRequester.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Net.Http;\nusing System.Threading.Tasks;\n\nnamespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester;\n\npublic interface IHttpRequester\n{\n    Task<HttpResponseMessage> GetResponse(HttpRequestMessage request);\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/MemoryHttpClientCache.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Concurrent;\n\nnamespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester;\n\npublic class MemoryHttpClientCache : IHttpClientCache\n{\n    private readonly ConcurrentDictionary<string, ConcurrentQueue<IHttpClient>> _httpClientsCache = new();\n\n    public void Set(string id, IHttpClient client, TimeSpan expirationTime)\n    {\n        if (_httpClientsCache.TryGetValue(id, out var connectionQueue))\n        {\n            connectionQueue.Enqueue(client);\n        }\n        else\n        {\n            connectionQueue = new ConcurrentQueue<IHttpClient>();\n            connectionQueue.Enqueue(client);\n            _httpClientsCache.TryAdd(id, connectionQueue);\n        }\n    }\n\n    public bool Exists(string id)\n    {\n        return _httpClientsCache.TryGetValue(id, out _);\n    }\n\n    public IHttpClient Get(string id)\n    {\n        IHttpClient client = null;\n        if (_httpClientsCache.TryGetValue(id, out var connectionQueue)) connectionQueue.TryDequeue(out client);\n\n        return client;\n    }\n\n    public void Remove(string id)\n    {\n        _httpClientsCache.TryRemove(id, out _);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/HtmlHelper.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Reflection;\nusing DotNetCore.CAP.Internal;\nusing Microsoft.Extensions.Internal;\n\nnamespace DotNetCore.CAP.Dashboard;\n\npublic class HtmlHelper\n{\n    public static string MethodEscaped(MethodInfo method)\n    {\n        var @public = WrapKeyword(\"public\");\n        var async = string.Empty;\n        string @return;\n\n        var isAwaitable = CoercedAwaitableInfo.IsTypeAwaitable(method.ReturnType, out var coercedAwaitableInfo);\n        if (isAwaitable)\n        {\n            async = WrapKeyword(\"async\");\n            var asyncResultType = coercedAwaitableInfo.AwaitableInfo.ResultType;\n            if (asyncResultType.Name == \"Void\")\n                @return = WrapType(\"Task\");\n            else\n                @return = WrapType(\"Task\") + WrapIdentifier(\"<\") + WrapType(asyncResultType) + WrapIdentifier(\">\");\n        }\n        else\n        {\n            @return = WrapType(method.ReturnType);\n        }\n\n        var name = method.Name;\n\n        string paramType = null;\n        string paramName = null;\n\n        var @params = method.GetParameters();\n        if (@params.Length == 1)\n        {\n            var firstParam = @params[0];\n            var firstParamType = firstParam.ParameterType;\n            paramType = WrapType(firstParamType);\n            paramName = firstParam.Name;\n        }\n\n        var paramString = paramType == null ? \"();\" : $\"({paramType} {paramName});\";\n\n        var outputString = @public + \" \" + (string.IsNullOrEmpty(async) ? \"\" : async + \" \") + @return + \" \" + name +\n                           paramString;\n\n        return outputString;\n    }\n\n    private static string WrapType(Type type)\n    {\n        if (type == null) return string.Empty;\n\n        if (type.Name == \"Void\") return WrapKeyword(type.Name.ToLower());\n\n        if (Helper.IsComplexType(type)) return WrapType(type.Name);\n\n        if (type.IsPrimitive || type == typeof(string) || type == typeof(decimal))\n            return WrapKeyword(type.Name.ToLower());\n\n        return WrapType(type.Name);\n    }\n\n    private static string WrapIdentifier(string value)\n    {\n        return value;\n    }\n\n    private static string WrapKeyword(string value)\n    {\n        return Span(\"keyword\", value);\n    }\n\n    private static string WrapType(string value)\n    {\n        return Span(\"type\", value);\n    }\n\n    private static string Span(string @class, string value)\n    {\n        return $\"<span class=\\\"{@class}\\\">{value}</span>\";\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/NodeDiscovery/CAP.ConsulDiscoveryOptions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nnamespace DotNetCore.CAP.Dashboard.NodeDiscovery;\n\npublic class ConsulDiscoveryOptions\n{\n    public const string DefaultDiscoveryServerHost = \"localhost\";\n    public const int DefaultDiscoveryServerPort = 8500;\n\n    public const string DefaultCurrentNodeHostName = \"localhost\";\n    public const int DefaultCurrentNodePort = 5000;\n\n    public const string DefaultMatchPath = \"/cap\";\n\n    public const string DefaultScheme = \"http\";\n\n    public string DiscoveryServerHostName { get; set; } = DefaultDiscoveryServerHost;\n    public int DiscoveryServerPort { get; set; } = DefaultDiscoveryServerPort;\n\n    public string CurrentNodeHostName { get; set; } = DefaultCurrentNodeHostName;\n    public int CurrentNodePort { get; set; } = DefaultCurrentNodePort;\n\n    public string NodeId { get; set; }\n    public string NodeName { get; set; }\n\n    public string MatchPath { get; set; } = DefaultMatchPath;\n\n    public string Scheme { get; set; } = DefaultScheme;\n\n    public string[] CustomTags { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/NodeDiscovery/CAP.ConsulDiscoveryOptionsExtensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP;\nusing DotNetCore.CAP.Dashboard.GatewayProxy;\nusing DotNetCore.CAP.Dashboard.GatewayProxy.Requester;\nusing DotNetCore.CAP.Dashboard.NodeDiscovery;\nusing DotNetCore.CAP.Internal;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace DotNetCore.CAP.Dashboard.NodeDiscovery\n{\n    internal sealed class ConsulDiscoveryOptionsExtension : ICapOptionsExtension\n    {\n        private readonly Action<ConsulDiscoveryOptions> _options;\n\n        public ConsulDiscoveryOptionsExtension(Action<ConsulDiscoveryOptions> option)\n        {\n            _options = option;\n        }\n\n        public void AddServices(IServiceCollection services)\n        {\n            var discoveryOptions = new ConsulDiscoveryOptions();\n\n            _options?.Invoke(discoveryOptions);\n            services.AddSingleton(discoveryOptions);\n\n            services.AddSingleton<IHttpRequester, HttpClientHttpRequester>();\n            services.AddSingleton<IHttpClientCache, MemoryHttpClientCache>();\n            services.AddSingleton<IRequestMapper, RequestMapper>();\n            services.AddSingleton<GatewayProxyAgent>();\n            services.AddSingleton<IProcessingServer, ConsulProcessingNodeServer>();\n            services.AddSingleton<INodeDiscoveryProvider, ConsulNodeDiscoveryProvider>();\n        }\n    }\n}\n\nnamespace Microsoft.Extensions.DependencyInjection\n{\n    public static class CapDiscoveryOptionsExtensions\n    {\n        /// <summary>\n        /// Default use kubernetes as service discovery.\n        /// </summary>\n        public static CapOptions UseConsulDiscovery(this CapOptions capOptions)\n        {\n            return capOptions.UseConsulDiscovery(_ => { });\n        }\n\n        public static CapOptions UseConsulDiscovery(this CapOptions capOptions, Action<ConsulDiscoveryOptions> options)\n        {\n            if (options == null) throw new ArgumentNullException(nameof(options));\n\n            capOptions.RegisterExtension(new ConsulDiscoveryOptionsExtension(options));\n\n            return capOptions;\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/NodeDiscovery/INodeDiscoveryProvider.Consul.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Consul;\nusing Microsoft.Extensions.Logging;\n\nnamespace DotNetCore.CAP.Dashboard.NodeDiscovery;\n\npublic class ConsulNodeDiscoveryProvider : INodeDiscoveryProvider\n{\n    private readonly ConsulDiscoveryOptions _discoveryOptions;\n    private readonly ILogger<ConsulNodeDiscoveryProvider> _logger;\n\n    public ConsulNodeDiscoveryProvider(ILoggerFactory logger, ConsulDiscoveryOptions options)\n    {\n        _logger = logger.CreateLogger<ConsulNodeDiscoveryProvider>();\n        _discoveryOptions = options;\n    }\n\n    public async Task<Node> GetNode(string nodeName, string ns, CancellationToken cancellationToken = default)\n    {\n        try\n        {\n            using var consul = new ConsulClient(config =>\n            {\n                config.WaitTime = TimeSpan.FromSeconds(5);\n                config.Address =\n                    new Uri(\n                        $\"http://{_discoveryOptions.DiscoveryServerHostName}:{_discoveryOptions.DiscoveryServerPort}\");\n            });\n            var serviceCatalog = await consul.Catalog.Service(nodeName, \"CAP\", cancellationToken);\n            if (serviceCatalog.StatusCode == HttpStatusCode.OK)\n                return serviceCatalog.Response.Select(info => new Node\n                {\n                    Id = info.ServiceID,\n                    Name = info.ServiceName,\n                    Address = info.ServiceAddress,\n                    Port = info.ServicePort,\n                    Tags = string.Join(\", \", info.ServiceTags)\n                }).FirstOrDefault();\n        }\n        catch (Exception ex)\n        {\n            _logger.LogError(ex, $\"Get consul nodes raised an exception. Exception:{ex.Message}\");\n        }\n\n        return null;\n    }\n\n\n    public async Task<IList<Node>> GetNodes(string ns, CancellationToken cancellationToken)\n    {\n        try\n        {\n            var nodes = new List<Node>();\n\n            using var consul = new ConsulClient(config =>\n            {\n                config.WaitTime = TimeSpan.FromSeconds(5);\n                config.Address =\n                    new Uri(\n                        $\"http://{_discoveryOptions.DiscoveryServerHostName}:{_discoveryOptions.DiscoveryServerPort}\");\n            });\n\n            var services = await consul.Catalog.Services(cancellationToken);\n\n            foreach (var service in services.Response)\n            {\n                var serviceInfo = consul.Catalog.Service(service.Key, \"CAP\", cancellationToken).GetAwaiter()\n                    .GetResult();\n                var node = serviceInfo.Response.Select(info => new Node\n                {\n                    Id = info.ServiceID,\n                    Name = info.ServiceName,\n                    Address = \"http://\" + info.ServiceAddress,\n                    Port = info.ServicePort,\n                    Tags = string.Join(\", \", info.ServiceTags)\n                }).ToList();\n\n                nodes.AddRange(node);\n            }\n\n            CapCache.Global.AddOrUpdate(\"cap.nodes.count\", nodes.Count, TimeSpan.FromSeconds(60), true);\n\n            return nodes;\n        }\n        catch (Exception ex)\n        {\n            CapCache.Global.AddOrUpdate(\"cap.nodes.count\", 0, TimeSpan.FromSeconds(20));\n\n            _logger.LogError(\n                $\"Get consul nodes raised an exception. Exception:{ex.Message},{ex.InnerException.Message}\");\n            return null;\n        }\n    }\n\n    public async Task RegisterNode(CancellationToken cancellationToken)\n    {\n        try\n        {\n            var healthCheck = new AgentServiceCheck\n            {\n                DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(30),\n                Interval = TimeSpan.FromSeconds(10),\n                Status = HealthStatus.Passing\n            };\n\n            if (_discoveryOptions.Scheme.Equals(\"http\", StringComparison.OrdinalIgnoreCase))\n                healthCheck.HTTP =\n                    $\"http://{_discoveryOptions.CurrentNodeHostName}:{_discoveryOptions.CurrentNodePort}{_discoveryOptions.MatchPath}/api/health\";\n            else if (_discoveryOptions.Scheme.Equals(\"https\", StringComparison.OrdinalIgnoreCase))\n                healthCheck.TCP = $\"{_discoveryOptions.CurrentNodeHostName}:{_discoveryOptions.CurrentNodePort}\";\n\n            var tags = new[] { \"CAP\", \"Client\", \"Dashboard\" };\n            if (_discoveryOptions.CustomTags != null && _discoveryOptions.CustomTags.Length > 0)\n                tags = tags.Union(_discoveryOptions.CustomTags).ToArray();\n\n            using var consul = new ConsulClient(config =>\n            {\n                config.WaitTime = TimeSpan.FromSeconds(5);\n                config.Address =\n                    new Uri(\n                        $\"http://{_discoveryOptions.DiscoveryServerHostName}:{_discoveryOptions.DiscoveryServerPort}\");\n            });\n\n            var result = await consul.Agent.ServiceRegister(new AgentServiceRegistration\n            {\n                ID = _discoveryOptions.NodeId,\n                Name = _discoveryOptions.NodeName,\n                Address = _discoveryOptions.CurrentNodeHostName,\n                Port = _discoveryOptions.CurrentNodePort,\n                Tags = tags,\n                Check = healthCheck\n            }, cancellationToken);\n\n            if (result.StatusCode == HttpStatusCode.OK) _logger.LogInformation(\"Consul node register success!\");\n        }\n        catch (Exception ex)\n        {\n            _logger.LogError(\n                $\"Get consul nodes raised an exception. Exception:{ex.Message},{ex.InnerException.Message}\");\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/NodeDiscovery/INodeDiscoveryProvider.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace DotNetCore.CAP.Dashboard.NodeDiscovery;\n\npublic interface INodeDiscoveryProvider\n{\n    Task<IList<Node>> GetNodes(string ns = null, CancellationToken cancellationToken = default);\n\n    Task<Node> GetNode(string nodeName, string ns = null, CancellationToken cancellationToken = default);\n\n    Task RegisterNode(CancellationToken cancellationToken = default)\n    {\n        throw new NotImplementedException();\n    }\n\n    Task<List<string>> GetNamespaces(CancellationToken cancellationToken)\n    {\n        return Task.FromResult(new List<string>());\n    }\n\n    Task<IList<Node>> ListServices(string ns = null)\n    {\n        throw new NotImplementedException();\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/NodeDiscovery/IProcessingServer.Consul.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\n\nnamespace DotNetCore.CAP.Dashboard.NodeDiscovery;\n\ninternal class ConsulProcessingNodeServer : IProcessingServer\n{\n    private readonly INodeDiscoveryProvider _discoveryProvider;\n\n    public ConsulProcessingNodeServer(INodeDiscoveryProvider discoveryProvider)\n    {\n        _discoveryProvider = discoveryProvider;\n    }\n\n    public async ValueTask StartAsync(CancellationToken stoppingToken)\n    {\n        await _discoveryProvider.RegisterNode(stoppingToken);\n    }\n\n    public void Dispose()\n    {\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/NodeDiscovery/Node.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nnamespace DotNetCore.CAP.Dashboard.NodeDiscovery;\n\npublic class Node\n{\n    public string Id { get; set; }\n\n    public string Name { get; set; }\n\n    public string Address { get; set; }\n\n    public int Port { get; set; }\n\n    public string Tags { get; set; }\n\n    public string Latency { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/RouteActionProvider.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Net;\nusing System.Net.Http;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Dashboard.GatewayProxy;\nusing DotNetCore.CAP.Dashboard.NodeDiscovery;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Monitoring;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Routing;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Primitives;\n\n// ReSharper disable UnusedMember.Global\n\nnamespace DotNetCore.CAP.Dashboard;\n\npublic class RouteActionProvider\n{\n    private readonly GatewayProxyAgent _agent;\n    private readonly IEndpointRouteBuilder _builder;\n    private readonly DashboardOptions _options;\n    private readonly IServiceProvider _serviceProvider;\n\n    public RouteActionProvider(IEndpointRouteBuilder builder, DashboardOptions options)\n    {\n        _builder = builder;\n        _options = options;\n        _serviceProvider = builder.ServiceProvider;\n        _agent = _serviceProvider.GetService<GatewayProxyAgent>(); // may be null\n    }\n\n    private IDataStorage DataStorage => _serviceProvider.GetRequiredService<IDataStorage>();\n    private IMonitoringApi MonitoringApi => DataStorage.GetMonitoringApi();\n\n    public void MapDashboardRoutes()\n    {\n        var prefixMatch = _options.PathMatch + \"/api\";\n\n        _builder.MapGet(prefixMatch + \"/metrics-realtime\", Metrics).AllowAnonymousIf(_options.AllowAnonymousExplicit, _options.AuthorizationPolicy);\n        _builder.MapGet(prefixMatch + \"/meta\", MetaInfo).AllowAnonymousIf(_options.AllowAnonymousExplicit, _options.AuthorizationPolicy);\n        _builder.MapGet(prefixMatch + \"/stats\", Stats).AllowAnonymousIf(_options.AllowAnonymousExplicit, _options.AuthorizationPolicy);\n        _builder.MapGet(prefixMatch + \"/metrics-history\", MetricsHistory).AllowAnonymousIf(_options.AllowAnonymousExplicit, _options.AuthorizationPolicy);\n        _builder.MapGet(prefixMatch + \"/health\", Health).AllowAnonymous();\n        _builder.MapGet(prefixMatch + \"/published/message/{id:long}\", PublishedMessageDetails).AllowAnonymousIf(_options.AllowAnonymousExplicit, _options.AuthorizationPolicy);\n        _builder.MapGet(prefixMatch + \"/received/message/{id:long}\", ReceivedMessageDetails).AllowAnonymousIf(_options.AllowAnonymousExplicit, _options.AuthorizationPolicy);\n        _builder.MapPost(prefixMatch + \"/published/requeue\", PublishedRequeue).AllowAnonymousIf(_options.AllowAnonymousExplicit, _options.AuthorizationPolicy);\n        _builder.MapPost(prefixMatch + \"/published/delete\", PublishedDelete).AllowAnonymousIf(_options.AllowAnonymousExplicit, _options.AuthorizationPolicy);\n        _builder.MapPost(prefixMatch + \"/received/reexecute\", ReceivedRequeue).AllowAnonymousIf(_options.AllowAnonymousExplicit, _options.AuthorizationPolicy);\n        _builder.MapPost(prefixMatch + \"/received/delete\", ReceivedDelete).AllowAnonymousIf(_options.AllowAnonymousExplicit, _options.AuthorizationPolicy);\n        _builder.MapGet(prefixMatch + \"/published/{status}\", PublishedList).AllowAnonymousIf(_options.AllowAnonymousExplicit, _options.AuthorizationPolicy);\n        _builder.MapGet(prefixMatch + \"/received/{status}\", ReceivedList).AllowAnonymousIf(_options.AllowAnonymousExplicit, _options.AuthorizationPolicy);\n        _builder.MapGet(prefixMatch + \"/subscriber\", Subscribers).AllowAnonymousIf(_options.AllowAnonymousExplicit, _options.AuthorizationPolicy);\n        _builder.MapGet(prefixMatch + \"/nodes\", Nodes).AllowAnonymousIf(_options.AllowAnonymousExplicit, _options.AuthorizationPolicy);\n        _builder.MapGet(prefixMatch + \"/list-ns\", ListNamespaces).AllowAnonymousIf(_options.AllowAnonymousExplicit, _options.AuthorizationPolicy);\n        _builder.MapGet(prefixMatch + \"/list-svc/{namespace}\", ListServices).AllowAnonymousIf(_options.AllowAnonymousExplicit, _options.AuthorizationPolicy);\n        _builder.MapGet(prefixMatch + \"/ping\", PingServices).AllowAnonymous();\n    }\n\n    public async Task Metrics(HttpContext httpContext)\n    {\n        if (_agent != null && await _agent.Invoke(httpContext)) return;\n\n        var metrics = _serviceProvider.GetRequiredService<CapMetricsEventListener>();\n        await httpContext.Response.WriteAsJsonAsync(metrics.GetRealTimeMetrics());\n    }\n\n    public async Task MetaInfo(HttpContext httpContext)\n    {\n        if (_agent != null && await _agent.Invoke(httpContext)) return;\n\n        var cap = _serviceProvider.GetService<CapMarkerService>();\n        var broker = _serviceProvider.GetService<CapMessageQueueMakerService>();\n        var storage = _serviceProvider.GetService<CapStorageMarkerService>();\n\n        await httpContext.Response.WriteAsJsonAsync(new\n        {\n            cap,\n            broker,\n            storage\n        });\n    }\n\n    public async Task Stats(HttpContext httpContext)\n    {\n        if (_agent != null && await _agent.Invoke(httpContext)) return;\n\n        var result = await MonitoringApi.GetStatisticsAsync();\n        await SetServersCountAsync(result);\n        await httpContext.Response.WriteAsJsonAsync(result);\n\n        async Task SetServersCountAsync(StatisticsDto dto)\n        {\n            if (CapCache.Global.TryGet(\"cap.nodes.count\", out var count))\n            {\n                dto.Servers = (int)count;\n            }\n            else\n            {\n                if (_serviceProvider.GetService<ConsulDiscoveryOptions>() != null)\n                {\n                    var discoveryProvider = _serviceProvider.GetRequiredService<INodeDiscoveryProvider>();\n                    var nodes = await discoveryProvider.GetNodes();\n                    dto.Servers = nodes.Count;\n                }\n            }\n        }\n    }\n\n    public async Task MetricsHistory(HttpContext httpContext)\n    {\n        if (_agent != null && await _agent.Invoke(httpContext)) return;\n\n        const string cacheKey = \"dashboard.metrics.history\";\n        if (CapCache.Global.TryGet(cacheKey, out var ret))\n        {\n            await httpContext.Response.WriteAsJsonAsync(ret);\n            return;\n        }\n\n        var ps = await MonitoringApi.HourlySucceededJobs(MessageType.Publish);\n        var pf = await MonitoringApi.HourlyFailedJobs(MessageType.Publish);\n        var ss = await MonitoringApi.HourlySucceededJobs(MessageType.Subscribe);\n        var sf = await MonitoringApi.HourlyFailedJobs(MessageType.Subscribe);\n\n        var dayHour = ps.Keys.OrderBy(x => x).Select(x => new DateTimeOffset(x).ToUnixTimeSeconds());\n\n        var result = new\n        {\n            DayHour = dayHour.ToArray(),\n            PublishSuccessed = ps.Values.Reverse(),\n            PublishFailed = pf.Values.Reverse(),\n            SubscribeSuccessed = ss.Values.Reverse(),\n            SubscribeFailed = sf.Values.Reverse()\n        };\n\n        CapCache.Global.AddOrUpdate(cacheKey, result, TimeSpan.FromMinutes(10));\n\n        await httpContext.Response.WriteAsJsonAsync(result);\n    }\n\n    public Task Health(HttpContext httpContext)\n    {\n        httpContext.Response.WriteAsync(\"OK\");\n        return Task.CompletedTask;\n    }\n\n    public async Task PublishedMessageDetails(HttpContext httpContext)\n    {\n        if (_agent != null && await _agent.Invoke(httpContext)) return;\n\n        if (long.TryParse(httpContext.GetRouteData().Values[\"id\"]?.ToString() ?? string.Empty, out var id))\n        {\n            var message = await MonitoringApi.GetPublishedMessageAsync(id);\n            if (message == null)\n            {\n                httpContext.Response.StatusCode = StatusCodes.Status404NotFound;\n                return;\n            }\n\n            await httpContext.Response.WriteAsJsonAsync(message.Content);\n        }\n        else\n        {\n            BadRequest(httpContext);\n        }\n    }\n\n    public async Task ReceivedMessageDetails(HttpContext httpContext)\n    {\n        if (_agent != null && await _agent.Invoke(httpContext)) return;\n\n        if (long.TryParse(httpContext.GetRouteData().Values[\"id\"]?.ToString() ?? string.Empty, out var id))\n        {\n            var message = await MonitoringApi.GetReceivedMessageAsync(id);\n            if (message == null)\n            {\n                httpContext.Response.StatusCode = StatusCodes.Status404NotFound;\n                return;\n            }\n\n            await httpContext.Response.WriteAsJsonAsync(message.Content);\n        }\n        else\n        {\n            BadRequest(httpContext);\n        }\n    }\n\n    public async Task PublishedRequeue(HttpContext httpContext)\n    {\n        if (_agent != null && await _agent.Invoke(httpContext)) return;\n\n        var messageIds = await httpContext.Request.ReadFromJsonAsync<long[]>();\n        if (messageIds == null || messageIds.Length == 0)\n        {\n            httpContext.Response.StatusCode = StatusCodes.Status422UnprocessableEntity;\n            return;\n        }\n\n        foreach (var messageId in messageIds)\n        {\n            var message = await MonitoringApi.GetPublishedMessageAsync(messageId);\n            if (message != null)\n                await _serviceProvider.GetRequiredService<IDispatcher>().EnqueueToPublish(message);\n        }\n\n        httpContext.Response.StatusCode = StatusCodes.Status204NoContent;\n    }\n\n    public async Task PublishedDelete(HttpContext httpContext)\n    {\n        if (_agent != null && await _agent.Invoke(httpContext)) return;\n\n        var messageIds = await httpContext.Request.ReadFromJsonAsync<long[]>();\n        if (messageIds == null || messageIds.Length == 0)\n        {\n            httpContext.Response.StatusCode = StatusCodes.Status422UnprocessableEntity;\n            return;\n        }\n\n        foreach (var messageId in messageIds)\n            _ = await DataStorage.DeletePublishedMessageAsync(messageId);\n\n        httpContext.Response.StatusCode = StatusCodes.Status204NoContent;\n    }\n\n    public async Task ReceivedRequeue(HttpContext httpContext)\n    {\n        if (_agent != null && await _agent.Invoke(httpContext)) return;\n\n        var messageIds = await httpContext.Request.ReadFromJsonAsync<long[]>();\n        if (messageIds == null || messageIds.Length == 0)\n        {\n            httpContext.Response.StatusCode = StatusCodes.Status422UnprocessableEntity;\n            return;\n        }\n\n        foreach (var messageId in messageIds)\n        {\n            var message = await MonitoringApi.GetReceivedMessageAsync(messageId);\n            if (message != null)\n                await _serviceProvider.GetRequiredService<IDispatcher>().EnqueueToExecute(message);\n        }\n\n        httpContext.Response.StatusCode = StatusCodes.Status204NoContent;\n    }\n\n    public async Task ReceivedDelete(HttpContext httpContext)\n    {\n        if (_agent != null && await _agent.Invoke(httpContext)) return;\n\n        var messageIds = await httpContext.Request.ReadFromJsonAsync<long[]>();\n        if (messageIds == null || messageIds.Length == 0)\n        {\n            httpContext.Response.StatusCode = StatusCodes.Status422UnprocessableEntity;\n            return;\n        }\n\n        foreach (var messageId in messageIds)\n            _ = await DataStorage.DeleteReceivedMessageAsync(messageId);\n\n        httpContext.Response.StatusCode = StatusCodes.Status204NoContent;\n    }\n\n\n    public async Task PublishedList(HttpContext httpContext)\n    {\n        if (_agent != null && await _agent.Invoke(httpContext)) return;\n\n        var routeValue = httpContext.GetRouteData().Values;\n        var pageSize = httpContext.Request.Query[\"perPage\"].ToInt32OrDefault(20);\n        var pageIndex = httpContext.Request.Query[\"currentPage\"].ToInt32OrDefault(1);\n        var name = httpContext.Request.Query[\"name\"].ToString();\n        var content = httpContext.Request.Query[\"content\"].ToString();\n        var status = routeValue[\"status\"]?.ToString() ?? nameof(StatusName.Succeeded);\n\n        var queryDto = new MessageQueryDto\n        {\n            MessageType = MessageType.Publish,\n            Name = name,\n            Content = content,\n            StatusName = status,\n            CurrentPage = pageIndex - 1,\n            PageSize = pageSize\n        };\n\n        var result = await MonitoringApi.GetMessagesAsync(queryDto);\n\n        await httpContext.Response.WriteAsJsonAsync(result);\n    }\n\n    public async Task ReceivedList(HttpContext httpContext)\n    {\n        if (_agent != null && await _agent.Invoke(httpContext)) return;\n\n        var routeValue = httpContext.GetRouteData().Values;\n        var pageSize = httpContext.Request.Query[\"perPage\"].ToInt32OrDefault(20);\n        var pageIndex = httpContext.Request.Query[\"currentPage\"].ToInt32OrDefault(1);\n        var name = httpContext.Request.Query[\"name\"].ToString();\n        var group = httpContext.Request.Query[\"group\"].ToString();\n        var content = httpContext.Request.Query[\"content\"].ToString();\n        var status = routeValue[\"status\"]?.ToString() ?? nameof(StatusName.Succeeded);\n\n        var queryDto = new MessageQueryDto\n        {\n            MessageType = MessageType.Subscribe,\n            Group = group,\n            Name = name,\n            Content = content,\n            StatusName = status,\n            CurrentPage = pageIndex - 1,\n            PageSize = pageSize\n        };\n\n        var result = await MonitoringApi.GetMessagesAsync(queryDto);\n\n        await httpContext.Response.WriteAsJsonAsync(result);\n    }\n\n    public async Task Subscribers(HttpContext httpContext)\n    {\n        if (_agent != null && await _agent.Invoke(httpContext)) return;\n\n        var cache = _serviceProvider.GetRequiredService<MethodMatcherCache>();\n        var subscribers = cache.GetCandidatesMethodsOfGroupNameGrouped();\n\n        var result = new List<WarpResult>();\n\n        foreach (var subscriber in subscribers)\n        {\n            var inner = new WarpResult\n            {\n                Group = subscriber.Key,\n                Values = new List<WarpResult.SubInfo>()\n            };\n            foreach (var descriptor in subscriber.Value)\n            {\n                inner.Values.Add(new WarpResult.SubInfo\n                {\n                    Topic = descriptor.TopicName,\n                    ImplName = descriptor.ImplTypeInfo.Name,\n                    MethodEscaped = HtmlHelper.MethodEscaped(descriptor.MethodInfo)\n                });\n            }\n\n            result.Add(inner);\n        }\n\n        await httpContext.Response.WriteAsJsonAsync(result);\n    }\n\n    public async Task Nodes(HttpContext httpContext)\n    {\n        IList<Node> result = new List<Node>();\n        var discoveryProvider = _serviceProvider.GetService<INodeDiscoveryProvider>();\n        if (discoveryProvider == null)\n        {\n            await httpContext.Response.WriteAsJsonAsync(result);\n            return;\n        }\n\n        result = await discoveryProvider.GetNodes();\n\n        await httpContext.Response.WriteAsJsonAsync(result);\n    }\n\n    public async Task ListNamespaces(HttpContext httpContext)\n    {\n        var discoveryProvider = _serviceProvider.GetService<INodeDiscoveryProvider>();\n        if (discoveryProvider == null)\n        {\n            await httpContext.Response.WriteAsJsonAsync(new List<string>());\n            return;\n        }\n\n        var nsList = await discoveryProvider.GetNamespaces(httpContext.RequestAborted);\n        if (nsList == null)\n            httpContext.Response.StatusCode = 404;\n        else\n            await httpContext.Response.WriteAsJsonAsync(\n                await discoveryProvider.GetNamespaces(httpContext.RequestAborted));\n    }\n\n    public async Task ListServices(HttpContext httpContext)\n    {\n        var @namespace = string.Empty;\n\n        if (httpContext.Request.RouteValues.TryGetValue(\"namespace\", out var val)) @namespace = val!.ToString();\n\n        var discoveryProvider = _serviceProvider.GetService<INodeDiscoveryProvider>();\n        if (discoveryProvider == null)\n        {\n            await httpContext.Response.WriteAsJsonAsync(new List<Node>());\n            return;\n        }\n\n        var result = await discoveryProvider.ListServices(@namespace);\n\n\n        await httpContext.Response.WriteAsJsonAsync(result);\n    }\n\n    public async Task PingServices(HttpContext httpContext)\n    {\n        var endpoint = httpContext.Request.Query[\"endpoint\"];\n\n        var httpClient = new HttpClient();\n        var sw = new Stopwatch();\n        try\n        {\n            sw.Restart();\n            var healthEndpoint = endpoint + _options.PathMatch + \"/api/health\";\n            var response = await httpClient.GetStringAsync(healthEndpoint);\n            sw.Stop();\n\n            if (response == \"OK\")\n            {\n                await httpContext.Response.WriteAsync(sw.ElapsedMilliseconds.ToString());\n            }\n            else\n            {\n                httpContext.Response.StatusCode = 501;\n                await httpContext.Response.WriteAsync(response);\n            }\n        }\n        catch (HttpRequestException e)\n        {\n            httpContext.Response.StatusCode = (int)e.StatusCode.GetValueOrDefault(HttpStatusCode.BadGateway);\n            await httpContext.Response.WriteAsync(e.Message);\n        }\n        catch (Exception e)\n        {\n            httpContext.Response.StatusCode = (int)HttpStatusCode.BadGateway;\n            await httpContext.Response.WriteAsync(e.Message);\n        }\n    }\n\n    private void BadRequest(HttpContext httpContext)\n    {\n        httpContext.Response.StatusCode = StatusCodes.Status400BadRequest;\n    }\n}\n\npublic class WarpResult\n{\n    public int ChildCount => Values.Count;\n\n    public string Group { get; set; }\n\n    public List<SubInfo> Values { get; set; }\n\n    public class SubInfo\n    {\n        public string Topic { get; set; }\n\n        public string ImplName { get; set; }\n\n        public string MethodEscaped { get; set; }\n    }\n}\n\npublic static class IntExtension\n{\n    public static int ToInt32OrDefault(this StringValues value, int defaultValue = 0)\n    {\n        return int.TryParse(value, out var result) ? result : defaultValue;\n    }\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/.gitignore",
    "content": ".DS_Store\nnode_modules\n\n# local env files\n.env.local\n.env.*.local\n\n# Log files\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\n\n# Editor directories and files\n.idea\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/.vscode/settings.json",
    "content": "{\n    \"vetur.format.defaultFormatter.html\": \"js-beautify-html\",\n    \"vetur.format.defaultFormatter.js\": \"vscode-typescript\",\n    \"vetur.format.defaultFormatterOptions\": {\n        \"js-beautify-html\": {\n            \"wrap_attributes\": \"auto\"\n        },\n        \"prettyhtml\": {\n            \"printWidth\": 100,\n            \"singleQuote\": false,\n            \"wrapAttributes\": false,\n            \"sortAttributes\": false\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/README.md",
    "content": "# Dashboard\n\nThe dashboard project uses vue 2 to build with vite, and the UI uses bootstrap 4.\n\n## Local Development\n\n### Install dependent packages\n\n> cd src\\DotNetCore.CAP.Dashboard\\wwwroot\n\n```sh\nnpm install\n```\n\n### Update backend api\n\nUpdate the `target` in `vite.config.js` of development to specify the backend service api.\n\n```\n  server: {\n    proxy: {\n      '^/cap/api': {\n        target: 'http://localhost:5000',  //backend\n        changeOrigin: true\n      }\n    }\n  }\n```\n\n### Run\n\nThe backend api needs to allow cross-domain access.\n\n```\nnpm run dev\n```\n\n## Publish\n\nThe release will be generated into the `dist` folder, and the contents of this folder will be embedded in the dashboard csproj assembly.\n\n```\nnpm run build\n```\n\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/dist/assets/Nodes.40464ac3.css",
    "content": ".table-dark td{border-color:#c6c8ca}.texts{width:70px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/dist/assets/Nodes.e12132f5.js",
    "content": "import{d as i,n as o,a as c,f as d,g as u,c as f}from\"./index.909977fe.js\";var l=i.CancelToken.source();const p={components:{BIconInfoCircleFill:c,BIconSpeedometer2:d,BIconArrowClockwise:u,BIconSearch:f},data(){return{pinging:!1,selected:null,nsList:[],isBusy:!1,items:[]}},computed:{fields(){return[{key:\"id\",label:this.$t(\"Id\")},{key:\"name\",label:this.$t(\"Node Name\"),tdClass:\"text-left\"},{key:\"address\",label:this.$t(\"Ip Address\"),tdClass:\"text-left\"},{key:\"tags\",label:this.$t(\"Tags\"),tdClass:\"text-left\"},{key:\"latency\",label:this.$t(\"Latency\"),thClass:\"text-center\",tdClass:\"text-success\"},{key:\"actions\",label:this.$t(\"Actions\"),thClass:\"text-center\"}]}},mounted(){this.fetchNsOptions(),this.fetchData()},methods:{colWidth(n){switch(n){case\"address\":return\"320px\";case\"actions\":return\"80px\";case\"latency\":return\"60px\";default:return\"\"}},fetchNsOptions(){this.isBusy=!0,i.get(\"/list-ns\").then(e=>{e.data.length>0&&(this.nsList=e.data)}),this.isBusy=!1;var n=this.getCookie(\"cap.node.ns\");n&&(this.selected=n,this.fetchSvcs())},fetchSvcs(){if(!!this.selected){this.isBusy=!0;var n=this.getCookie(\"cap.node\");this.pinging==!0&&(l.cancel(),l=i.CancelToken.source()),i.get(\"/list-svc/\"+this.selected).then(e=>{for(var t of e.data)t.name==n&&(t._rowVariant=\"dark\"),t._ping=!1;this.items=e.data,this.isBusy=!1})}},async pingSvcs(){var t;this.pinging=!0;for(var n of this.items)try{var e=await i.get(\"/ping\",{params:{endpoint:n.address+\":\"+n.port},timeout:3e3,cancelToken:l.token});n.latency=e.data}catch(s){if(i.isCancel(s))break;n.latency=(t=s.response)==null?void 0:t.data}this.pinging=!1},fetchData(){this.isBusy=!0;var n=this.getCookie(\"cap.node\");i.get(\"/nodes\").then(e=>{for(var t of e.data)t.name==n&&(t._rowVariant=\"dark\");this.items=e.data,this.isBusy=!1})},switchNode(n){n._ping=!0,i.get(\"/ping\",{params:{endpoint:n.address+\":\"+n.port},timeout:3e3}).then(e=>{n.latency=e.data,document.cookie=`cap.node=${escape(n.name)};`,document.cookie=`cap.node.ns=${this.selected};`,n._ping=!1,location.reload()}).catch(e=>{var t;i.isAxiosError(e)&&(n.latency=(t=e.response)==null?void 0:t.data,this.$bvToast.toast(\"Switch to [\"+n.name+\"] failed! Endpoint: \"+n.address,{title:\"Warning\",variant:\"danger\",autoHideDelay:2e3,appendToast:!0,solid:!0})),n._ping=!1})},getCookie(n){for(var e=n+\"=\",t=decodeURIComponent(document.cookie),s=t.split(\";\"),a=0;a<s.length;a++){for(var r=s[a];r.charAt(0)==\" \";)r=r.substring(1);if(r.indexOf(e)==0)return r.substring(e.length,r.length)}return\"\"}}};var h=function(){var e=this,t=e._self._c;return t(\"div\",[t(\"h2\",{staticClass:\"text-left mb-4\"},[e._v(e._s(e.$t(\"Nodes\")))]),e.nsList.length>0?t(\"b-row\",{staticClass:\"mb-3\"},[t(\"b-col\",[t(\"b-form-select\",{attrs:{\"value-field\":\"item\",\"text-field\":\"name\",options:e.nsList},on:{change:function(s){return e.fetchSvcs()}},scopedSlots:e._u([{key:\"first\",fn:function(){return[t(\"b-form-select-option\",{attrs:{value:null,disabled:\"\"}},[e._v(e._s(e.$t(\"SelectNamespaces\")))])]},proxy:!0}],null,!1,213963292),model:{value:e.selected,callback:function(s){e.selected=s},expression:\"selected\"}})],1),t(\"b-col\",{attrs:{cols:\"1\"}},[t(\"b-button\",{attrs:{variant:\"dark\",disabled:e.selected==null||e.pinging,\"aria-disabled\":\"true\",id:\"latency\"},on:{click:function(s){return e.pingSvcs()}}},[e.pinging?e._e():t(\"b-icon-speedometer2\"),e.pinging?t(\"b-icon-arrow-clockwise\",{attrs:{animation:\"spin\"}}):e._e()],1)],1)],1):e._e(),t(\"b-table\",{attrs:{fields:e.fields,items:e.items,busy:e.isBusy,small:\"\",\"head-variant\":\"light\",\"show-empty\":\"\",striped:\"\",hover:\"\",responsive:\"\",\"thead-tr-class\":\"text-left\",\"empty-text\":e.nsList.length==0?e.$t(\"NonDiscovery\"):e.$t(\"EmptyRecords\")},scopedSlots:e._u([{key:\"table-colgroup\",fn:function(s){return e._l(s.fields,function(a){return t(\"col\",{key:a.key,style:{width:e.colWidth(a.key)}})})}},{key:\"table-busy\",fn:function(){return[t(\"div\",{staticClass:\"text-center text-secondary my-2\"},[t(\"b-spinner\",{staticClass:\"align-middle\"}),t(\"strong\",{staticClass:\"ml-2\"},[e._v(e._s(e.$t(\"Loading\"))+\"...\")])],1)]},proxy:!0},{key:\"empty\",fn:function(s){return[t(\"h5\",{staticClass:\"alert alert-info\",attrs:{role:\"alert\"}},[t(\"b-icon-info-circle-fill\"),e._v(\" \"+e._s(s.emptyText)+\" \")],1)]}},{key:\"cell(id)\",fn:function(s){return[t(\"div\",{staticClass:\"texts\"},[e._v(\" \"+e._s(s.item.id)+\" \")])]}},{key:\"cell(address)\",fn:function(s){return[e._v(\" \"+e._s(s.item.address+(s.item.port==80?\"\":\":\"+s.item.port))+\" \")]}},{key:\"cell(tags)\",fn:function(s){return[t(\"b-badge\",{attrs:{variant:\"info\"}},[e._v(e._s(s.item.tags.split(\",\")[0]))]),s.item.tags!=\"\"?t(\"b-link\",{on:{click:s.toggleDetails}},[t(\"div\",{staticClass:\"ml-2\",staticStyle:{\"font-size\":\"12px\",color:\"gray\"}},[e._v(\"Show \"+e._s(s.detailsShowing?\"Less\":\"More\")+\" \")])]):e._e()]}},{key:\"row-details\",fn:function(s){return e._l(s.item.tags.split(\",\"),function(a){return t(\"b-badge\",{key:a,staticClass:\"mb-1 ml-2\"},[e._v(e._s(a))])})}},{key:\"cell(latency)\",fn:function(s){return[s.item.latency==null?t(\"div\"):typeof s.item.latency==\"number\"?t(\"b-badge\",{attrs:{variant:\"success\"}},[e._v(\" \"+e._s(s.item.latency+\" ms\")+\" \")]):t(\"b-badge\",{directives:[{name:\"b-popover\",rawName:\"v-b-popover.hover.left\",value:s.item.latency,expression:\"data.item.latency\",modifiers:{hover:!0,left:!0}}],attrs:{pill:\"\",href:\"#\",variant:\"danger\",size:\"sm\",title:\"Request failed\"}},[e._v(\" Error \")])]}},{key:\"cell(actions)\",fn:function(s){return[t(\"b-button\",{attrs:{size:\"sm\",variant:\"dark\"},on:{click:function(a){return e.switchNode(s.item)}}},[s.item._ping?t(\"b-spinner\",{attrs:{small:\"\",variant:\"secondary\",type:\"grow\",label:\"Spinning\"}}):e._e(),e._v(\" \"+e._s(e.$t(\"Switch\"))+\" \")],1)]}}])})],1)},v=[],g=o(p,h,v,!1,null,null,null,null);const m=g.exports;export{m as default};\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/dist/assets/Published.429cfade.css",
    "content": ".pagination[data-v-15713fa2]{flex:1;justify-content:flex-end;align-items:center}.capPagination[data-v-15713fa2] .page-link{color:#6c757d;box-shadow:none;border-color:#6c757d}.capPagination[data-v-15713fa2] .page-link:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.capPagination[data-v-15713fa2] .active .page-link{color:#fff;background-color:#000}.my-align-middle[data-v-15713fa2]{vertical-align:middle}.action-button[data-v-15713fa2]{margin-right:1rem}\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/dist/assets/Published.a8d638e6.js",
    "content": "import{n,B as o,a as r,b as c,c as d,d as l}from\"./index.909977fe.js\";import{j as u}from\"./index.2d8714a6.js\";const m={currentPage:1,perPage:10,name:\"\",content:\"\"},h={components:{BIconTrash:o,BIconInfoCircleFill:r,BIconArrowRepeat:c,BIconSearch:d},props:{status:{}},data(){return{subMens:[{variant:\"secondary\",text:\"Succeeded\",num:\"publishedSucceeded\",name:\"/published/succeeded\"},{variant:\"danger\",text:\"Failed\",name:\"/published/failed\",num:\"publishedFailed\"},{variant:\"warning\",text:\"Delayed\",name:\"/published/delayed\",num:\"publishedDelayed\"}],pageOptions:[10,20,50,100,500],selectedItems:[],isBusy:!1,tableValues:[],isSelectedAll:!1,formData:{...m},totals:0,items:[],infoModal:{id:\"info-modal\",title:\"\",content:\"{}\"},expiresTitle:this.$t(\"Expires\"),requeueTitle:this.$t(\"Requeue\")}},computed:{onMetric(){return this.$store.getters.getMetric},fields(){return[{key:\"checkbox\",label:\"\"},{key:\"id\",label:this.$t(\"IdName\")},{key:\"retries\",label:this.$t(\"Retries\")},{key:\"added\",label:this.$t(\"Added\"),formatter:s=>{if(s!=null)return new Date(s).format(\"yyyy-MM-dd hh:mm:ss\")}},{key:\"expiresAt\",label:this.expiresTitle,formatter:s=>{if(s!=null)return new Date(s).format(\"yyyy-MM-dd hh:mm:ss\")}}]}},mounted(){this.fetchData(),window.abc=this},watch:{status:function(){this.fetchData()},\"formData.currentPage\":function(){this.fetchData()}},methods:{fetchData(){this.isBusy=!0,l.get(`/published/${this.status}`,{params:this.formData}).then(s=>{this.items=s.data.items,this.totals=s.data.totals,this.status==\"delayed\"?(this.expiresTitle=this.$t(\"DelayedPublishTime\"),this.requeueTitle=this.$t(\"PublishNow\")):(this.expiresTitle=this.$t(\"Expires\"),this.requeueTitle=this.$t(\"Requeue\"))}).finally(()=>{this.isBusy=!1})},selectAll(s){s?(this.selectedItems=[...this.items.map(t=>({...t,selected:!0}))],this.items=[...this.selectedItems]):(this.selectedItems=[],this.items=this.items.map(t=>({...t,selected:!1})))},select(s){const{id:t}=s;this.selectedItems.some(e=>e.id==t)?this.selectedItems=this.selectedItems.filter(e=>e.id!=t):this.selectedItems.push(s),this.isSelectedAll=this.selectedItems.length==this.items.length},clearSelected(){this.allSelected=!1,this.selectedItems=[]},info(s,t){this.infoModal.title=s.id.toString(),this.infoModal.content=u.exports({storeAsString:!0}).parse(s.content.trim()),this.$root.$emit(\"bv::show::modal\",this.infoModal.id,t)},pageSizeChange:function(s){this.formData.perPage=s,this.fetchData()},onSearch:function(){this.fetchData()},requeue:function(){const s=this;l.post(\"/published/requeue\",this.selectedItems.map(t=>t.id)).then(()=>{this.selectedItems.map(t=>{s.$bvToast.toast(this.$t(\"RequeueSuccess\")+\"   \"+t.id,{title:\"Tips\",variant:\"secondary\",autoHideDelay:1e3,appendToast:!0,solid:!0})}),s.clear()})},deletemsg:function(){const s=this;l.post(\"/published/delete\",this.selectedItems.map(t=>t.id)).then(()=>{this.selectedItems.map(t=>{s.$bvToast.toast(this.$t(\"DeleteSuccess\")+\"   \"+t.id,{title:\"Tips\",variant:\"secondary\",autoHideDelay:1e3,appendToast:!0,solid:!0})}),s.fetchData(),s.clear()})},clear(){this.items=this.items.map(s=>({...s,selected:!1})),this.selectedItems=[],this.isSelectedAll=!1}}};var f=function(){var t=this,e=t._self._c;return e(\"div\",[e(\"b-row\",[e(\"b-col\",{attrs:{md:\"3\"}},[e(\"b-list-group\",[e(\"b-tooltip\",{attrs:{target:\"tooltip\",triggers:\"hover\",variant:\"warning\",\"custom-class\":\"my-tooltip-class\",placement:\"bottomright\"}},[t._v(\" \"+t._s(t.$t(\"DelayedInfo\"))+\" \")]),t._l(t.subMens,function(a,i){return e(\"router-link\",{key:a.text,staticClass:\"list-group-item text-left list-group-item-secondary list-group-item-action\",attrs:{\"active-class\":\"active\",to:a.name}},[t._v(\" \"+t._s(t.$t(a.text))+\" \"),i==t.subMens.length-1?e(\"b-icon-info-circle-fill\",{attrs:{id:\"tooltip\"}}):t._e(),e(\"b-badge\",{staticClass:\"float-right\",attrs:{variant:a.variant,pill:\"\"}},[t._v(\" \"+t._s(t.onMetric[a.num])+\" \")])],1)})],2)],1),e(\"b-col\",{attrs:{md:\"9\"}},[e(\"h2\",{staticClass:\"page-line mb-2\"},[t._v(t._s(t.$t(\"Published Message\")))]),e(\"b-form\",{staticClass:\"d-flex\"},[e(\"div\",{staticClass:\"col-sm-10\"},[e(\"div\",{staticClass:\"form-row mb-2\"},[e(\"label\",{staticClass:\"sr-only\",attrs:{for:\"form-input-name\"}},[t._v(t._s(t.$t(\"Name\")))]),e(\"b-form-input\",{staticClass:\"form-control\",attrs:{id:\"form-input-name\",placeholder:t.$t(\"Name\")},model:{value:t.formData.name,callback:function(a){t.$set(t.formData,\"name\",a)},expression:\"formData.name\"}})],1),e(\"div\",{staticClass:\"form-row\"},[e(\"label\",{staticClass:\"sr-only\",attrs:{for:\"inline-form-input-content\"}},[t._v(t._s(t.$t(\"Content\")))]),e(\"b-form-input\",{staticClass:\"form-control\",attrs:{id:\"inline-form-input-content\",placeholder:t.$t(\"Content\")},model:{value:t.formData.content,callback:function(a){t.$set(t.formData,\"content\",a)},expression:\"formData.content\"}})],1)]),e(\"b-button\",{staticClass:\"ml-2 align-self-end\",attrs:{variant:\"dark\"},on:{click:t.onSearch}},[e(\"b-icon-search\"),t._v(\" \"+t._s(t.$t(\"Search\"))+\" \")],1)],1)],1)],1),e(\"b-row\",[e(\"b-col\",{attrs:{md:\"12\"}},[e(\"b-btn-toolbar\",{staticClass:\"mt-4\"},[e(\"b-button\",{staticClass:\"action-button\",attrs:{size:\"sm\",variant:\"dark\",disabled:!t.selectedItems.length},on:{click:t.requeue}},[e(\"b-icon-arrow-repeat\",{attrs:{\"aria-hidden\":\"true\"}}),t._v(\" \"+t._s(t.requeueTitle)+\" \")],1),e(\"b-button\",{staticClass:\"action-button\",attrs:{size:\"sm\",variant:\"danger\",disabled:!t.selectedItems.length},on:{click:t.deletemsg}},[e(\"b-icon-trash\",{attrs:{\"aria-hidden\":\"true\"}}),t._v(\" \"+t._s(t.$t(\"Delete\"))+\" \")],1),e(\"div\",{staticClass:\"pagination\"},[e(\"span\",{staticStyle:{\"font-size\":\"14px\"}},[t._v(t._s(t.$t(\"Page Size\"))+\":\")]),e(\"b-button-group\",{staticClass:\"ml-2\"},t._l(t.pageOptions,function(a){return e(\"b-button\",{key:a,class:{active:t.formData.perPage==a},attrs:{variant:\"outline-secondary\",size:\"sm\"},on:{click:function(i){return t.pageSizeChange(a)}}},[t._v(t._s(a)+\" \")])}),1)],1)],1),e(\"b-table\",{staticClass:\"mt-3\",attrs:{id:\"datatable\",busy:t.isBusy,striped:\"\",\"thead-tr-class\":\"text-left \",\"head-variant\":\"light\",\"details-td-class\":\"align-middle\",\"tbody-tr-class\":\"text-left\",small:\"\",fields:t.fields,items:t.items,\"select-mode\":\"range\"},scopedSlots:t._u([{key:\"table-busy\",fn:function(){return[e(\"div\",{staticClass:\"text-center text-secondary my-2\"},[e(\"b-spinner\",{staticClass:\"align-middle\"}),e(\"strong\",{staticClass:\"ml-2\"},[t._v(t._s(t.$t(\"Loading\"))+\"...\")])],1)]},proxy:!0},{key:\"head(checkbox)\",fn:function(){return[e(\"b-form-checkbox\",{on:{change:t.selectAll},model:{value:t.isSelectedAll,callback:function(a){t.isSelectedAll=a},expression:\"isSelectedAll\"}})]},proxy:!0},{key:\"cell(checkbox)\",fn:function(a){return[e(\"b-form-checkbox\",{on:{change:function(i){return t.select(a.item)}},model:{value:a.item.selected,callback:function(i){t.$set(a.item,\"selected\",i)},expression:\"data.item.selected\"}})]}},{key:\"cell(id)\",fn:function(a){return[e(\"b-link\",{on:{click:function(i){return t.info(a.item,i.target)}}},[t._v(\" \"+t._s(a.item.id)+\" \")]),e(\"br\"),t._v(\" \"+t._s(a.item.name)+\" \")]}}])}),e(\"span\",{staticClass:\"float-left\"},[t._v(\" \"+t._s(t.$t(\"Total\"))+\": \"+t._s(t.totals)+\" \")]),e(\"b-pagination\",{staticClass:\"capPagination\",attrs:{\"first-text\":t.$t(\"First\"),\"prev-text\":t.$t(\"Prev\"),\"next-text\":t.$t(\"Next\"),\"last-text\":t.$t(\"Last\"),\"total-rows\":t.totals,\"per-page\":t.formData.perPage,\"aria-controls\":\"datatable\"},model:{value:t.formData.currentPage,callback:function(a){t.$set(t.formData,\"currentPage\",a)},expression:\"formData.currentPage\"}})],1)],1),e(\"b-modal\",{attrs:{size:\"lg\",id:t.infoModal.id,title:\"Id: \"+t.infoModal.title,\"ok-only\":\"\",\"ok-variant\":\"secondary\"}},[e(\"vue-json-pretty\",{key:t.infoModal.id,attrs:{showSelectController:\"\",data:t.infoModal.content}})],1)],1)},p=[],b=n(h,f,p,!1,null,\"15713fa2\",null,null);const v=b.exports;export{v as default};\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/dist/assets/Received.37160321.css",
    "content": ".pagination[data-v-33811592]{flex:1;justify-content:flex-end;align-items:center}.capPagination[data-v-33811592] .page-link{color:#6c757d;box-shadow:none;border-color:#6c757d}.capPagination[data-v-33811592] .page-link:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.capPagination[data-v-33811592] .active .page-link{color:#fff;background-color:#000}.action-button[data-v-33811592]{margin-right:1rem}\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/dist/assets/Received.e36ea621.js",
    "content": "import{n as l,b as r,c as o,B as c,d as n}from\"./index.909977fe.js\";import{j as d}from\"./index.2d8714a6.js\";const m={currentPage:1,perPage:10,name:\"\",group:\"\",content:\"\"},u={components:{BIconArrowRepeat:r,BIconSearch:o,BIconTrash:c},props:{status:{}},data(){return{subMens:[{variant:\"secondary\",text:\"Succeeded\",num:\"receivedSucceeded\",name:\"/received/succeeded\"},{variant:\"danger\",text:\"Failed\",name:\"/received/failed\",num:\"receivedFailed\"}],pageOptions:[10,20,50,100,500],selectedItems:[],isBusy:!1,tableValues:[],isSelectedAll:!1,formData:{...m},totals:0,items:[],infoModal:{id:\"info-modal\",title:\"\",content:\"{}\"}}},computed:{onMetric(){return this.$store.getters.getMetric},fields(){return[{key:\"checkbox\",label:\"\"},{key:\"id\",label:this.$t(\"IdName\")},{key:\"group\",label:this.$t(\"Group\")},{key:\"retries\",label:this.$t(\"Retries\")},{key:\"added\",label:this.$t(\"Added\"),formatter:a=>{if(a!=null)return new Date(a).format(\"yyyy-MM-dd hh:mm:ss\")}},{key:\"expiresAt\",label:this.$t(\"Expires\"),formatter:a=>{if(a!=null)return new Date(a).format(\"yyyy-MM-dd hh:mm:ss\")}}]}},mounted(){this.fetchData()},watch:{status:function(){this.fetchData()},\"formData.currentPage\":function(){this.fetchData()}},methods:{fetchData(){this.isBusy=!0,n.get(`/received/${this.status}`,{params:this.formData}).then(a=>{this.items=a.data.items,this.totals=a.data.totals}).finally(()=>{this.isBusy=!1})},selectAll(a){a?(this.selectedItems=[...this.items.map(t=>({...t,selected:!0}))],this.items=[...this.selectedItems]):(this.selectedItems=[],this.items=this.items.map(t=>({...t,selected:!1})))},select(a){const{id:t}=a;this.selectedItems.some(e=>e.id==t)?this.selectedItems=this.selectedItems.filter(e=>e.id!=t):this.selectedItems.push(a),this.isSelectedAll=this.selectedItems.length==this.items.length},clearSelected(){this.allSelected=!1,this.selectedItems=[]},info(a,t){this.infoModal.title=a.id.toString(),this.infoModal.content=d.exports({storeAsString:!0}).parse(a.content.trim()),this.$root.$emit(\"bv::show::modal\",this.infoModal.id,t)},pageSizeChange:function(a){this.formData.perPage=a,this.fetchData()},onSearch:function(){this.fetchData()},reexecute:function(){const a=this;n.post(\"/received/reexecute\",this.selectedItems.map(t=>t.id)).then(()=>{this.selectedItems.map(t=>{a.$bvToast.toast(this.$t(\"ReexecuteSuccess\")+\"   \"+t.id,{title:\"Tips\",variant:\"secondary\",autoHideDelay:1e3,appendToast:!0,solid:!0})}),a.fetchData(),a.clear()})},deletemsg:function(){const a=this;n.post(\"/received/delete\",this.selectedItems.map(t=>t.id)).then(()=>{this.selectedItems.map(t=>{a.$bvToast.toast(this.$t(\"DeleteSuccess\")+\"   \"+t.id,{title:\"Tips\",variant:\"secondary\",autoHideDelay:1e3,appendToast:!0,solid:!0})}),a.fetchData(),a.clear()})},clear(){this.items=this.items.map(a=>({...a,selected:!1})),this.selectedItems=[],this.isSelectedAll=!1}}};var f=function(){var t=this,e=t._self._c;return e(\"div\",[e(\"b-row\",[e(\"b-col\",{staticClass:\"mt-4\",attrs:{md:\"3\"}},[e(\"b-list-group\",t._l(t.subMens,function(s){return e(\"router-link\",{key:s.text,staticClass:\"list-group-item text-left list-group-item-secondary list-group-item-action\",attrs:{\"active-class\":\"active\",to:s.name}},[t._v(\" \"+t._s(t.$t(s.text))+\" \"),e(\"b-badge\",{staticClass:\"float-right\",attrs:{variant:s.variant,pill:\"\"}},[t._v(\" \"+t._s(t.onMetric[s.num])+\" \")])],1)}),1)],1),e(\"b-col\",{attrs:{md:\"9\"}},[e(\"h2\",{staticClass:\"page-line mb-2\"},[t._v(t._s(t.$t(\"Received Message\")))]),e(\"b-form\",{staticClass:\"d-flex\"},[e(\"div\",{staticClass:\"col-sm-10\"},[e(\"div\",{staticClass:\"form-row mb-2\"},[e(\"label\",{staticClass:\"sr-only\",attrs:{for:\"inline-form-input-name\"}},[t._v(t._s(t.$t(\"Name\")))]),e(\"b-form-input\",{staticClass:\"form-control col mr-4\",attrs:{id:\"inline-form-input-name\",placeholder:t.$t(\"Name\")},model:{value:t.formData.name,callback:function(s){t.$set(t.formData,\"name\",s)},expression:\"formData.name\"}}),e(\"label\",{staticClass:\"sr-only\",attrs:{for:\"inline-form-input-name\"}},[t._v(t._s(t.$t(\"Group\")))]),e(\"b-form-input\",{staticClass:\"form-control col\",attrs:{id:\"inline-form-input-group\",placeholder:t.$t(\"Group\")},model:{value:t.formData.group,callback:function(s){t.$set(t.formData,\"group\",s)},expression:\"formData.group\"}})],1),e(\"div\",{staticClass:\"form-row\"},[e(\"label\",{staticClass:\"sr-only\",attrs:{for:\"inline-form-input-content\"}},[t._v(t._s(t.$t(\"Content\")))]),e(\"b-form-input\",{staticClass:\"form-control\",attrs:{id:\"inline-form-input-content\",placeholder:t.$t(\"Content\")},model:{value:t.formData.content,callback:function(s){t.$set(t.formData,\"content\",s)},expression:\"formData.content\"}})],1)]),e(\"b-button\",{staticClass:\"ml-2 align-self-end\",attrs:{variant:\"dark\"},on:{click:t.onSearch}},[e(\"b-icon-search\"),t._v(\" \"+t._s(t.$t(\"Search\"))+\" \")],1)],1)],1)],1),e(\"b-row\",[e(\"b-col\",{attrs:{md:\"12\"}},[e(\"b-btn-toolbar\",{staticClass:\"mt-4\"},[e(\"b-button\",{staticClass:\"action-button\",attrs:{size:\"sm\",variant:\"dark\",disabled:!t.selectedItems.length},on:{click:t.reexecute}},[e(\"b-icon-arrow-repeat\",{attrs:{\"aria-hidden\":\"true\"}}),t._v(\" \"+t._s(t.$t(\"Re-execute\"))+\" \")],1),e(\"b-button\",{staticClass:\"action-button\",attrs:{size:\"sm\",variant:\"danger\",disabled:!t.selectedItems.length},on:{click:t.deletemsg}},[e(\"b-icon-trash\",{attrs:{\"aria-hidden\":\"true\"}}),t._v(\" \"+t._s(t.$t(\"Delete\"))+\" \")],1),e(\"div\",{staticClass:\"pagination\"},[e(\"span\",{staticStyle:{\"font-size\":\"14px\"}},[t._v(\" \"+t._s(t.$t(\"Page Size\"))+\":\")]),e(\"b-button-group\",{staticClass:\"ml-2\"},t._l(t.pageOptions,function(s){return e(\"b-button\",{key:s,class:{active:t.formData.perPage==s},attrs:{variant:\"outline-secondary\",size:\"sm\"},on:{click:function(i){return t.pageSizeChange(s)}}},[t._v(t._s(s)+\" \")])}),1)],1)],1),e(\"b-table\",{staticClass:\"mt-3\",attrs:{id:\"datatable\",busy:t.isBusy,striped:\"\",\"thead-tr-class\":\"text-left\",\"head-variant\":\"light\",\"tbody-tr-class\":\"text-left\",small:\"\",fields:t.fields,items:t.items,\"select-mode\":\"range\"},scopedSlots:t._u([{key:\"table-busy\",fn:function(){return[e(\"div\",{staticClass:\"text-center text-secondary my-2\"},[e(\"b-spinner\",{staticClass:\"align-middle\"}),e(\"strong\",{staticClass:\"ml-2\"},[t._v(t._s(t.$t(\"Loading\"))+\"...\")])],1)]},proxy:!0},{key:\"head(checkbox)\",fn:function(){return[e(\"b-form-checkbox\",{on:{change:t.selectAll},model:{value:t.isSelectedAll,callback:function(s){t.isSelectedAll=s},expression:\"isSelectedAll\"}})]},proxy:!0},{key:\"cell(checkbox)\",fn:function(s){return[e(\"b-form-checkbox\",{on:{change:function(i){return t.select(s.item)}},model:{value:s.item.selected,callback:function(i){t.$set(s.item,\"selected\",i)},expression:\"data.item.selected\"}})]}},{key:\"cell(id)\",fn:function(s){return[e(\"b-link\",{on:{click:function(i){return t.info(s.item,i.target)}}},[t._v(\" \"+t._s(s.item.id)+\" \")]),e(\"br\"),t._v(\" \"+t._s(s.item.name)+\" \")]}},{key:\"cell(group)\",fn:function(s){return[e(\"span\",{staticClass:\"text-break\"},[t._v(\" \"+t._s(s.item.group))])]}}])}),e(\"span\",{staticClass:\"float-left\"},[t._v(\" \"+t._s(t.$t(\"Total\"))+\": \"+t._s(t.totals)+\" \")]),e(\"b-pagination\",{staticClass:\"capPagination\",attrs:{\"first-text\":t.$t(\"First\"),\"prev-text\":t.$t(\"Prev\"),\"next-text\":t.$t(\"Next\"),\"last-text\":t.$t(\"Last\"),\"total-rows\":t.totals,\"per-page\":t.formData.perPage,\"aria-controls\":\"datatable\"},model:{value:t.formData.currentPage,callback:function(s){t.$set(t.formData,\"currentPage\",s)},expression:\"formData.currentPage\"}})],1)],1),e(\"b-modal\",{attrs:{size:\"lg\",id:t.infoModal.id,title:\"Id: \"+t.infoModal.title,\"ok-only\":\"\",\"ok-variant\":\"secondary\"}},[e(\"vue-json-pretty\",{key:t.infoModal.id,attrs:{showSelectController:\"\",data:t.infoModal.content}})],1)],1)},h=[],p=l(u,f,h,!1,null,\"33811592\",null,null);const g=p.exports;export{g as default};\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/dist/assets/Subscriber.300bed2c.css",
    "content": ".snippet-code pre{margin:0}.snippet-code pre .comment{color:green}.snippet-code pre .keyword{color:#00f}.snippet-code pre .string{color:#a31515}.snippet-code pre .type{color:#2b91af}\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/dist/assets/Subscriber.d66f9645.js",
    "content": "import{n,d as _}from\"./index.909977fe.js\";const l={data(){return{subscribers:{}}},mounted(){_.get(\"/subscriber\").then(r=>{this.subscribers=r.data})}};var o=function(){var t=this,s=t._self._c;return s(\"b-row\",[s(\"h2\",{attrs:{\"page-line\":\"\",\"mb-4\":\"\"}},[t._v(t._s(t.$t(\"Subscriber\")))]),s(\"b-table-simple\",{attrs:{\"caption-top\":\"\",bordered:\"\",small:\"\",responsive:\"\"}},[s(\"caption\",[t._v(t._s(t.$t(\"SubscriberDescription\")))]),s(\"b-thead\",{attrs:{\"head-variant\":\"light\"}},[s(\"b-tr\",[s(\"b-th\",{staticClass:\"text-left\",attrs:{width:\"30%\"}},[t._v(t._s(t.$t(\"Group\")))]),s(\"b-th\",{staticClass:\"text-left\"},[t._v(t._s(t.$t(\"Name\")))]),s(\"b-th\",{staticClass:\"text-left\"},[t._v(t._s(t.$t(\"Method\")))])],1)],1),s(\"b-tbody\",[t._l(t.subscribers,function(e){return t._l(e.values,function(a,i){return s(\"b-tr\",{key:e.group+i},[i==0?s(\"b-td\",{staticClass:\"text-left align-middle\",attrs:{rowspan:e.childCount}},[t._v(\" \"+t._s(e.group)+\" \")]):t._e(),s(\"b-td\",{staticClass:\"text-left align-middle\"},[t._v(\" \"+t._s(a.topic)+\" \")]),s(\"b-td\",[s(\"div\",{staticClass:\"snippet-code text-left align-middle\"},[s(\"code\",[s(\"pre\",[s(\"span\",{staticClass:\"type\"},[t._v(t._s(a.implName))]),t._v(\":\"),s(\"br\"),s(\"span\",{domProps:{innerHTML:t._s(a.methodEscaped)}},[t._v(t._s(a.methodEscaped))])])])])])],1)})})],2)],1)],1)},d=[],c=n(l,o,d,!1,null,null,null,null);const b=c.exports;export{b as default};\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/dist/assets/index.2d8714a6.js",
    "content": "import{e as Se}from\"./index.909977fe.js\";var Oe={exports:{}},xe={exports:{}},me={exports:{}};(function(R){(function(L){var q,A=/^-?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:e[+-]?\\d+)?$/i,$=Math.ceil,T=Math.floor,D=\"[BigNumber Error] \",v=D+\"Number primitive has more than 15 significant digits: \",H=1e14,N=14,C=9007199254740991,X=[1,10,100,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13],B=1e7,_=1e9;function K(E){var m,F,j,g=h.prototype={constructor:h,toString:null,valueOf:null},b=new h(1),M=20,U=4,Q=-7,Z=21,ue=-1e7,te=1e7,se=!1,le=1,oe=0,pe={prefix:\"\",groupSize:3,secondaryGroupSize:0,groupSeparator:\",\",decimalSeparator:\".\",fractionGroupSize:0,fractionGroupSeparator:\"\\xA0\",suffix:\"\"},ce=\"0123456789abcdefghijklmnopqrstuvwxyz\",we=!0;function h(e,r){var t,s,i,o,l,n,f,c,u=this;if(!(u instanceof h))return new h(e,r);if(r==null){if(e&&e._isBigNumber===!0){u.s=e.s,!e.c||e.e>te?u.c=u.e=null:e.e<ue?u.c=[u.e=0]:(u.e=e.e,u.c=e.c.slice());return}if((n=typeof e==\"number\")&&e*0==0){if(u.s=1/e<0?(e=-e,-1):1,e===~~e){for(o=0,l=e;l>=10;l/=10,o++);o>te?u.c=u.e=null:(u.e=o,u.c=[e]);return}c=String(e)}else{if(!A.test(c=String(e)))return j(u,c,n);u.s=c.charCodeAt(0)==45?(c=c.slice(1),-1):1}(o=c.indexOf(\".\"))>-1&&(c=c.replace(\".\",\"\")),(l=c.search(/e/i))>0?(o<0&&(o=l),o+=+c.slice(l+1),c=c.substring(0,l)):o<0&&(o=c.length)}else{if(w(r,2,ce.length,\"Base\"),r==10&&we)return u=new h(e),ee(u,M+u.e+1,U);if(c=String(e),n=typeof e==\"number\"){if(e*0!=0)return j(u,c,n,r);if(u.s=1/e<0?(c=c.slice(1),-1):1,h.DEBUG&&c.replace(/^0\\.0*|\\./,\"\").length>15)throw Error(v+e)}else u.s=c.charCodeAt(0)===45?(c=c.slice(1),-1):1;for(t=ce.slice(0,r),o=l=0,f=c.length;l<f;l++)if(t.indexOf(s=c.charAt(l))<0){if(s==\".\"){if(l>o){o=f;continue}}else if(!i&&(c==c.toUpperCase()&&(c=c.toLowerCase())||c==c.toLowerCase()&&(c=c.toUpperCase()))){i=!0,l=-1,o=0;continue}return j(u,String(e),n,r)}n=!1,c=F(c,r,10,u.s),(o=c.indexOf(\".\"))>-1?c=c.replace(\".\",\"\"):o=c.length}for(l=0;c.charCodeAt(l)===48;l++);for(f=c.length;c.charCodeAt(--f)===48;);if(c=c.slice(l,++f)){if(f-=l,n&&h.DEBUG&&f>15&&(e>C||e!==T(e)))throw Error(v+u.s*e);if((o=o-l-1)>te)u.c=u.e=null;else if(o<ue)u.c=[u.e=0];else{if(u.e=o,u.c=[],l=(o+1)%N,o<0&&(l+=N),l<f){for(l&&u.c.push(+c.slice(0,l)),f-=N;l<f;)u.c.push(+c.slice(l,l+=N));l=N-(c=c.slice(l)).length}else l-=f;for(;l--;c+=\"0\");u.c.push(+c)}}else u.c=[u.e=0]}h.clone=K,h.ROUND_UP=0,h.ROUND_DOWN=1,h.ROUND_CEIL=2,h.ROUND_FLOOR=3,h.ROUND_HALF_UP=4,h.ROUND_HALF_DOWN=5,h.ROUND_HALF_EVEN=6,h.ROUND_HALF_CEIL=7,h.ROUND_HALF_FLOOR=8,h.EUCLID=9,h.config=h.set=function(e){var r,t;if(e!=null)if(typeof e==\"object\"){if(e.hasOwnProperty(r=\"DECIMAL_PLACES\")&&(t=e[r],w(t,0,_,r),M=t),e.hasOwnProperty(r=\"ROUNDING_MODE\")&&(t=e[r],w(t,0,8,r),U=t),e.hasOwnProperty(r=\"EXPONENTIAL_AT\")&&(t=e[r],t&&t.pop?(w(t[0],-_,0,r),w(t[1],0,_,r),Q=t[0],Z=t[1]):(w(t,-_,_,r),Q=-(Z=t<0?-t:t))),e.hasOwnProperty(r=\"RANGE\"))if(t=e[r],t&&t.pop)w(t[0],-_,-1,r),w(t[1],1,_,r),ue=t[0],te=t[1];else if(w(t,-_,_,r),t)ue=-(te=t<0?-t:t);else throw Error(D+r+\" cannot be zero: \"+t);if(e.hasOwnProperty(r=\"CRYPTO\"))if(t=e[r],t===!!t)if(t)if(typeof crypto<\"u\"&&crypto&&(crypto.getRandomValues||crypto.randomBytes))se=t;else throw se=!t,Error(D+\"crypto unavailable\");else se=t;else throw Error(D+r+\" not true or false: \"+t);if(e.hasOwnProperty(r=\"MODULO_MODE\")&&(t=e[r],w(t,0,9,r),le=t),e.hasOwnProperty(r=\"POW_PRECISION\")&&(t=e[r],w(t,0,_,r),oe=t),e.hasOwnProperty(r=\"FORMAT\"))if(t=e[r],typeof t==\"object\")pe=t;else throw Error(D+r+\" not an object: \"+t);if(e.hasOwnProperty(r=\"ALPHABET\"))if(t=e[r],typeof t==\"string\"&&!/^.?$|[+\\-.\\s]|(.).*\\1/.test(t))we=t.slice(0,10)==\"0123456789\",ce=t;else throw Error(D+r+\" invalid: \"+t)}else throw Error(D+\"Object expected: \"+e);return{DECIMAL_PLACES:M,ROUNDING_MODE:U,EXPONENTIAL_AT:[Q,Z],RANGE:[ue,te],CRYPTO:se,MODULO_MODE:le,POW_PRECISION:oe,FORMAT:pe,ALPHABET:ce}},h.isBigNumber=function(e){if(!e||e._isBigNumber!==!0)return!1;if(!h.DEBUG)return!0;var r,t,s=e.c,i=e.e,o=e.s;e:if({}.toString.call(s)==\"[object Array]\"){if((o===1||o===-1)&&i>=-_&&i<=_&&i===T(i)){if(s[0]===0){if(i===0&&s.length===1)return!0;break e}if(r=(i+1)%N,r<1&&(r+=N),String(s[0]).length==r){for(r=0;r<s.length;r++)if(t=s[r],t<0||t>=H||t!==T(t))break e;if(t!==0)return!0}}}else if(s===null&&i===null&&(o===null||o===1||o===-1))return!0;throw Error(D+\"Invalid BigNumber: \"+e)},h.maximum=h.max=function(){return ve(arguments,-1)},h.minimum=h.min=function(){return ve(arguments,1)},h.random=function(){var e=9007199254740992,r=Math.random()*e&2097151?function(){return T(Math.random()*e)}:function(){return(Math.random()*1073741824|0)*8388608+(Math.random()*8388608|0)};return function(t){var s,i,o,l,n,f=0,c=[],u=new h(b);if(t==null?t=M:w(t,0,_),l=$(t/N),se)if(crypto.getRandomValues){for(s=crypto.getRandomValues(new Uint32Array(l*=2));f<l;)n=s[f]*131072+(s[f+1]>>>11),n>=9e15?(i=crypto.getRandomValues(new Uint32Array(2)),s[f]=i[0],s[f+1]=i[1]):(c.push(n%1e14),f+=2);f=l/2}else if(crypto.randomBytes){for(s=crypto.randomBytes(l*=7);f<l;)n=(s[f]&31)*281474976710656+s[f+1]*1099511627776+s[f+2]*4294967296+s[f+3]*16777216+(s[f+4]<<16)+(s[f+5]<<8)+s[f+6],n>=9e15?crypto.randomBytes(7).copy(s,f):(c.push(n%1e14),f+=7);f=l/7}else throw se=!1,Error(D+\"crypto unavailable\");if(!se)for(;f<l;)n=r(),n<9e15&&(c[f++]=n%1e14);for(l=c[--f],t%=N,l&&t&&(n=X[N-t],c[f]=T(l/n)*n);c[f]===0;c.pop(),f--);if(f<0)c=[o=0];else{for(o=-1;c[0]===0;c.splice(0,1),o-=N);for(f=1,n=c[0];n>=10;n/=10,f++);f<N&&(o-=N-f)}return u.e=o,u.c=c,u}}(),h.sum=function(){for(var e=1,r=arguments,t=new h(r[0]);e<r.length;)t=t.plus(r[e++]);return t},F=function(){var e=\"0123456789\";function r(t,s,i,o){for(var l,n=[0],f,c=0,u=t.length;c<u;){for(f=n.length;f--;n[f]*=s);for(n[0]+=o.indexOf(t.charAt(c++)),l=0;l<n.length;l++)n[l]>i-1&&(n[l+1]==null&&(n[l+1]=0),n[l+1]+=n[l]/i|0,n[l]%=i)}return n.reverse()}return function(t,s,i,o,l){var n,f,c,u,a,p,d,S,k=t.indexOf(\".\"),z=M,y=U;for(k>=0&&(u=oe,oe=0,t=t.replace(\".\",\"\"),S=new h(s),p=S.pow(t.length-k),oe=u,S.c=r(V(x(p.c),p.e,\"0\"),10,i,e),S.e=S.c.length),d=r(t,s,i,l?(n=ce,e):(n=e,ce)),c=u=d.length;d[--u]==0;d.pop());if(!d[0])return n.charAt(0);if(k<0?--c:(p.c=d,p.e=c,p.s=o,p=m(p,S,z,y,i),d=p.c,a=p.r,c=p.e),f=c+z+1,k=d[f],u=i/2,a=a||f<0||d[f+1]!=null,a=y<4?(k!=null||a)&&(y==0||y==(p.s<0?3:2)):k>u||k==u&&(y==4||a||y==6&&d[f-1]&1||y==(p.s<0?8:7)),f<1||!d[0])t=a?V(n.charAt(1),-z,n.charAt(0)):n.charAt(0);else{if(d.length=f,a)for(--i;++d[--f]>i;)d[f]=0,f||(++c,d=[1].concat(d));for(u=d.length;!d[--u];);for(k=0,t=\"\";k<=u;t+=n.charAt(d[k++]));t=V(t,c,n.charAt(0))}return t}}(),m=function(){function e(s,i,o){var l,n,f,c,u=0,a=s.length,p=i%B,d=i/B|0;for(s=s.slice();a--;)f=s[a]%B,c=s[a]/B|0,l=d*f+c*p,n=p*f+l%B*B+u,u=(n/o|0)+(l/B|0)+d*c,s[a]=n%o;return u&&(s=[u].concat(s)),s}function r(s,i,o,l){var n,f;if(o!=l)f=o>l?1:-1;else for(n=f=0;n<o;n++)if(s[n]!=i[n]){f=s[n]>i[n]?1:-1;break}return f}function t(s,i,o,l){for(var n=0;o--;)s[o]-=n,n=s[o]<i[o]?1:0,s[o]=n*l+s[o]-i[o];for(;!s[0]&&s.length>1;s.splice(0,1));}return function(s,i,o,l,n){var f,c,u,a,p,d,S,k,z,y,P,W,he,Ae,Ee,ie,ae,re=s.s==i.s?1:-1,Y=s.c,G=i.c;if(!Y||!Y[0]||!G||!G[0])return new h(!s.s||!i.s||(Y?G&&Y[0]==G[0]:!G)?NaN:Y&&Y[0]==0||!G?re*0:re/0);for(k=new h(re),z=k.c=[],c=s.e-i.e,re=o+c+1,n||(n=H,c=O(s.e/N)-O(i.e/N),re=re/N|0),u=0;G[u]==(Y[u]||0);u++);if(G[u]>(Y[u]||0)&&c--,re<0)z.push(1),a=!0;else{for(Ae=Y.length,ie=G.length,u=0,re+=2,p=T(n/(G[0]+1)),p>1&&(G=e(G,p,n),Y=e(Y,p,n),ie=G.length,Ae=Y.length),he=ie,y=Y.slice(0,ie),P=y.length;P<ie;y[P++]=0);ae=G.slice(),ae=[0].concat(ae),Ee=G[0],G[1]>=n/2&&Ee++;do{if(p=0,f=r(G,y,ie,P),f<0){if(W=y[0],ie!=P&&(W=W*n+(y[1]||0)),p=T(W/Ee),p>1)for(p>=n&&(p=n-1),d=e(G,p,n),S=d.length,P=y.length;r(d,y,S,P)==1;)p--,t(d,ie<S?ae:G,S,n),S=d.length,f=1;else p==0&&(f=p=1),d=G.slice(),S=d.length;if(S<P&&(d=[0].concat(d)),t(y,d,P,n),P=y.length,f==-1)for(;r(G,y,ie,P)<1;)p++,t(y,ie<P?ae:G,P,n),P=y.length}else f===0&&(p++,y=[0]);z[u++]=p,y[0]?y[P++]=Y[he]||0:(y=[Y[he]],P=1)}while((he++<Ae||y[0]!=null)&&re--);a=y[0]!=null,z[0]||z.splice(0,1)}if(n==H){for(u=1,re=z[0];re>=10;re/=10,u++);ee(k,o+(k.e=u+c*N-1)+1,l,a)}else k.e=c,k.r=+a;return k}}();function de(e,r,t,s){var i,o,l,n,f;if(t==null?t=U:w(t,0,8),!e.c)return e.toString();if(i=e.c[0],l=e.e,r==null)f=x(e.c),f=s==1||s==2&&(l<=Q||l>=Z)?ne(f,l):V(f,l,\"0\");else if(e=ee(new h(e),r,t),o=e.e,f=x(e.c),n=f.length,s==1||s==2&&(r<=o||o<=Q)){for(;n<r;f+=\"0\",n++);f=ne(f,o)}else if(r-=l,f=V(f,o,\"0\"),o+1>n){if(--r>0)for(f+=\".\";r--;f+=\"0\");}else if(r+=o-n,r>0)for(o+1==n&&(f+=\".\");r--;f+=\"0\");return e.s<0&&i?\"-\"+f:f}function ve(e,r){for(var t,s,i=1,o=new h(e[0]);i<e.length;i++)s=new h(e[i]),(!s.s||(t=I(o,s))===r||t===0&&o.s===r)&&(o=s);return o}function Ne(e,r,t){for(var s=1,i=r.length;!r[--i];r.pop());for(i=r[0];i>=10;i/=10,s++);return(t=s+t*N-1)>te?e.c=e.e=null:t<ue?e.c=[e.e=0]:(e.e=t,e.c=r),e}j=function(){var e=/^(-?)0([xbo])(?=\\w[\\w.]*$)/i,r=/^([^.]+)\\.$/,t=/^\\.([^.]+)$/,s=/^-?(Infinity|NaN)$/,i=/^\\s*\\+(?=[\\w.])|^\\s+|\\s+$/g;return function(o,l,n,f){var c,u=n?l:l.replace(i,\"\");if(s.test(u))o.s=isNaN(u)?null:u<0?-1:1;else{if(!n&&(u=u.replace(e,function(a,p,d){return c=(d=d.toLowerCase())==\"x\"?16:d==\"b\"?2:8,!f||f==c?p:a}),f&&(c=f,u=u.replace(r,\"$1\").replace(t,\"0.$1\")),l!=u))return new h(u,c);if(h.DEBUG)throw Error(D+\"Not a\"+(f?\" base \"+f:\"\")+\" number: \"+l);o.s=null}o.c=o.e=null}}();function ee(e,r,t,s){var i,o,l,n,f,c,u,a=e.c,p=X;if(a){e:{for(i=1,n=a[0];n>=10;n/=10,i++);if(o=r-i,o<0)o+=N,l=r,f=a[c=0],u=T(f/p[i-l-1]%10);else if(c=$((o+1)/N),c>=a.length)if(s){for(;a.length<=c;a.push(0));f=u=0,i=1,o%=N,l=o-N+1}else break e;else{for(f=n=a[c],i=1;n>=10;n/=10,i++);o%=N,l=o-N+i,u=l<0?0:T(f/p[i-l-1]%10)}if(s=s||r<0||a[c+1]!=null||(l<0?f:f%p[i-l-1]),s=t<4?(u||s)&&(t==0||t==(e.s<0?3:2)):u>5||u==5&&(t==4||s||t==6&&(o>0?l>0?f/p[i-l]:0:a[c-1])%10&1||t==(e.s<0?8:7)),r<1||!a[0])return a.length=0,s?(r-=e.e+1,a[0]=p[(N-r%N)%N],e.e=-r||0):a[0]=e.e=0,e;if(o==0?(a.length=c,n=1,c--):(a.length=c+1,n=p[N-o],a[c]=l>0?T(f/p[i-l]%p[l])*n:0),s)for(;;)if(c==0){for(o=1,l=a[0];l>=10;l/=10,o++);for(l=a[0]+=n,n=1;l>=10;l/=10,n++);o!=n&&(e.e++,a[0]==H&&(a[0]=1));break}else{if(a[c]+=n,a[c]!=H)break;a[c--]=0,n=1}for(o=a.length;a[--o]===0;a.pop());}e.e>te?e.c=e.e=null:e.e<ue&&(e.c=[e.e=0])}return e}function fe(e){var r,t=e.e;return t===null?e.toString():(r=x(e.c),r=t<=Q||t>=Z?ne(r,t):V(r,t,\"0\"),e.s<0?\"-\"+r:r)}return g.absoluteValue=g.abs=function(){var e=new h(this);return e.s<0&&(e.s=1),e},g.comparedTo=function(e,r){return I(this,new h(e,r))},g.decimalPlaces=g.dp=function(e,r){var t,s,i,o=this;if(e!=null)return w(e,0,_),r==null?r=U:w(r,0,8),ee(new h(o),e+o.e+1,r);if(!(t=o.c))return null;if(s=((i=t.length-1)-O(this.e/N))*N,i=t[i])for(;i%10==0;i/=10,s--);return s<0&&(s=0),s},g.dividedBy=g.div=function(e,r){return m(this,new h(e,r),M,U)},g.dividedToIntegerBy=g.idiv=function(e,r){return m(this,new h(e,r),0,1)},g.exponentiatedBy=g.pow=function(e,r){var t,s,i,o,l,n,f,c,u,a=this;if(e=new h(e),e.c&&!e.isInteger())throw Error(D+\"Exponent not an integer: \"+fe(e));if(r!=null&&(r=new h(r)),n=e.e>14,!a.c||!a.c[0]||a.c[0]==1&&!a.e&&a.c.length==1||!e.c||!e.c[0])return u=new h(Math.pow(+fe(a),n?e.s*(2-J(e)):+fe(e))),r?u.mod(r):u;if(f=e.s<0,r){if(r.c?!r.c[0]:!r.s)return new h(NaN);s=!f&&a.isInteger()&&r.isInteger(),s&&(a=a.mod(r))}else{if(e.e>9&&(a.e>0||a.e<-1||(a.e==0?a.c[0]>1||n&&a.c[1]>=24e7:a.c[0]<8e13||n&&a.c[0]<=9999975e7)))return o=a.s<0&&J(e)?-0:0,a.e>-1&&(o=1/o),new h(f?1/o:o);oe&&(o=$(oe/N+2))}for(n?(t=new h(.5),f&&(e.s=1),c=J(e)):(i=Math.abs(+fe(e)),c=i%2),u=new h(b);;){if(c){if(u=u.times(a),!u.c)break;o?u.c.length>o&&(u.c.length=o):s&&(u=u.mod(r))}if(i){if(i=T(i/2),i===0)break;c=i%2}else if(e=e.times(t),ee(e,e.e+1,1),e.e>14)c=J(e);else{if(i=+fe(e),i===0)break;c=i%2}a=a.times(a),o?a.c&&a.c.length>o&&(a.c.length=o):s&&(a=a.mod(r))}return s?u:(f&&(u=b.div(u)),r?u.mod(r):o?ee(u,oe,U,l):u)},g.integerValue=function(e){var r=new h(this);return e==null?e=U:w(e,0,8),ee(r,r.e+1,e)},g.isEqualTo=g.eq=function(e,r){return I(this,new h(e,r))===0},g.isFinite=function(){return!!this.c},g.isGreaterThan=g.gt=function(e,r){return I(this,new h(e,r))>0},g.isGreaterThanOrEqualTo=g.gte=function(e,r){return(r=I(this,new h(e,r)))===1||r===0},g.isInteger=function(){return!!this.c&&O(this.e/N)>this.c.length-2},g.isLessThan=g.lt=function(e,r){return I(this,new h(e,r))<0},g.isLessThanOrEqualTo=g.lte=function(e,r){return(r=I(this,new h(e,r)))===-1||r===0},g.isNaN=function(){return!this.s},g.isNegative=function(){return this.s<0},g.isPositive=function(){return this.s>0},g.isZero=function(){return!!this.c&&this.c[0]==0},g.minus=function(e,r){var t,s,i,o,l=this,n=l.s;if(e=new h(e,r),r=e.s,!n||!r)return new h(NaN);if(n!=r)return e.s=-r,l.plus(e);var f=l.e/N,c=e.e/N,u=l.c,a=e.c;if(!f||!c){if(!u||!a)return u?(e.s=-r,e):new h(a?l:NaN);if(!u[0]||!a[0])return a[0]?(e.s=-r,e):new h(u[0]?l:U==3?-0:0)}if(f=O(f),c=O(c),u=u.slice(),n=f-c){for((o=n<0)?(n=-n,i=u):(c=f,i=a),i.reverse(),r=n;r--;i.push(0));i.reverse()}else for(s=(o=(n=u.length)<(r=a.length))?n:r,n=r=0;r<s;r++)if(u[r]!=a[r]){o=u[r]<a[r];break}if(o&&(i=u,u=a,a=i,e.s=-e.s),r=(s=a.length)-(t=u.length),r>0)for(;r--;u[t++]=0);for(r=H-1;s>n;){if(u[--s]<a[s]){for(t=s;t&&!u[--t];u[t]=r);--u[t],u[s]+=H}u[s]-=a[s]}for(;u[0]==0;u.splice(0,1),--c);return u[0]?Ne(e,u,c):(e.s=U==3?-1:1,e.c=[e.e=0],e)},g.modulo=g.mod=function(e,r){var t,s,i=this;return e=new h(e,r),!i.c||!e.s||e.c&&!e.c[0]?new h(NaN):!e.c||i.c&&!i.c[0]?new h(i):(le==9?(s=e.s,e.s=1,t=m(i,e,0,3),e.s=s,t.s*=s):t=m(i,e,0,le),e=i.minus(t.times(e)),!e.c[0]&&le==1&&(e.s=i.s),e)},g.multipliedBy=g.times=function(e,r){var t,s,i,o,l,n,f,c,u,a,p,d,S,k,z,y=this,P=y.c,W=(e=new h(e,r)).c;if(!P||!W||!P[0]||!W[0])return!y.s||!e.s||P&&!P[0]&&!W||W&&!W[0]&&!P?e.c=e.e=e.s=null:(e.s*=y.s,!P||!W?e.c=e.e=null:(e.c=[0],e.e=0)),e;for(s=O(y.e/N)+O(e.e/N),e.s*=y.s,f=P.length,a=W.length,f<a&&(S=P,P=W,W=S,i=f,f=a,a=i),i=f+a,S=[];i--;S.push(0));for(k=H,z=B,i=a;--i>=0;){for(t=0,p=W[i]%z,d=W[i]/z|0,l=f,o=i+l;o>i;)c=P[--l]%z,u=P[l]/z|0,n=d*c+u*p,c=p*c+n%z*z+S[o]+t,t=(c/k|0)+(n/z|0)+d*u,S[o--]=c%k;S[o]=t}return t?++s:S.splice(0,1),Ne(e,S,s)},g.negated=function(){var e=new h(this);return e.s=-e.s||null,e},g.plus=function(e,r){var t,s=this,i=s.s;if(e=new h(e,r),r=e.s,!i||!r)return new h(NaN);if(i!=r)return e.s=-r,s.minus(e);var o=s.e/N,l=e.e/N,n=s.c,f=e.c;if(!o||!l){if(!n||!f)return new h(i/0);if(!n[0]||!f[0])return f[0]?e:new h(n[0]?s:i*0)}if(o=O(o),l=O(l),n=n.slice(),i=o-l){for(i>0?(l=o,t=f):(i=-i,t=n),t.reverse();i--;t.push(0));t.reverse()}for(i=n.length,r=f.length,i-r<0&&(t=f,f=n,n=t,r=i),i=0;r;)i=(n[--r]=n[r]+f[r]+i)/H|0,n[r]=H===n[r]?0:n[r]%H;return i&&(n=[i].concat(n),++l),Ne(e,n,l)},g.precision=g.sd=function(e,r){var t,s,i,o=this;if(e!=null&&e!==!!e)return w(e,1,_),r==null?r=U:w(r,0,8),ee(new h(o),e,r);if(!(t=o.c))return null;if(i=t.length-1,s=i*N+1,i=t[i]){for(;i%10==0;i/=10,s--);for(i=t[0];i>=10;i/=10,s++);}return e&&o.e+1>s&&(s=o.e+1),s},g.shiftedBy=function(e){return w(e,-C,C),this.times(\"1e\"+e)},g.squareRoot=g.sqrt=function(){var e,r,t,s,i,o=this,l=o.c,n=o.s,f=o.e,c=M+4,u=new h(\"0.5\");if(n!==1||!l||!l[0])return new h(!n||n<0&&(!l||l[0])?NaN:l?o:1/0);if(n=Math.sqrt(+fe(o)),n==0||n==1/0?(r=x(l),(r.length+f)%2==0&&(r+=\"0\"),n=Math.sqrt(+r),f=O((f+1)/2)-(f<0||f%2),n==1/0?r=\"5e\"+f:(r=n.toExponential(),r=r.slice(0,r.indexOf(\"e\")+1)+f),t=new h(r)):t=new h(n+\"\"),t.c[0]){for(f=t.e,n=f+c,n<3&&(n=0);;)if(i=t,t=u.times(i.plus(m(o,i,c,1))),x(i.c).slice(0,n)===(r=x(t.c)).slice(0,n))if(t.e<f&&--n,r=r.slice(n-3,n+1),r==\"9999\"||!s&&r==\"4999\"){if(!s&&(ee(i,i.e+M+2,0),i.times(i).eq(o))){t=i;break}c+=4,n+=4,s=1}else{(!+r||!+r.slice(1)&&r.charAt(0)==\"5\")&&(ee(t,t.e+M+2,1),e=!t.times(t).eq(o));break}}return ee(t,t.e+M+1,U,e)},g.toExponential=function(e,r){return e!=null&&(w(e,0,_),e++),de(this,e,r,1)},g.toFixed=function(e,r){return e!=null&&(w(e,0,_),e=e+this.e+1),de(this,e,r)},g.toFormat=function(e,r,t){var s,i=this;if(t==null)e!=null&&r&&typeof r==\"object\"?(t=r,r=null):e&&typeof e==\"object\"?(t=e,e=r=null):t=pe;else if(typeof t!=\"object\")throw Error(D+\"Argument not an object: \"+t);if(s=i.toFixed(e,r),i.c){var o,l=s.split(\".\"),n=+t.groupSize,f=+t.secondaryGroupSize,c=t.groupSeparator||\"\",u=l[0],a=l[1],p=i.s<0,d=p?u.slice(1):u,S=d.length;if(f&&(o=n,n=f,f=o,S-=o),n>0&&S>0){for(o=S%n||n,u=d.substr(0,o);o<S;o+=n)u+=c+d.substr(o,n);f>0&&(u+=c+d.slice(o)),p&&(u=\"-\"+u)}s=a?u+(t.decimalSeparator||\"\")+((f=+t.fractionGroupSize)?a.replace(new RegExp(\"\\\\d{\"+f+\"}\\\\B\",\"g\"),\"$&\"+(t.fractionGroupSeparator||\"\")):a):u}return(t.prefix||\"\")+s+(t.suffix||\"\")},g.toFraction=function(e){var r,t,s,i,o,l,n,f,c,u,a,p,d=this,S=d.c;if(e!=null&&(n=new h(e),!n.isInteger()&&(n.c||n.s!==1)||n.lt(b)))throw Error(D+\"Argument \"+(n.isInteger()?\"out of range: \":\"not an integer: \")+fe(n));if(!S)return new h(d);for(r=new h(b),c=t=new h(b),s=f=new h(b),p=x(S),o=r.e=p.length-d.e-1,r.c[0]=X[(l=o%N)<0?N+l:l],e=!e||n.comparedTo(r)>0?o>0?r:c:n,l=te,te=1/0,n=new h(p),f.c[0]=0;u=m(n,r,0,1),i=t.plus(u.times(s)),i.comparedTo(e)!=1;)t=s,s=i,c=f.plus(u.times(i=c)),f=i,r=n.minus(u.times(i=r)),n=i;return i=m(e.minus(t),s,0,1),f=f.plus(i.times(c)),t=t.plus(i.times(s)),f.s=c.s=d.s,o=o*2,a=m(c,s,o,U).minus(d).abs().comparedTo(m(f,t,o,U).minus(d).abs())<1?[c,s]:[f,t],te=l,a},g.toNumber=function(){return+fe(this)},g.toPrecision=function(e,r){return e!=null&&w(e,1,_),de(this,e,r,2)},g.toString=function(e){var r,t=this,s=t.s,i=t.e;return i===null?s?(r=\"Infinity\",s<0&&(r=\"-\"+r)):r=\"NaN\":(e==null?r=i<=Q||i>=Z?ne(x(t.c),i):V(x(t.c),i,\"0\"):e===10&&we?(t=ee(new h(t),M+i+1,U),r=V(x(t.c),t.e,\"0\")):(w(e,2,ce.length,\"Base\"),r=F(V(x(t.c),i,\"0\"),10,e,s,!0)),s<0&&t.c[0]&&(r=\"-\"+r)),r},g.valueOf=g.toJSON=function(){return fe(this)},g._isBigNumber=!0,E!=null&&h.set(E),h}function O(E){var m=E|0;return E>0||E===m?m:m-1}function x(E){for(var m,F,j=1,g=E.length,b=E[0]+\"\";j<g;){for(m=E[j++]+\"\",F=N-m.length;F--;m=\"0\"+m);b+=m}for(g=b.length;b.charCodeAt(--g)===48;);return b.slice(0,g+1||1)}function I(E,m){var F,j,g=E.c,b=m.c,M=E.s,U=m.s,Q=E.e,Z=m.e;if(!M||!U)return null;if(F=g&&!g[0],j=b&&!b[0],F||j)return F?j?0:-U:M;if(M!=U)return M;if(F=M<0,j=Q==Z,!g||!b)return j?0:!g^F?1:-1;if(!j)return Q>Z^F?1:-1;for(U=(Q=g.length)<(Z=b.length)?Q:Z,M=0;M<U;M++)if(g[M]!=b[M])return g[M]>b[M]^F?1:-1;return Q==Z?0:Q>Z^F?1:-1}function w(E,m,F,j){if(E<m||E>F||E!==T(E))throw Error(D+(j||\"Argument\")+(typeof E==\"number\"?E<m||E>F?\" out of range: \":\" not an integer: \":\" not a primitive number: \")+String(E))}function J(E){var m=E.c.length-1;return O(E.e/N)==m&&E.c[m]%2!=0}function ne(E,m){return(E.length>1?E.charAt(0)+\".\"+E.slice(1):E)+(m<0?\"e\":\"e+\")+m}function V(E,m,F){var j,g;if(m<0){for(g=F+\".\";++m;g+=F);E=g+E}else if(j=E.length,++m>j){for(g=F,m-=j;--m;g+=F);E+=g}else m<j&&(E=E.slice(0,m)+\".\"+E.slice(m));return E}q=K(),q.default=q.BigNumber=q,R.exports?R.exports=q:(L||(L=typeof self<\"u\"&&self?self:window),L.BigNumber=q)})(Se)})(me);(function(R){var L=me.exports,q=R.exports;(function(){var A=/[\\\\\\\"\\x00-\\x1f\\x7f-\\x9f\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]/g,$,T,D={\"\\b\":\"\\\\b\",\"\t\":\"\\\\t\",\"\\n\":\"\\\\n\",\"\\f\":\"\\\\f\",\"\\r\":\"\\\\r\",'\"':'\\\\\"',\"\\\\\":\"\\\\\\\\\"},v;function H(C){return A.lastIndex=0,A.test(C)?'\"'+C.replace(A,function(X){var B=D[X];return typeof B==\"string\"?B:\"\\\\u\"+(\"0000\"+X.charCodeAt(0).toString(16)).slice(-4)})+'\"':'\"'+C+'\"'}function N(C,X){var B,_,K,O,x=$,I,w=X[C],J=w!=null&&(w instanceof L||L.isBigNumber(w));switch(w&&typeof w==\"object\"&&typeof w.toJSON==\"function\"&&(w=w.toJSON(C)),typeof v==\"function\"&&(w=v.call(X,C,w)),typeof w){case\"string\":return J?w:H(w);case\"number\":return isFinite(w)?String(w):\"null\";case\"boolean\":case\"null\":case\"bigint\":return String(w);case\"object\":if(!w)return\"null\";if($+=T,I=[],Object.prototype.toString.apply(w)===\"[object Array]\"){for(O=w.length,B=0;B<O;B+=1)I[B]=N(B,w)||\"null\";return K=I.length===0?\"[]\":$?`[\n`+$+I.join(`,\n`+$)+`\n`+x+\"]\":\"[\"+I.join(\",\")+\"]\",$=x,K}if(v&&typeof v==\"object\")for(O=v.length,B=0;B<O;B+=1)typeof v[B]==\"string\"&&(_=v[B],K=N(_,w),K&&I.push(H(_)+($?\": \":\":\")+K));else Object.keys(w).forEach(function(ne){var V=N(ne,w);V&&I.push(H(ne)+($?\": \":\":\")+V)});return K=I.length===0?\"{}\":$?`{\n`+$+I.join(`,\n`+$)+`\n`+x+\"}\":\"{\"+I.join(\",\")+\"}\",$=x,K}}typeof q.stringify!=\"function\"&&(q.stringify=function(C,X,B){var _;if($=\"\",T=\"\",typeof B==\"number\")for(_=0;_<B;_+=1)T+=\" \";else typeof B==\"string\"&&(T=B);if(v=X,X&&typeof X!=\"function\"&&(typeof X!=\"object\"||typeof X.length!=\"number\"))throw new Error(\"JSON.stringify\");return N(\"\",{\"\":C})})})()})(xe);var ge=null;const _e=/(?:_|\\\\u005[Ff])(?:_|\\\\u005[Ff])(?:p|\\\\u0070)(?:r|\\\\u0072)(?:o|\\\\u006[Ff])(?:t|\\\\u0074)(?:o|\\\\u006[Ff])(?:_|\\\\u005[Ff])(?:_|\\\\u005[Ff])/,Ie=/(?:c|\\\\u0063)(?:o|\\\\u006[Ff])(?:n|\\\\u006[Ee])(?:s|\\\\u0073)(?:t|\\\\u0074)(?:r|\\\\u0072)(?:u|\\\\u0075)(?:c|\\\\u0063)(?:t|\\\\u0074)(?:o|\\\\u006[Ff])(?:r|\\\\u0072)/;var Pe=function(R){var L={strict:!1,storeAsString:!1,alwaysParseAsBig:!1,useNativeBigInt:!1,protoAction:\"error\",constructorAction:\"error\"};if(R!=null){if(R.strict===!0&&(L.strict=!0),R.storeAsString===!0&&(L.storeAsString=!0),L.alwaysParseAsBig=R.alwaysParseAsBig===!0?R.alwaysParseAsBig:!1,L.useNativeBigInt=R.useNativeBigInt===!0?R.useNativeBigInt:!1,typeof R.constructorAction<\"u\")if(R.constructorAction===\"error\"||R.constructorAction===\"ignore\"||R.constructorAction===\"preserve\")L.constructorAction=R.constructorAction;else throw new Error(`Incorrect value for constructorAction option, must be \"error\", \"ignore\" or undefined but passed ${R.constructorAction}`);if(typeof R.protoAction<\"u\")if(R.protoAction===\"error\"||R.protoAction===\"ignore\"||R.protoAction===\"preserve\")L.protoAction=R.protoAction;else throw new Error(`Incorrect value for protoAction option, must be \"error\", \"ignore\" or undefined but passed ${R.protoAction}`)}var q,A,$={'\"':'\"',\"\\\\\":\"\\\\\",\"/\":\"/\",b:\"\\b\",f:\"\\f\",n:`\n`,r:\"\\r\",t:\"\t\"},T,D=function(O){throw{name:\"SyntaxError\",message:O,at:q,text:T}},v=function(O){return O&&O!==A&&D(\"Expected '\"+O+\"' instead of '\"+A+\"'\"),A=T.charAt(q),q+=1,A},H=function(){var O,x=\"\";for(A===\"-\"&&(x=\"-\",v(\"-\"));A>=\"0\"&&A<=\"9\";)x+=A,v();if(A===\".\")for(x+=\".\";v()&&A>=\"0\"&&A<=\"9\";)x+=A;if(A===\"e\"||A===\"E\")for(x+=A,v(),(A===\"-\"||A===\"+\")&&(x+=A,v());A>=\"0\"&&A<=\"9\";)x+=A,v();if(O=+x,!isFinite(O))D(\"Bad number\");else return ge==null&&(ge=me.exports),x.length>15?L.storeAsString?x:L.useNativeBigInt?BigInt(x):new ge(x):L.alwaysParseAsBig?L.useNativeBigInt?BigInt(O):new ge(O):O},N=function(){var O,x,I=\"\",w;if(A==='\"')for(var J=q;v();){if(A==='\"')return q-1>J&&(I+=T.substring(J,q-1)),v(),I;if(A===\"\\\\\"){if(q-1>J&&(I+=T.substring(J,q-1)),v(),A===\"u\"){for(w=0,x=0;x<4&&(O=parseInt(v(),16),!!isFinite(O));x+=1)w=w*16+O;I+=String.fromCharCode(w)}else if(typeof $[A]==\"string\")I+=$[A];else break;J=q}}D(\"Bad string\")},C=function(){for(;A&&A<=\" \";)v()},X=function(){switch(A){case\"t\":return v(\"t\"),v(\"r\"),v(\"u\"),v(\"e\"),!0;case\"f\":return v(\"f\"),v(\"a\"),v(\"l\"),v(\"s\"),v(\"e\"),!1;case\"n\":return v(\"n\"),v(\"u\"),v(\"l\"),v(\"l\"),null}D(\"Unexpected '\"+A+\"'\")},B,_=function(){var O=[];if(A===\"[\"){if(v(\"[\"),C(),A===\"]\")return v(\"]\"),O;for(;A;){if(O.push(B()),C(),A===\"]\")return v(\"]\"),O;v(\",\"),C()}}D(\"Bad array\")},K=function(){var O,x=Object.create(null);if(A===\"{\"){if(v(\"{\"),C(),A===\"}\")return v(\"}\"),x;for(;A;){if(O=N(),C(),v(\":\"),L.strict===!0&&Object.hasOwnProperty.call(x,O)&&D('Duplicate key \"'+O+'\"'),_e.test(O)===!0?L.protoAction===\"error\"?D(\"Object contains forbidden prototype property\"):L.protoAction===\"ignore\"?B():x[O]=B():Ie.test(O)===!0?L.constructorAction===\"error\"?D(\"Object contains forbidden constructor property\"):L.constructorAction===\"ignore\"?B():x[O]=B():x[O]=B(),C(),A===\"}\")return v(\"}\"),x;v(\",\"),C()}}D(\"Bad object\")};return B=function(){switch(C(),A){case\"{\":return K();case\"[\":return _();case'\"':return N();case\"-\":return H();default:return A>=\"0\"&&A<=\"9\"?H():X()}},function(O,x){var I;return T=O+\"\",q=0,A=\" \",I=B(),C(),A&&D(\"Syntax error\"),typeof x==\"function\"?function w(J,ne){var V,E=J[ne];return E&&typeof E==\"object\"&&Object.keys(E).forEach(function(m){V=w(E,m),V!==void 0?E[m]=V:delete E[m]}),x.call(J,ne,E)}({\"\":I},\"\"):I}},Re=Pe,Be=xe.exports.stringify,ye=Re;Oe.exports=function(R){return{parse:ye(R),stringify:Be}};Oe.exports.parse=ye();Oe.exports.stringify=Be;export{Oe as j};\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/dist/assets/index.856c0890.css",
    "content": "@charset \"UTF-8\";.nav-item[data-v-b874239e]{padding:0 10px}.drop-active .active{background-color:#000!important}.d-block[data-v-3ca8df4b]{color:#fff9}#app{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-align:center;color:#2c3e50;padding-bottom:50px}.page-line{text-align:left;line-height:38px;padding-bottom:9px;border-bottom:1px solid #eee}.uplot,.uplot *,.uplot *:before,.uplot *:after{box-sizing:border-box}.uplot{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol,\"Noto Color Emoji\";line-height:1.5;width:min-content}.u-title{text-align:center;font-size:18px;font-weight:700}.u-wrap{position:relative;user-select:none}.u-over,.u-under{position:absolute}.u-under{overflow:hidden}.uplot canvas{display:block;position:relative;width:100%;height:100%}.u-axis{position:absolute}.u-legend{font-size:14px;margin:auto;text-align:center}.u-inline{display:block}.u-inline *{display:inline-block}.u-inline tr{margin-right:16px}.u-legend th{font-weight:600}.u-legend th>*{vertical-align:middle;display:inline-block}.u-legend .u-marker{width:1em;height:1em;margin-right:4px;background-clip:padding-box!important}.u-inline.u-live th:after{content:\":\";vertical-align:middle}.u-inline:not(.u-live) .u-value{display:none}.u-series>*{padding:4px}.u-series th{cursor:pointer}.u-legend .u-off>*{opacity:.3}.u-select{background:rgba(0,0,0,.07);position:absolute;pointer-events:none}.u-cursor-x,.u-cursor-y{position:absolute;left:0;top:0;pointer-events:none;will-change:transform;z-index:100}.u-hz .u-cursor-x,.u-vt .u-cursor-y{height:100%;border-right:1px dashed #607D8B}.u-hz .u-cursor-y,.u-vt .u-cursor-x{width:100%;border-bottom:1px dashed #607D8B}.u-cursor-pt{position:absolute;top:0;left:0;border-radius:50%;border:0 solid;pointer-events:none;will-change:transform;z-index:100;background-clip:padding-box!important}.u-axis.u-off,.u-select.u-off,.u-cursor-x.u-off,.u-cursor-y.u-off,.u-cursor-pt.u-off{display:none}.chart{height:500px;width:100%}.vjs-tree-brackets{cursor:pointer}.vjs-tree-brackets:hover{color:#1890ff}.vjs-check-controller{position:absolute;left:0}.vjs-check-controller.is-checked .vjs-check-controller-inner{background-color:#1890ff;border-color:#0076e4}.vjs-check-controller.is-checked .vjs-check-controller-inner.is-checkbox:after{transform:rotate(45deg) scaleY(1)}.vjs-check-controller.is-checked .vjs-check-controller-inner.is-radio:after{transform:translate(-50%,-50%) scale(1)}.vjs-check-controller .vjs-check-controller-inner{display:inline-block;position:relative;border:1px solid #bfcbd9;border-radius:2px;vertical-align:middle;box-sizing:border-box;width:16px;height:16px;background-color:#fff;z-index:1;cursor:pointer;transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46)}.vjs-check-controller .vjs-check-controller-inner:after{box-sizing:content-box;content:\"\";border:2px solid #fff;border-left:0;border-top:0;height:8px;left:4px;position:absolute;top:1px;transform:rotate(45deg) scaleY(0);width:4px;transition:transform .15s cubic-bezier(.71,-.46,.88,.6) .05s;transform-origin:center}.vjs-check-controller .vjs-check-controller-inner.is-radio{border-radius:100%}.vjs-check-controller .vjs-check-controller-inner.is-radio:after{border-radius:100%;height:4px;background-color:#fff;left:50%;top:50%}.vjs-check-controller .vjs-check-controller-original{opacity:0;outline:none;position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;margin:0}.vjs-carets{position:absolute;right:0;cursor:pointer}.vjs-carets svg{transition:transform .3s}.vjs-carets:hover{color:#1890ff}.vjs-carets-close{transform:rotate(-90deg)}.vjs-tree-node{display:flex;position:relative;line-height:20px}.vjs-tree-node.has-carets{padding-left:15px}.vjs-tree-node.has-carets.has-selector,.vjs-tree-node.has-selector{padding-left:30px}.vjs-tree-node.is-highlight,.vjs-tree-node:hover{background-color:#e6f7ff}.vjs-tree-node .vjs-indent{display:flex;position:relative}.vjs-tree-node .vjs-indent-unit{width:1em}.vjs-tree-node .vjs-indent-unit.has-line{border-left:1px dashed #bfcbd9}.vjs-node-index{position:absolute;right:100%;margin-right:4px;user-select:none}.vjs-colon{white-space:pre}.vjs-comment{color:#bfcbd9}.vjs-value{word-break:break-word}.vjs-value-null,.vjs-value-undefined{color:#d55fde}.vjs-value-boolean,.vjs-value-number{color:#1d8ce0}.vjs-value-string{color:#13ce66}.vjs-tree{font-family:Monaco,Menlo,Consolas,Bitstream Vera Sans Mono,monospace;font-size:14px;text-align:left}.vjs-tree.is-virtual{overflow:auto}.vjs-tree.is-virtual .vjs-tree-node{white-space:nowrap}/*!\n* Bootstrap v4.6.2 (https://getbootstrap.com/)\n* Copyright 2011-2022 The Bootstrap Authors\n* Copyright 2011-2022 Twitter, Inc.\n* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n*/:root{--blue: #007bff;--indigo: #6610f2;--purple: #6f42c1;--pink: #e83e8c;--red: #dc3545;--orange: #fd7e14;--yellow: #ffc107;--green: #28a745;--teal: #20c997;--cyan: #17a2b8;--white: #fff;--gray: #6c757d;--gray-dark: #343a40;--primary: #007bff;--secondary: #6c757d;--success: #28a745;--info: #17a2b8;--warning: #ffc107;--danger: #dc3545;--light: #f8f9fa;--dark: #343a40;--breakpoint-xs: 0;--breakpoint-sm: 576px;--breakpoint-md: 768px;--breakpoint-lg: 992px;--breakpoint-xl: 1200px;--font-family-sans-serif: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", \"Liberation Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";--font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace}*,*:before,*:after{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,Liberation Sans,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol,\"Noto Color Emoji\";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex=\"-1\"]:focus:not(:focus-visible){outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[title],abbr[data-original-title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([class]){color:inherit;text-decoration:none}a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit;text-align:-webkit-match-parent}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus:not(:focus-visible){outline:0}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button:not(:disabled),[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled){cursor:pointer}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{padding:0;border-style:none}input[type=radio],input[type=checkbox]{box-sizing:border-box;padding:0}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{margin-bottom:.5rem;font-weight:500;line-height:1.2}h1,.h1{font-size:2.5rem}h2,.h2{font-size:2rem}h3,.h3{font-size:1.75rem}h4,.h4{font-size:1.5rem}h5,.h5{font-size:1.25rem}h6,.h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}small,.small{font-size:.875em;font-weight:400}mark,.mark{padding:.2em;background-color:#fcf8e3}.list-unstyled,.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:.875em;color:#6c757d}.blockquote-footer:before{content:\"\\2014\\a0\"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code{font-size:87.5%;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container,.container-fluid,.container-sm,.container-md,.container-lg,.container-xl{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width: 576px){.container,.container-sm{max-width:540px}}@media (min-width: 768px){.container,.container-sm,.container-md{max-width:720px}}@media (min-width: 992px){.container,.container-sm,.container-md,.container-lg{max-width:960px}}@media (min-width: 1200px){.container,.container-sm,.container-md,.container-lg,.container-xl{max-width:1140px}}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col-1,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12,.col,.col-auto,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm,.col-sm-auto,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-md,.col-md-auto,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg,.col-lg-auto,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl,.col-xl-auto{position:relative;width:100%;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-3>*{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.row-cols-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-6>*{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-ms-flex-order:-1;order:-1}.order-last{-ms-flex-order:13;order:13}.order-0{-ms-flex-order:0;order:0}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-9{-ms-flex-order:9;order:9}.order-10{-ms-flex-order:10;order:10}.order-11{-ms-flex-order:11;order:11}.order-12{-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width: 576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-sm-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-sm-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-sm-3>*{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.row-cols-sm-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-sm-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-sm-6>*{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-sm-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-ms-flex-order:-1;order:-1}.order-sm-last{-ms-flex-order:13;order:13}.order-sm-0{-ms-flex-order:0;order:0}.order-sm-1{-ms-flex-order:1;order:1}.order-sm-2{-ms-flex-order:2;order:2}.order-sm-3{-ms-flex-order:3;order:3}.order-sm-4{-ms-flex-order:4;order:4}.order-sm-5{-ms-flex-order:5;order:5}.order-sm-6{-ms-flex-order:6;order:6}.order-sm-7{-ms-flex-order:7;order:7}.order-sm-8{-ms-flex-order:8;order:8}.order-sm-9{-ms-flex-order:9;order:9}.order-sm-10{-ms-flex-order:10;order:10}.order-sm-11{-ms-flex-order:11;order:11}.order-sm-12{-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width: 768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-md-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-md-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-md-3>*{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.row-cols-md-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-md-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-md-6>*{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-md-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-ms-flex-order:-1;order:-1}.order-md-last{-ms-flex-order:13;order:13}.order-md-0{-ms-flex-order:0;order:0}.order-md-1{-ms-flex-order:1;order:1}.order-md-2{-ms-flex-order:2;order:2}.order-md-3{-ms-flex-order:3;order:3}.order-md-4{-ms-flex-order:4;order:4}.order-md-5{-ms-flex-order:5;order:5}.order-md-6{-ms-flex-order:6;order:6}.order-md-7{-ms-flex-order:7;order:7}.order-md-8{-ms-flex-order:8;order:8}.order-md-9{-ms-flex-order:9;order:9}.order-md-10{-ms-flex-order:10;order:10}.order-md-11{-ms-flex-order:11;order:11}.order-md-12{-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width: 992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-lg-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-lg-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-lg-3>*{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.row-cols-lg-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-lg-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-lg-6>*{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-lg-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-ms-flex-order:-1;order:-1}.order-lg-last{-ms-flex-order:13;order:13}.order-lg-0{-ms-flex-order:0;order:0}.order-lg-1{-ms-flex-order:1;order:1}.order-lg-2{-ms-flex-order:2;order:2}.order-lg-3{-ms-flex-order:3;order:3}.order-lg-4{-ms-flex-order:4;order:4}.order-lg-5{-ms-flex-order:5;order:5}.order-lg-6{-ms-flex-order:6;order:6}.order-lg-7{-ms-flex-order:7;order:7}.order-lg-8{-ms-flex-order:8;order:8}.order-lg-9{-ms-flex-order:9;order:9}.order-lg-10{-ms-flex-order:10;order:10}.order-lg-11{-ms-flex-order:11;order:11}.order-lg-12{-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width: 1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.row-cols-xl-1>*{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.row-cols-xl-2>*{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.row-cols-xl-3>*{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.row-cols-xl-4>*{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.row-cols-xl-5>*{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.row-cols-xl-6>*{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-xl-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-ms-flex-order:-1;order:-1}.order-xl-last{-ms-flex-order:13;order:13}.order-xl-0{-ms-flex-order:0;order:0}.order-xl-1{-ms-flex-order:1;order:1}.order-xl-2{-ms-flex-order:2;order:2}.order-xl-3{-ms-flex-order:3;order:3}.order-xl-4{-ms-flex-order:4;order:4}.order-xl-5{-ms-flex-order:5;order:5}.order-xl-6{-ms-flex-order:6;order:6}.order-xl-7{-ms-flex-order:7;order:7}.order-xl-8{-ms-flex-order:8;order:8}.order-xl-9{-ms-flex-order:9;order:9}.order-xl-10{-ms-flex-order:10;order:10}.order-xl-11{-ms-flex-order:11;order:11}.order-xl-12{-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.table{width:100%;margin-bottom:1rem;color:#212529}.table th,.table td{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table-sm th,.table-sm td{padding:.3rem}.table-bordered,.table-bordered th,.table-bordered td{border:1px solid #dee2e6}.table-bordered thead th,.table-bordered thead td{border-bottom-width:2px}.table-borderless th,.table-borderless td,.table-borderless thead th,.table-borderless tbody+tbody{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:#0000000d}.table-hover tbody tr:hover{color:#212529;background-color:#00000013}.table-primary,.table-primary>th,.table-primary>td{background-color:#b8daff}.table-primary th,.table-primary td,.table-primary thead th,.table-primary tbody+tbody{border-color:#7abaff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>th,.table-secondary>td{background-color:#d6d8db}.table-secondary th,.table-secondary td,.table-secondary thead th,.table-secondary tbody+tbody{border-color:#b3b7bb}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>th,.table-success>td{background-color:#c3e6cb}.table-success th,.table-success td,.table-success thead th,.table-success tbody+tbody{border-color:#8fd19e}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>th,.table-info>td{background-color:#bee5eb}.table-info th,.table-info td,.table-info thead th,.table-info tbody+tbody{border-color:#86cfda}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>th,.table-warning>td{background-color:#ffeeba}.table-warning th,.table-warning td,.table-warning thead th,.table-warning tbody+tbody{border-color:#ffdf7e}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>th,.table-danger>td{background-color:#f5c6cb}.table-danger th,.table-danger td,.table-danger thead th,.table-danger tbody+tbody{border-color:#ed969e}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>th,.table-light>td{background-color:#fdfdfe}.table-light th,.table-light td,.table-light thead th,.table-light tbody+tbody{border-color:#fbfcfc}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>th,.table-dark>td{background-color:#c6c8ca}.table-dark th,.table-dark td,.table-dark thead th,.table-dark tbody+tbody{border-color:#95999c}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>th,.table-active>td{background-color:#00000013}.table-hover .table-active:hover{background-color:#00000013}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:#00000013}.table .thead-dark th{color:#fff;background-color:#343a40;border-color:#454d55}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#343a40}.table-dark th,.table-dark td,.table-dark thead th{border-color:#454d55}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:#ffffff0d}.table-dark.table-hover tbody tr:hover{color:#fff;background-color:#ffffff13}@media (max-width: 575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-sm>.table-bordered{border:0}}@media (max-width: 767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-md>.table-bordered{border:0}}@media (max-width: 991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-lg>.table-bordered{border:0}}@media (max-width: 1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem #007bff40}.form-control::-webkit-input-placeholder{color:#6c757d;opacity:1}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control:-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{-webkit-appearance:none;-moz-appearance:none;appearance:none}select.form-control:-moz-focusring{color:transparent;text-shadow:0 0 0 #495057}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;font-size:1rem;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{height:calc(1.5em + .5rem + 2px);padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.form-control-lg{height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}select.form-control[size],select.form-control[multiple],textarea.form-control{height:auto}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input[disabled]~.form-check-label,.form-check-input:disabled~.form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#28a745}.valid-tooltip{position:absolute;top:100%;left:0;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:#28a745e6;border-radius:.25rem}.form-row>.col>.valid-tooltip,.form-row>[class*=col-]>.valid-tooltip{left:5px}.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip,.is-valid~.valid-feedback,.is-valid~.valid-tooltip{display:block}.was-validated .form-control:valid,.form-control.is-valid{border-color:#28a745;padding-right:calc(1.5em + .75rem)!important;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e\");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem #28a74540}.was-validated select.form-control:valid,select.form-control.is-valid{padding-right:3rem!important;background-position:right 1.5rem center}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.was-validated .custom-select:valid,.custom-select.is-valid{border-color:#28a745;padding-right:calc(.75em + 2.3125rem)!important;background:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e\") right .75rem center/8px 10px no-repeat,#fff url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e\") center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem) no-repeat}.was-validated .custom-select:valid:focus,.custom-select.is-valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem #28a74540}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:#28a745}.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip,.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip{display:block}.was-validated .custom-control-input:valid~.custom-control-label,.custom-control-input.is-valid~.custom-control-label{color:#28a745}.was-validated .custom-control-input:valid~.custom-control-label:before,.custom-control-input.is-valid~.custom-control-label:before{border-color:#28a745}.was-validated .custom-control-input:valid:checked~.custom-control-label:before,.custom-control-input.is-valid:checked~.custom-control-label:before{border-color:#34ce57;background-color:#34ce57}.was-validated .custom-control-input:valid:focus~.custom-control-label:before,.custom-control-input.is-valid:focus~.custom-control-label:before{box-shadow:0 0 0 .2rem #28a74540}.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label:before,.custom-control-input.is-valid:focus:not(:checked)~.custom-control-label:before{border-color:#28a745}.was-validated .custom-file-input:valid~.custom-file-label,.custom-file-input.is-valid~.custom-file-label{border-color:#28a745}.was-validated .custom-file-input:valid:focus~.custom-file-label,.custom-file-input.is-valid:focus~.custom-file-label{border-color:#28a745;box-shadow:0 0 0 .2rem #28a74540}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;left:0;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:#dc3545e6;border-radius:.25rem}.form-row>.col>.invalid-tooltip,.form-row>[class*=col-]>.invalid-tooltip{left:5px}.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip,.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip{display:block}.was-validated .form-control:invalid,.form-control.is-invalid{border-color:#dc3545;padding-right:calc(1.5em + .75rem)!important;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e\");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem #dc354540}.was-validated select.form-control:invalid,select.form-control.is-invalid{padding-right:3rem!important;background-position:right 1.5rem center}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.was-validated .custom-select:invalid,.custom-select.is-invalid{border-color:#dc3545;padding-right:calc(.75em + 2.3125rem)!important;background:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e\") right .75rem center/8px 10px no-repeat,#fff url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e\") center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem) no-repeat}.was-validated .custom-select:invalid:focus,.custom-select.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem #dc354540}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:#dc3545}.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip,.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip{display:block}.was-validated .custom-control-input:invalid~.custom-control-label,.custom-control-input.is-invalid~.custom-control-label{color:#dc3545}.was-validated .custom-control-input:invalid~.custom-control-label:before,.custom-control-input.is-invalid~.custom-control-label:before{border-color:#dc3545}.was-validated .custom-control-input:invalid:checked~.custom-control-label:before,.custom-control-input.is-invalid:checked~.custom-control-label:before{border-color:#e4606d;background-color:#e4606d}.was-validated .custom-control-input:invalid:focus~.custom-control-label:before,.custom-control-input.is-invalid:focus~.custom-control-label:before{box-shadow:0 0 0 .2rem #dc354540}.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label:before,.custom-control-input.is-invalid:focus:not(:checked)~.custom-control-label:before{border-color:#dc3545}.was-validated .custom-file-input:invalid~.custom-file-label,.custom-file-input.is-invalid~.custom-file-label{border-color:#dc3545}.was-validated .custom-file-input:invalid:focus~.custom-file-label,.custom-file-input.is-invalid:focus~.custom-file-label{border-color:#dc3545;box-shadow:0 0 0 .2rem #dc354540}.form-inline{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width: 576px){.form-inline label{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-ms-flexbox;display:flex;-ms-flex:0 0 auto;flex:0 0 auto;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .input-group,.form-inline .custom-select{width:auto}.form-inline .form-check{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;-ms-flex-negative:0;flex-shrink:0;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;color:#212529;text-align:center;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.btn{transition:none}}.btn:hover{color:#212529;text-decoration:none}.btn:focus,.btn.focus{outline:0;box-shadow:0 0 0 .2rem #007bff40}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary:focus,.btn-primary.focus{color:#fff;background-color:#0069d9;border-color:#0062cc;box-shadow:0 0 0 .2rem #268fff80}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled):active,.btn-primary:not(:disabled):not(.disabled).active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled):active:focus,.btn-primary:not(:disabled):not(.disabled).active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem #268fff80}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary:focus,.btn-secondary.focus{color:#fff;background-color:#5a6268;border-color:#545b62;box-shadow:0 0 0 .2rem #828a9180}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled):active,.btn-secondary:not(:disabled):not(.disabled).active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled):active:focus,.btn-secondary:not(:disabled):not(.disabled).active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem #828a9180}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success:focus,.btn-success.focus{color:#fff;background-color:#218838;border-color:#1e7e34;box-shadow:0 0 0 .2rem #48b46180}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled):active,.btn-success:not(:disabled):not(.disabled).active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled):active:focus,.btn-success:not(:disabled):not(.disabled).active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem #48b46180}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info:focus,.btn-info.focus{color:#fff;background-color:#138496;border-color:#117a8b;box-shadow:0 0 0 .2rem #3ab0c380}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled):active,.btn-info:not(:disabled):not(.disabled).active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled):active:focus,.btn-info:not(:disabled):not(.disabled).active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem #3ab0c380}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning:focus,.btn-warning.focus{color:#212529;background-color:#e0a800;border-color:#d39e00;box-shadow:0 0 0 .2rem #deaa0c80}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled):active,.btn-warning:not(:disabled):not(.disabled).active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled):active:focus,.btn-warning:not(:disabled):not(.disabled).active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem #deaa0c80}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger:focus,.btn-danger.focus{color:#fff;background-color:#c82333;border-color:#bd2130;box-shadow:0 0 0 .2rem #e1536180}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled):active,.btn-danger:not(:disabled):not(.disabled).active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled):active:focus,.btn-danger:not(:disabled):not(.disabled).active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem #e1536180}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light:focus,.btn-light.focus{color:#212529;background-color:#e2e6ea;border-color:#dae0e5;box-shadow:0 0 0 .2rem #d8d9db80}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled):active,.btn-light:not(:disabled):not(.disabled).active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled):active:focus,.btn-light:not(:disabled):not(.disabled).active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem #d8d9db80}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark:focus,.btn-dark.focus{color:#fff;background-color:#23272b;border-color:#1d2124;box-shadow:0 0 0 .2rem #52585d80}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled):active,.btn-dark:not(:disabled):not(.disabled).active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled):active:focus,.btn-dark:not(:disabled):not(.disabled).active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem #52585d80}.btn-outline-primary{color:#007bff;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:focus,.btn-outline-primary.focus{box-shadow:0 0 0 .2rem #007bff80}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled):active,.btn-outline-primary:not(:disabled):not(.disabled).active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem #007bff80}.btn-outline-secondary{color:#6c757d;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:focus,.btn-outline-secondary.focus{box-shadow:0 0 0 .2rem #6c757d80}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled):active,.btn-outline-secondary:not(:disabled):not(.disabled).active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem #6c757d80}.btn-outline-success{color:#28a745;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:focus,.btn-outline-success.focus{box-shadow:0 0 0 .2rem #28a74580}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled):active,.btn-outline-success:not(:disabled):not(.disabled).active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled):active:focus,.btn-outline-success:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem #28a74580}.btn-outline-info{color:#17a2b8;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:focus,.btn-outline-info.focus{box-shadow:0 0 0 .2rem #17a2b880}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled):active,.btn-outline-info:not(:disabled):not(.disabled).active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled):active:focus,.btn-outline-info:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem #17a2b880}.btn-outline-warning{color:#ffc107;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:focus,.btn-outline-warning.focus{box-shadow:0 0 0 .2rem #ffc10780}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled):active,.btn-outline-warning:not(:disabled):not(.disabled).active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem #ffc10780}.btn-outline-danger{color:#dc3545;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:focus,.btn-outline-danger.focus{box-shadow:0 0 0 .2rem #dc354580}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled):active,.btn-outline-danger:not(:disabled):not(.disabled).active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem #dc354580}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:focus,.btn-outline-light.focus{box-shadow:0 0 0 .2rem #f8f9fa80}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled):active,.btn-outline-light:not(:disabled):not(.disabled).active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled):active:focus,.btn-outline-light:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem #f8f9fa80}.btn-outline-dark{color:#343a40;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:focus,.btn-outline-dark.focus{box-shadow:0 0 0 .2rem #343a4080}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled):active,.btn-outline-dark:not(:disabled):not(.disabled).active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem #343a4080}.btn-link{font-weight:400;color:#007bff;text-decoration:none}.btn-link:hover{color:#0056b3;text-decoration:underline}.btn-link:focus,.btn-link.focus{text-decoration:underline}.btn-link:disabled,.btn-link.disabled{color:#6c757d;pointer-events:none}.btn-lg,.btn-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-sm,.btn-group-sm>.btn{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion: reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion: reduce){.collapsing{transition:none}}.collapsing.width{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion: reduce){.collapsing.width{transition:none}}.dropup,.dropright,.dropdown,.dropleft{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:\"\";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty:after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu-left{right:auto;left:0}.dropdown-menu-right{right:0;left:auto}@media (min-width: 576px){.dropdown-menu-sm-left{right:auto;left:0}.dropdown-menu-sm-right{right:0;left:auto}}@media (min-width: 768px){.dropdown-menu-md-left{right:auto;left:0}.dropdown-menu-md-right{right:0;left:auto}}@media (min-width: 992px){.dropdown-menu-lg-left{right:auto;left:0}.dropdown-menu-lg-right{right:0;left:auto}}@media (min-width: 1200px){.dropdown-menu-xl-left{right:auto;left:0}.dropdown-menu-xl-right{right:0;left:auto}}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:\"\";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty:after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:\"\";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty:after{margin-left:0}.dropright .dropdown-toggle:after{vertical-align:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:\"\"}.dropleft .dropdown-toggle:after{display:none}.dropleft .dropdown-toggle:before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:\"\";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty:after{margin-left:0}.dropleft .dropdown-toggle:before{vertical-align:0}.dropdown-menu[x-placement^=top],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:hover,.dropdown-item:focus{color:#16181b;text-decoration:none;background-color:#e9ecef}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#212529}.btn-group,.btn-group-vertical{position:relative;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;-ms-flex:1 1 auto;flex:1 1 auto}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover{z-index:1}.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:not(:first-child),.btn-group>.btn-group:not(:first-child){margin-left:-1px}.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.btn-group>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:not(:first-child),.btn-group>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split:after,.dropup .dropdown-toggle-split:after,.dropright .dropdown-toggle-split:after{margin-left:0}.dropleft .dropdown-toggle-split:before{margin-right:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:center;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle),.btn-group-vertical>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:stretch;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-control-plaintext,.input-group>.custom-select,.input-group>.custom-file{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;min-width:0;margin-bottom:0}.input-group>.form-control+.form-control,.input-group>.form-control+.custom-select,.input-group>.form-control+.custom-file,.input-group>.form-control-plaintext+.form-control,.input-group>.form-control-plaintext+.custom-select,.input-group>.form-control-plaintext+.custom-file,.input-group>.custom-select+.form-control,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.custom-file,.input-group>.custom-file+.form-control,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.custom-file{margin-left:-1px}.input-group>.form-control:focus,.input-group>.custom-select:focus,.input-group>.custom-file .custom-file-input:focus~.custom-file-label{z-index:3}.input-group>.custom-file .custom-file-input:focus{z-index:4}.input-group>.form-control:not(:first-child),.input-group>.custom-select:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label:after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label{border-top-left-radius:0;border-bottom-left-radius:0}.input-group:not(.has-validation)>.form-control:not(:last-child),.input-group:not(.has-validation)>.custom-select:not(:last-child),.input-group:not(.has-validation)>.custom-file:not(:last-child) .custom-file-label,.input-group:not(.has-validation)>.custom-file:not(:last-child) .custom-file-label:after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.form-control:nth-last-child(n + 3),.input-group.has-validation>.custom-select:nth-last-child(n + 3),.input-group.has-validation>.custom-file:nth-last-child(n + 3) .custom-file-label,.input-group.has-validation>.custom-file:nth-last-child(n + 3) .custom-file-label:after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group-prepend,.input-group-append{display:-ms-flexbox;display:flex}.input-group-prepend .btn,.input-group-append .btn{position:relative;z-index:2}.input-group-prepend .btn:focus,.input-group-append .btn:focus{z-index:3}.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.input-group-text,.input-group-append .input-group-text+.btn{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type=radio],.input-group-text input[type=checkbox]{margin-top:0}.input-group-lg>.form-control:not(textarea),.input-group-lg>.custom-select{height:calc(1.5em + 1rem + 2px)}.input-group-lg>.form-control,.input-group-lg>.custom-select,.input-group-lg>.input-group-prepend>.input-group-text,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-append>.btn{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-sm>.form-control:not(textarea),.input-group-sm>.custom-select{height:calc(1.5em + .5rem + 2px)}.input-group-sm>.form-control,.input-group-sm>.custom-select,.input-group-sm>.input-group-prepend>.input-group-text,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-append>.btn{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-lg>.custom-select,.input-group-sm>.custom-select{padding-right:1.75rem}.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text,.input-group:not(.has-validation)>.input-group-append:not(:last-child)>.btn,.input-group:not(.has-validation)>.input-group-append:not(:last-child)>.input-group-text,.input-group.has-validation>.input-group-append:nth-last-child(n + 3)>.btn,.input-group.has-validation>.input-group-append:nth-last-child(n + 3)>.input-group-text,.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;z-index:1;display:block;min-height:1.5rem;padding-left:1.5rem;-webkit-print-color-adjust:exact;color-adjust:exact;print-color-adjust:exact}.custom-control-inline{display:-ms-inline-flexbox;display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;left:0;z-index:-1;width:1rem;height:1.25rem;opacity:0}.custom-control-input:checked~.custom-control-label:before{color:#fff;border-color:#007bff;background-color:#007bff}.custom-control-input:focus~.custom-control-label:before{box-shadow:0 0 0 .2rem #007bff40}.custom-control-input:focus:not(:checked)~.custom-control-label:before{border-color:#80bdff}.custom-control-input:not(:disabled):active~.custom-control-label:before{color:#fff;background-color:#b3d7ff;border-color:#b3d7ff}.custom-control-input[disabled]~.custom-control-label,.custom-control-input:disabled~.custom-control-label{color:#6c757d}.custom-control-input[disabled]~.custom-control-label:before,.custom-control-input:disabled~.custom-control-label:before{background-color:#e9ecef}.custom-control-label{position:relative;margin-bottom:0;vertical-align:top}.custom-control-label:before{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;pointer-events:none;content:\"\";background-color:#fff;border:1px solid #adb5bd}.custom-control-label:after{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:\"\";background:50% / 50% 50% no-repeat}.custom-checkbox .custom-control-label:before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3e%3c/svg%3e\")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label:before{border-color:#007bff;background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e\")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label:before{background-color:#007bff80}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label:before{background-color:#007bff80}.custom-radio .custom-control-label:before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e\")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label:before{background-color:#007bff80}.custom-switch{padding-left:2.25rem}.custom-switch .custom-control-label:before{left:-2.25rem;width:1.75rem;pointer-events:all;border-radius:.5rem}.custom-switch .custom-control-label:after{top:calc(.25rem + 2px);left:calc(-2.25rem + 2px);width:calc(1rem - 4px);height:calc(1rem - 4px);background-color:#adb5bd;border-radius:.5rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out}@media (prefers-reduced-motion: reduce){.custom-switch .custom-control-label:after{transition:none}}.custom-switch .custom-control-input:checked~.custom-control-label:after{background-color:#fff;-webkit-transform:translateX(.75rem);transform:translate(.75rem)}.custom-switch .custom-control-input:disabled:checked~.custom-control-label:before{background-color:#007bff80}.custom-select{display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem 1.75rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;vertical-align:middle;background:#fff url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e\") right .75rem center/8px 10px no-repeat;border:1px solid #ced4da;border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem #007bff40}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size=\"1\"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{display:none}.custom-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #495057}.custom-select-sm{height:calc(1.5em + .5rem + 2px);padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem}.custom-select-lg{height:calc(1.5em + 1rem + 2px);padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.custom-file{position:relative;display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(1.5em + .75rem + 2px);margin:0;overflow:hidden;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#80bdff;box-shadow:0 0 0 .2rem #007bff40}.custom-file-input[disabled]~.custom-file-label,.custom-file-input:disabled~.custom-file-label{background-color:#e9ecef}.custom-file-input:lang(en)~.custom-file-label:after{content:\"Browse\"}.custom-file-input~.custom-file-label[data-browse]:after{content:attr(data-browse)}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;overflow:hidden;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label:after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:calc(1.5em + .75rem);padding:.375rem .75rem;line-height:1.5;color:#495057;content:\"Browse\";background-color:#e9ecef;border-left:inherit;border-radius:0 .25rem .25rem 0}.custom-range{width:100%;height:1.4rem;padding:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-range:focus{outline:0}.custom-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem #007bff40}.custom-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem #007bff40}.custom-range:focus::-ms-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem #007bff40}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#007bff;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion: reduce){.custom-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.custom-range::-webkit-slider-thumb:active{background-color:#b3d7ff}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#007bff;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion: reduce){.custom-range::-moz-range-thumb{-moz-transition:none;transition:none}}.custom-range::-moz-range-thumb:active{background-color:#b3d7ff}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-ms-thumb{width:1rem;height:1rem;margin-top:0;margin-right:.2rem;margin-left:.2rem;background-color:#007bff;border:0;border-radius:1rem;-ms-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media (prefers-reduced-motion: reduce){.custom-range::-ms-thumb{-ms-transition:none;transition:none}}.custom-range::-ms-thumb:active{background-color:#b3d7ff}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem}.custom-range::-ms-fill-lower{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:15px;background-color:#dee2e6;border-radius:1rem}.custom-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.custom-range:disabled::-webkit-slider-runnable-track{cursor:default}.custom-range:disabled::-moz-range-thumb{background-color:#adb5bd}.custom-range:disabled::-moz-range-track{cursor:default}.custom-range:disabled::-ms-thumb{background-color:#adb5bd}.custom-control-label:before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.custom-control-label:before,.custom-file-label,.custom-select{transition:none}}.nav{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:hover,.nav-link:focus{text-decoration:none}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{margin-bottom:-1px;background-color:transparent;border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{isolation:isolate;border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{background:none;border:0;border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill>.nav-link,.nav-fill .nav-item{-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified>.nav-link,.nav-justified .nav-item{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar .container,.navbar .container-fluid,.navbar .container-sm,.navbar .container-md,.navbar .container-lg,.navbar .container-xl{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}.navbar-nav{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:hover,.navbar-toggler:focus{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:\"\";background:50% / 100% 100% no-repeat}.navbar-nav-scroll{max-height:75vh;overflow-y:auto}@media (max-width: 575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-xl{padding-right:0;padding-left:0}}@media (min-width: 576px){.navbar-expand-sm{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width: 767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-md,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-xl{padding-right:0;padding-left:0}}@media (min-width: 768px){.navbar-expand-md{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-md,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width: 991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-xl{padding-right:0;padding-left:0}}@media (min-width: 992px){.navbar-expand-lg{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width: 1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-xl{padding-right:0;padding-left:0}}@media (min-width: 1200px){.navbar-expand-xl{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-sm,.navbar-expand>.container-md,.navbar-expand>.container-lg,.navbar-expand>.container-xl{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-sm,.navbar-expand>.container-md,.navbar-expand>.container-lg,.navbar-expand>.container-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:#000000e6}.navbar-light .navbar-brand:hover,.navbar-light .navbar-brand:focus{color:#000000e6}.navbar-light .navbar-nav .nav-link{color:#00000080}.navbar-light .navbar-nav .nav-link:hover,.navbar-light .navbar-nav .nav-link:focus{color:#000000b3}.navbar-light .navbar-nav .nav-link.disabled{color:#0000004d}.navbar-light .navbar-nav .show>.nav-link,.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .nav-link.active{color:#000000e6}.navbar-light .navbar-toggler{color:#00000080;border-color:#0000001a}.navbar-light .navbar-toggler-icon{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.5%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e\")}.navbar-light .navbar-text{color:#00000080}.navbar-light .navbar-text a{color:#000000e6}.navbar-light .navbar-text a:hover,.navbar-light .navbar-text a:focus{color:#000000e6}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:hover,.navbar-dark .navbar-brand:focus{color:#fff}.navbar-dark .navbar-nav .nav-link{color:#ffffff80}.navbar-dark .navbar-nav .nav-link:hover,.navbar-dark .navbar-nav .nav-link:focus{color:#ffffffbf}.navbar-dark .navbar-nav .nav-link.disabled{color:#ffffff40}.navbar-dark .navbar-nav .show>.nav-link,.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .nav-link.active{color:#fff}.navbar-dark .navbar-toggler{color:#ffffff80;border-color:#ffffff1a}.navbar-dark .navbar-toggler-icon{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.5%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e\")}.navbar-dark .navbar-text{color:#ffffff80}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:hover,.navbar-dark .navbar-text a:focus{color:#fff}.card{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{-ms-flex:1 1 auto;flex:1 1 auto;min-height:1px;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:#00000008;border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{padding:.75rem 1.25rem;background-color:#00000008;border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem;border-radius:calc(.25rem - 1px)}.card-img,.card-img-top,.card-img-bottom{-ms-flex-negative:0;flex-shrink:0;width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck .card{margin-bottom:15px}@media (min-width: 576px){.card-deck{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{-ms-flex:1 0 0%;flex:1 0 0%;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group>.card{margin-bottom:15px}@media (min-width: 576px){.card-group{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group>.card{-ms-flex:1 0 0%;flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-img-top,.card-group>.card:not(:last-child) .card-header{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-img-bottom,.card-group>.card:not(:last-child) .card-footer{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-img-top,.card-group>.card:not(:first-child) .card-header{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-img-bottom,.card-group>.card:not(:first-child) .card-footer{border-bottom-left-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width: 576px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.accordion{overflow-anchor:none}.accordion>.card{overflow:hidden}.accordion>.card:not(:last-of-type){border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion>.card:not(:first-of-type){border-top-left-radius:0;border-top-right-radius:0}.accordion>.card>.card-header{border-radius:0;margin-bottom:-1px}.breadcrumb{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item:before{float:left;padding-right:.5rem;color:#6c757d;content:\"/\"}.breadcrumb-item+.breadcrumb-item:hover:before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover:before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{z-index:2;color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;outline:0;box-shadow:0 0 0 .2rem #007bff40}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:3;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.badge{transition:none}}a.badge:hover,a.badge:focus{text-decoration:none}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}a.badge-primary:hover,a.badge-primary:focus{color:#fff;background-color:#0062cc}a.badge-primary:focus,a.badge-primary.focus{outline:0;box-shadow:0 0 0 .2rem #007bff80}.badge-secondary{color:#fff;background-color:#6c757d}a.badge-secondary:hover,a.badge-secondary:focus{color:#fff;background-color:#545b62}a.badge-secondary:focus,a.badge-secondary.focus{outline:0;box-shadow:0 0 0 .2rem #6c757d80}.badge-success{color:#fff;background-color:#28a745}a.badge-success:hover,a.badge-success:focus{color:#fff;background-color:#1e7e34}a.badge-success:focus,a.badge-success.focus{outline:0;box-shadow:0 0 0 .2rem #28a74580}.badge-info{color:#fff;background-color:#17a2b8}a.badge-info:hover,a.badge-info:focus{color:#fff;background-color:#117a8b}a.badge-info:focus,a.badge-info.focus{outline:0;box-shadow:0 0 0 .2rem #17a2b880}.badge-warning{color:#212529;background-color:#ffc107}a.badge-warning:hover,a.badge-warning:focus{color:#212529;background-color:#d39e00}a.badge-warning:focus,a.badge-warning.focus{outline:0;box-shadow:0 0 0 .2rem #ffc10780}.badge-danger{color:#fff;background-color:#dc3545}a.badge-danger:hover,a.badge-danger:focus{color:#fff;background-color:#bd2130}a.badge-danger:focus,a.badge-danger.focus{outline:0;box-shadow:0 0 0 .2rem #dc354580}.badge-light{color:#212529;background-color:#f8f9fa}a.badge-light:hover,a.badge-light:focus{color:#212529;background-color:#dae0e5}a.badge-light:focus,a.badge-light.focus{outline:0;box-shadow:0 0 0 .2rem #f8f9fa80}.badge-dark{color:#fff;background-color:#343a40}a.badge-dark:hover,a.badge-dark:focus{color:#fff;background-color:#1d2124}a.badge-dark:focus,a.badge-dark.focus{outline:0;box-shadow:0 0 0 .2rem #343a4080}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width: 576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;z-index:2;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes progress-bar-stripes{0%{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{0%{background-position:1rem 0}to{background-position:0 0}}.progress{display:-ms-flexbox;display:flex;height:1rem;overflow:hidden;line-height:0;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#007bff;transition:width .6s ease}@media (prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:1s linear infinite progress-bar-stripes;animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion: reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.media{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start}.media-body{-ms-flex:1;flex:1}.list-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media (min-width: 576px){.list-group-horizontal-sm{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width: 768px){.list-group-horizontal-md{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width: 992px){.list-group-horizontal-lg{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width: 1200px){.list-group-horizontal-xl{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:hover,.list-group-item-primary.list-group-item-action:focus{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:hover,.list-group-item-secondary.list-group-item-action:focus{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:hover,.list-group-item-success.list-group-item-action:focus{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:hover,.list-group-item-info.list-group-item-action:focus{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:hover,.list-group-item-warning.list-group-item-action:focus{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:hover,.list-group-item-danger.list-group-item-action:focus{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:hover,.list-group-item-light.list-group-item-action:focus{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:hover,.list-group-item-dark.list-group-item-action:focus{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:hover{color:#000;text-decoration:none}.close:not(:disabled):not(.disabled):hover,.close:not(:disabled):not(.disabled):focus{opacity:.75}button.close{padding:0;background-color:transparent;border:0}a.close.disabled{pointer-events:none}.toast{-ms-flex-preferred-size:350px;flex-basis:350px;max-width:350px;font-size:.875rem;background-color:#ffffffd9;background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .25rem .75rem #0000001a;opacity:0;border-radius:.25rem}.toast:not(:last-child){margin-bottom:.75rem}.toast.showing{opacity:1}.toast.show{display:block;opacity:1}.toast.hide{display:none}.toast-header{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.25rem .75rem;color:#6c757d;background-color:#ffffffd9;background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05);border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.toast-body{padding:.75rem}.modal-open{overflow:hidden}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal{position:fixed;top:0;left:0;z-index:1050;display:none;width:100%;height:100%;overflow:hidden;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-50px);transform:translateY(-50px)}@media (prefers-reduced-motion: reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{-webkit-transform:none;transform:none}.modal.modal-static .modal-dialog{-webkit-transform:scale(1.02);transform:scale(1.02)}.modal-dialog-scrollable{display:-ms-flexbox;display:flex;max-height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 1rem);overflow:hidden}.modal-dialog-scrollable .modal-header,.modal-dialog-scrollable .modal-footer{-ms-flex-negative:0;flex-shrink:0}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;min-height:calc(100% - 1rem)}.modal-dialog-centered:before{display:block;height:calc(100vh - 1rem);height:-webkit-min-content;height:-moz-min-content;height:min-content;content:\"\"}.modal-dialog-centered.modal-dialog-scrollable{-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;height:100%}.modal-dialog-centered.modal-dialog-scrollable .modal-content{max-height:none}.modal-dialog-centered.modal-dialog-scrollable:before{content:none}.modal-content{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:justify;justify-content:space-between;padding:1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.modal-header .close{padding:1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-footer{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:end;justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6;border-bottom-right-radius:calc(.3rem - 1px);border-bottom-left-radius:calc(.3rem - 1px)}.modal-footer>*{margin:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width: 576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{max-height:calc(100% - 3.5rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-dialog-centered:before{height:calc(100vh - 3.5rem);height:-webkit-min-content;height:-moz-min-content;height:min-content}.modal-sm{max-width:300px}}@media (min-width: 992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width: 1200px){.modal-xl{max-width:1140px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,Liberation Sans,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol,\"Noto Color Emoji\";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow:before{position:absolute;content:\"\";border-color:transparent;border-style:solid}.bs-tooltip-top,.bs-tooltip-auto[x-placement^=top]{padding:.4rem 0}.bs-tooltip-top .arrow,.bs-tooltip-auto[x-placement^=top] .arrow{bottom:0}.bs-tooltip-top .arrow:before,.bs-tooltip-auto[x-placement^=top] .arrow:before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-right,.bs-tooltip-auto[x-placement^=right]{padding:0 .4rem}.bs-tooltip-right .arrow,.bs-tooltip-auto[x-placement^=right] .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-right .arrow:before,.bs-tooltip-auto[x-placement^=right] .arrow:before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-bottom,.bs-tooltip-auto[x-placement^=bottom]{padding:.4rem 0}.bs-tooltip-bottom .arrow,.bs-tooltip-auto[x-placement^=bottom] .arrow{top:0}.bs-tooltip-bottom .arrow:before,.bs-tooltip-auto[x-placement^=bottom] .arrow:before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-left,.bs-tooltip-auto[x-placement^=left]{padding:0 .4rem}.bs-tooltip-left .arrow,.bs-tooltip-auto[x-placement^=left] .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-left .arrow:before,.bs-tooltip-auto[x-placement^=left] .arrow:before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,Liberation Sans,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol,\"Noto Color Emoji\";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow:before,.popover .arrow:after{position:absolute;display:block;content:\"\";border-color:transparent;border-style:solid}.bs-popover-top,.bs-popover-auto[x-placement^=top]{margin-bottom:.5rem}.bs-popover-top>.arrow,.bs-popover-auto[x-placement^=top]>.arrow{bottom:calc(-.5rem - 1px)}.bs-popover-top>.arrow:before,.bs-popover-auto[x-placement^=top]>.arrow:before{bottom:0;border-width:.5rem .5rem 0;border-top-color:#00000040}.bs-popover-top>.arrow:after,.bs-popover-auto[x-placement^=top]>.arrow:after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-right,.bs-popover-auto[x-placement^=right]{margin-left:.5rem}.bs-popover-right>.arrow,.bs-popover-auto[x-placement^=right]>.arrow{left:calc(-.5rem - 1px);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-right>.arrow:before,.bs-popover-auto[x-placement^=right]>.arrow:before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:#00000040}.bs-popover-right>.arrow:after,.bs-popover-auto[x-placement^=right]>.arrow:after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-bottom,.bs-popover-auto[x-placement^=bottom]{margin-top:.5rem}.bs-popover-bottom>.arrow,.bs-popover-auto[x-placement^=bottom]>.arrow{top:calc(-.5rem - 1px)}.bs-popover-bottom>.arrow:before,.bs-popover-auto[x-placement^=bottom]>.arrow:before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:#00000040}.bs-popover-bottom>.arrow:after,.bs-popover-auto[x-placement^=bottom]>.arrow:after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-bottom .popover-header:before,.bs-popover-auto[x-placement^=bottom] .popover-header:before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:\"\";border-bottom:1px solid #f7f7f7}.bs-popover-left,.bs-popover-auto[x-placement^=left]{margin-right:.5rem}.bs-popover-left>.arrow,.bs-popover-auto[x-placement^=left]>.arrow{right:calc(-.5rem - 1px);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-left>.arrow:before,.bs-popover-auto[x-placement^=left]>.arrow:before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:#00000040}.bs-popover-left>.arrow:after,.bs-popover-auto[x-placement^=left]>.arrow:after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{-ms-touch-action:pan-y;touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner:after{display:block;clear:both;content:\"\"}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:-webkit-transform .6s ease-in-out;transition:transform .6s ease-in-out;transition:transform .6s ease-in-out,-webkit-transform .6s ease-in-out}@media (prefers-reduced-motion: reduce){.carousel-item{transition:none}}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-left),.active.carousel-item-right{-webkit-transform:translateX(100%);transform:translate(100%)}.carousel-item-prev:not(.carousel-item-right),.active.carousel-item-left{-webkit-transform:translateX(-100%);transform:translate(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;-webkit-transform:none;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right{z-index:1;opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion: reduce){.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{transition:none}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;z-index:1;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:none;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion: reduce){.carousel-control-prev,.carousel-control-next{transition:none}}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:20px;height:20px;background:50% / 100% 100% no-repeat}.carousel-control-prev-icon{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%3e%3c/svg%3e\")}.carousel-control-next-icon{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5L3.75 4l-2.5 2.5L2.75 8l4-4-4-4z'/%3e%3c/svg%3e\")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:15;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{box-sizing:content-box;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion: reduce){.carousel-indicators li{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}@-webkit-keyframes spinner-border{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spinner-border{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;border:.25em solid currentcolor;border-right-color:transparent;border-radius:50%;-webkit-animation:.75s linear infinite spinner-border;animation:.75s linear infinite spinner-border}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@-webkit-keyframes spinner-grow{0%{-webkit-transform:scale(0);transform:scale(0)}50%{opacity:1;-webkit-transform:none;transform:none}}@keyframes spinner-grow{0%{-webkit-transform:scale(0);transform:scale(0)}50%{opacity:1;-webkit-transform:none;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;background-color:currentcolor;border-radius:50%;opacity:0;-webkit-animation:.75s linear infinite spinner-grow;animation:.75s linear infinite spinner-grow}.spinner-grow-sm{width:1rem;height:1rem}@media (prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{-webkit-animation-duration:1.5s;animation-duration:1.5s}}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:hover,a.bg-primary:focus,button.bg-primary:hover,button.bg-primary:focus{background-color:#0062cc!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:hover,a.bg-secondary:focus,button.bg-secondary:hover,button.bg-secondary:focus{background-color:#545b62!important}.bg-success{background-color:#28a745!important}a.bg-success:hover,a.bg-success:focus,button.bg-success:hover,button.bg-success:focus{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:hover,a.bg-info:focus,button.bg-info:hover,button.bg-info:focus{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:hover,a.bg-warning:focus,button.bg-warning:hover,button.bg-warning:focus{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:hover,a.bg-danger:focus,button.bg-danger:hover,button.bg-danger:focus{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:hover,a.bg-light:focus,button.bg-light:hover,button.bg-light:focus{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:hover,a.bg-dark:focus,button.bg-dark:hover,button.bg-dark:focus{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded-sm{border-radius:.2rem!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-lg{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-0{border-radius:0!important}.clearfix:after{display:block;clear:both;content:\"\"}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width: 576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width: 768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width: 992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width: 1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive:before{display:block;content:\"\"}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9:before{padding-top:42.857143%}.embed-responsive-16by9:before{padding-top:56.25%}.embed-responsive-4by3:before{padding-top:75%}.embed-responsive-1by1:before{padding-top:100%}.flex-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width: 576px){.flex-sm-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-sm-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-sm-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-sm-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-sm-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-sm-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-sm-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width: 768px){.flex-md-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-md-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-md-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-md-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-md-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-md-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-md-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width: 992px){.flex-lg-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-lg-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-lg-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-lg-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-lg-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-lg-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-lg-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width: 1200px){.flex-xl-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-xl-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-xl-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-xl-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-xl-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-xl-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-xl-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width: 576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width: 768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width: 992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width: 1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;-ms-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;-ms-user-select:none!important;user-select:none!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position: -webkit-sticky) or (position: sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal}.shadow-sm{box-shadow:0 .125rem .25rem #00000013!important}.shadow{box-shadow:0 .5rem 1rem #00000026!important}.shadow-lg{box-shadow:0 1rem 3rem #0000002d!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.min-vw-100{min-width:100vw!important}.min-vh-100{min-height:100vh!important}.vw-100{width:100vw!important}.vh-100{height:100vh!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-n1{margin:-.25rem!important}.mt-n1,.my-n1{margin-top:-.25rem!important}.mr-n1,.mx-n1{margin-right:-.25rem!important}.mb-n1,.my-n1{margin-bottom:-.25rem!important}.ml-n1,.mx-n1{margin-left:-.25rem!important}.m-n2{margin:-.5rem!important}.mt-n2,.my-n2{margin-top:-.5rem!important}.mr-n2,.mx-n2{margin-right:-.5rem!important}.mb-n2,.my-n2{margin-bottom:-.5rem!important}.ml-n2,.mx-n2{margin-left:-.5rem!important}.m-n3{margin:-1rem!important}.mt-n3,.my-n3{margin-top:-1rem!important}.mr-n3,.mx-n3{margin-right:-1rem!important}.mb-n3,.my-n3{margin-bottom:-1rem!important}.ml-n3,.mx-n3{margin-left:-1rem!important}.m-n4{margin:-1.5rem!important}.mt-n4,.my-n4{margin-top:-1.5rem!important}.mr-n4,.mx-n4{margin-right:-1.5rem!important}.mb-n4,.my-n4{margin-bottom:-1.5rem!important}.ml-n4,.mx-n4{margin-left:-1.5rem!important}.m-n5{margin:-3rem!important}.mt-n5,.my-n5{margin-top:-3rem!important}.mr-n5,.mx-n5{margin-right:-3rem!important}.mb-n5,.my-n5{margin-bottom:-3rem!important}.ml-n5,.mx-n5{margin-left:-3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width: 576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-n1{margin:-.25rem!important}.mt-sm-n1,.my-sm-n1{margin-top:-.25rem!important}.mr-sm-n1,.mx-sm-n1{margin-right:-.25rem!important}.mb-sm-n1,.my-sm-n1{margin-bottom:-.25rem!important}.ml-sm-n1,.mx-sm-n1{margin-left:-.25rem!important}.m-sm-n2{margin:-.5rem!important}.mt-sm-n2,.my-sm-n2{margin-top:-.5rem!important}.mr-sm-n2,.mx-sm-n2{margin-right:-.5rem!important}.mb-sm-n2,.my-sm-n2{margin-bottom:-.5rem!important}.ml-sm-n2,.mx-sm-n2{margin-left:-.5rem!important}.m-sm-n3{margin:-1rem!important}.mt-sm-n3,.my-sm-n3{margin-top:-1rem!important}.mr-sm-n3,.mx-sm-n3{margin-right:-1rem!important}.mb-sm-n3,.my-sm-n3{margin-bottom:-1rem!important}.ml-sm-n3,.mx-sm-n3{margin-left:-1rem!important}.m-sm-n4{margin:-1.5rem!important}.mt-sm-n4,.my-sm-n4{margin-top:-1.5rem!important}.mr-sm-n4,.mx-sm-n4{margin-right:-1.5rem!important}.mb-sm-n4,.my-sm-n4{margin-bottom:-1.5rem!important}.ml-sm-n4,.mx-sm-n4{margin-left:-1.5rem!important}.m-sm-n5{margin:-3rem!important}.mt-sm-n5,.my-sm-n5{margin-top:-3rem!important}.mr-sm-n5,.mx-sm-n5{margin-right:-3rem!important}.mb-sm-n5,.my-sm-n5{margin-bottom:-3rem!important}.ml-sm-n5,.mx-sm-n5{margin-left:-3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width: 768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-n1{margin:-.25rem!important}.mt-md-n1,.my-md-n1{margin-top:-.25rem!important}.mr-md-n1,.mx-md-n1{margin-right:-.25rem!important}.mb-md-n1,.my-md-n1{margin-bottom:-.25rem!important}.ml-md-n1,.mx-md-n1{margin-left:-.25rem!important}.m-md-n2{margin:-.5rem!important}.mt-md-n2,.my-md-n2{margin-top:-.5rem!important}.mr-md-n2,.mx-md-n2{margin-right:-.5rem!important}.mb-md-n2,.my-md-n2{margin-bottom:-.5rem!important}.ml-md-n2,.mx-md-n2{margin-left:-.5rem!important}.m-md-n3{margin:-1rem!important}.mt-md-n3,.my-md-n3{margin-top:-1rem!important}.mr-md-n3,.mx-md-n3{margin-right:-1rem!important}.mb-md-n3,.my-md-n3{margin-bottom:-1rem!important}.ml-md-n3,.mx-md-n3{margin-left:-1rem!important}.m-md-n4{margin:-1.5rem!important}.mt-md-n4,.my-md-n4{margin-top:-1.5rem!important}.mr-md-n4,.mx-md-n4{margin-right:-1.5rem!important}.mb-md-n4,.my-md-n4{margin-bottom:-1.5rem!important}.ml-md-n4,.mx-md-n4{margin-left:-1.5rem!important}.m-md-n5{margin:-3rem!important}.mt-md-n5,.my-md-n5{margin-top:-3rem!important}.mr-md-n5,.mx-md-n5{margin-right:-3rem!important}.mb-md-n5,.my-md-n5{margin-bottom:-3rem!important}.ml-md-n5,.mx-md-n5{margin-left:-3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width: 992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-n1{margin:-.25rem!important}.mt-lg-n1,.my-lg-n1{margin-top:-.25rem!important}.mr-lg-n1,.mx-lg-n1{margin-right:-.25rem!important}.mb-lg-n1,.my-lg-n1{margin-bottom:-.25rem!important}.ml-lg-n1,.mx-lg-n1{margin-left:-.25rem!important}.m-lg-n2{margin:-.5rem!important}.mt-lg-n2,.my-lg-n2{margin-top:-.5rem!important}.mr-lg-n2,.mx-lg-n2{margin-right:-.5rem!important}.mb-lg-n2,.my-lg-n2{margin-bottom:-.5rem!important}.ml-lg-n2,.mx-lg-n2{margin-left:-.5rem!important}.m-lg-n3{margin:-1rem!important}.mt-lg-n3,.my-lg-n3{margin-top:-1rem!important}.mr-lg-n3,.mx-lg-n3{margin-right:-1rem!important}.mb-lg-n3,.my-lg-n3{margin-bottom:-1rem!important}.ml-lg-n3,.mx-lg-n3{margin-left:-1rem!important}.m-lg-n4{margin:-1.5rem!important}.mt-lg-n4,.my-lg-n4{margin-top:-1.5rem!important}.mr-lg-n4,.mx-lg-n4{margin-right:-1.5rem!important}.mb-lg-n4,.my-lg-n4{margin-bottom:-1.5rem!important}.ml-lg-n4,.mx-lg-n4{margin-left:-1.5rem!important}.m-lg-n5{margin:-3rem!important}.mt-lg-n5,.my-lg-n5{margin-top:-3rem!important}.mr-lg-n5,.mx-lg-n5{margin-right:-3rem!important}.mb-lg-n5,.my-lg-n5{margin-bottom:-3rem!important}.ml-lg-n5,.mx-lg-n5{margin-left:-3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width: 1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-n1{margin:-.25rem!important}.mt-xl-n1,.my-xl-n1{margin-top:-.25rem!important}.mr-xl-n1,.mx-xl-n1{margin-right:-.25rem!important}.mb-xl-n1,.my-xl-n1{margin-bottom:-.25rem!important}.ml-xl-n1,.mx-xl-n1{margin-left:-.25rem!important}.m-xl-n2{margin:-.5rem!important}.mt-xl-n2,.my-xl-n2{margin-top:-.5rem!important}.mr-xl-n2,.mx-xl-n2{margin-right:-.5rem!important}.mb-xl-n2,.my-xl-n2{margin-bottom:-.5rem!important}.ml-xl-n2,.mx-xl-n2{margin-left:-.5rem!important}.m-xl-n3{margin:-1rem!important}.mt-xl-n3,.my-xl-n3{margin-top:-1rem!important}.mr-xl-n3,.mx-xl-n3{margin-right:-1rem!important}.mb-xl-n3,.my-xl-n3{margin-bottom:-1rem!important}.ml-xl-n3,.mx-xl-n3{margin-left:-1rem!important}.m-xl-n4{margin:-1.5rem!important}.mt-xl-n4,.my-xl-n4{margin-top:-1.5rem!important}.mr-xl-n4,.mx-xl-n4{margin-right:-1.5rem!important}.mb-xl-n4,.my-xl-n4{margin-bottom:-1.5rem!important}.ml-xl-n4,.mx-xl-n4{margin-left:-1.5rem!important}.m-xl-n5{margin:-3rem!important}.mt-xl-n5,.my-xl-n5{margin-top:-3rem!important}.mr-xl-n5,.mx-xl-n5{margin-right:-3rem!important}.mb-xl-n5,.my-xl-n5{margin-bottom:-3rem!important}.ml-xl-n5,.mx-xl-n5{margin-left:-3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.stretched-link:after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;pointer-events:auto;content:\"\";background-color:#0000}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace!important}.text-justify{text-align:justify!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width: 576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width: 768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width: 992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width: 1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-lighter{font-weight:lighter!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-weight-bolder{font-weight:bolder!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:hover,a.text-primary:focus{color:#0056b3!important}.text-secondary{color:#6c757d!important}a.text-secondary:hover,a.text-secondary:focus{color:#494f54!important}.text-success{color:#28a745!important}a.text-success:hover,a.text-success:focus{color:#19692c!important}.text-info{color:#17a2b8!important}a.text-info:hover,a.text-info:focus{color:#0f6674!important}.text-warning{color:#ffc107!important}a.text-warning:hover,a.text-warning:focus{color:#ba8b00!important}.text-danger{color:#dc3545!important}a.text-danger:hover,a.text-danger:focus{color:#a71d2a!important}.text-light{color:#f8f9fa!important}a.text-light:hover,a.text-light:focus{color:#cbd3da!important}.text-dark{color:#343a40!important}a.text-dark:hover,a.text-dark:focus{color:#121416!important}.text-body{color:#212529!important}.text-muted{color:#6c757d!important}.text-black-50{color:#00000080!important}.text-white-50{color:#ffffff80!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.text-decoration-none{text-decoration:none!important}.text-break{word-break:break-word!important;word-wrap:break-word!important}.text-reset{color:inherit!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,*:before,*:after{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]:after{content:\" (\" attr(title) \")\"}pre{white-space:pre-wrap!important}pre,blockquote{border:1px solid #adb5bd;page-break-inside:avoid}tr,img{page-break-inside:avoid}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body,.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered th,.table-bordered td{border:1px solid #dee2e6!important}.table-dark{color:inherit}.table-dark th,.table-dark td,.table-dark thead th,.table-dark tbody+tbody{border-color:#dee2e6}.table .thead-dark th{color:inherit;border-color:#dee2e6}}/*!\n * BootstrapVue Custom CSS (https://bootstrap-vue.org)\n */.bv-no-focus-ring:focus{outline:none}@media (max-width: 575.98px){.bv-d-xs-down-none{display:none!important}}@media (max-width: 767.98px){.bv-d-sm-down-none{display:none!important}}@media (max-width: 991.98px){.bv-d-md-down-none{display:none!important}}@media (max-width: 1199.98px){.bv-d-lg-down-none{display:none!important}}.bv-d-xl-down-none{display:none!important}.form-control.focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem #007bff40}.form-control.focus.is-valid{border-color:#28a745;box-shadow:0 0 0 .2rem #28a74540}.form-control.focus.is-invalid{border-color:#dc3545;box-shadow:0 0 0 .2rem #dc354540}.b-avatar{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;flex-shrink:0;width:2.5rem;height:2.5rem;font-size:inherit;font-weight:400;line-height:1;max-width:100%;max-height:auto;text-align:center;overflow:visible;position:relative;transition:color .15s ease-in-out,background-color .15s ease-in-out,box-shadow .15s ease-in-out}.b-avatar:focus{outline:0}.b-avatar.btn,.b-avatar[href]{padding:0;border:0}.b-avatar.btn .b-avatar-img img,.b-avatar[href] .b-avatar-img img{transition:-webkit-transform .15s ease-in-out;transition:transform .15s ease-in-out;transition:transform .15s ease-in-out,-webkit-transform .15s ease-in-out}.b-avatar.btn:not(:disabled):not(.disabled),.b-avatar[href]:not(:disabled):not(.disabled){cursor:pointer}.b-avatar.btn:not(:disabled):not(.disabled):hover .b-avatar-img img,.b-avatar[href]:not(:disabled):not(.disabled):hover .b-avatar-img img{-webkit-transform:scale(1.15);transform:scale(1.15)}.b-avatar.disabled,.b-avatar:disabled,.b-avatar[disabled]{opacity:.65;pointer-events:none}.b-avatar .b-avatar-custom,.b-avatar .b-avatar-text,.b-avatar .b-avatar-img{border-radius:inherit;width:100%;height:100%;overflow:hidden;display:flex;justify-content:center;align-items:center;-webkit-mask-image:radial-gradient(white,black);mask-image:radial-gradient(white,black)}.b-avatar .b-avatar-text{text-transform:uppercase;white-space:nowrap}.b-avatar[href]{text-decoration:none}.b-avatar>.b-icon{width:60%;height:auto;max-width:100%}.b-avatar .b-avatar-img img{width:100%;height:100%;max-height:auto;border-radius:inherit;-o-object-fit:cover;object-fit:cover}.b-avatar .b-avatar-badge{position:absolute;min-height:1.5em;min-width:1.5em;padding:.25em;line-height:1;border-radius:10em;font-size:70%;font-weight:700;z-index:1}.b-avatar-sm{width:1.5rem;height:1.5rem}.b-avatar-sm .b-avatar-text{font-size:.6rem}.b-avatar-sm .b-avatar-badge{font-size:.42rem}.b-avatar-lg{width:3.5rem;height:3.5rem}.b-avatar-lg .b-avatar-text{font-size:1.4rem}.b-avatar-lg .b-avatar-badge{font-size:.98rem}.b-avatar-group .b-avatar-group-inner{display:flex;flex-wrap:wrap}.b-avatar-group .b-avatar{border:1px solid #dee2e6}.b-avatar-group a.b-avatar:hover:not(.disabled):not(disabled),.b-avatar-group .btn.b-avatar:hover:not(.disabled):not(disabled){z-index:1}.b-calendar{display:inline-flex}.b-calendar .b-calendar-inner{min-width:250px}.b-calendar .b-calendar-header,.b-calendar .b-calendar-nav{margin-bottom:.25rem}.b-calendar .b-calendar-nav .btn{padding:.25rem}.b-calendar output{padding:.25rem;font-size:80%}.b-calendar output.readonly{background-color:#e9ecef;opacity:1}.b-calendar .b-calendar-footer{margin-top:.5rem}.b-calendar .b-calendar-grid{padding:0;margin:0;overflow:hidden}.b-calendar .b-calendar-grid .row{flex-wrap:nowrap}.b-calendar .b-calendar-grid-caption{padding:.25rem}.b-calendar .b-calendar-grid-body .col[data-date] .btn{width:32px;height:32px;font-size:14px;line-height:1;margin:3px auto;padding:9px 0}.b-calendar .btn:disabled,.b-calendar .btn.disabled,.b-calendar .btn[aria-disabled=true]{cursor:default;pointer-events:none}.card-img-left{border-top-left-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-img-right{border-top-right-radius:calc(.25rem - 1px);border-bottom-right-radius:calc(.25rem - 1px)}.dropdown:not(.dropleft) .dropdown-toggle.dropdown-toggle-no-caret:after{display:none!important}.dropdown.dropleft .dropdown-toggle.dropdown-toggle-no-caret:before{display:none!important}.dropdown .dropdown-menu:focus{outline:none}.b-dropdown-form{display:inline-block;padding:.25rem 1.5rem;width:100%;clear:both;font-weight:400}.b-dropdown-form:focus{outline:1px dotted!important;outline:5px auto -webkit-focus-ring-color!important}.b-dropdown-form.disabled,.b-dropdown-form:disabled{outline:0!important;color:#adb5bd;pointer-events:none}.b-dropdown-text{display:inline-block;padding:.25rem 1.5rem;margin-bottom:0;width:100%;clear:both;font-weight:lighter}.custom-checkbox.b-custom-control-lg,.input-group-lg .custom-checkbox{font-size:1.25rem;line-height:1.5;padding-left:1.875rem}.custom-checkbox.b-custom-control-lg .custom-control-label:before,.input-group-lg .custom-checkbox .custom-control-label:before{top:.3125rem;left:-1.875rem;width:1.25rem;height:1.25rem;border-radius:.3rem}.custom-checkbox.b-custom-control-lg .custom-control-label:after,.input-group-lg .custom-checkbox .custom-control-label:after{top:.3125rem;left:-1.875rem;width:1.25rem;height:1.25rem;background-size:50% 50%}.custom-checkbox.b-custom-control-sm,.input-group-sm .custom-checkbox{font-size:.875rem;line-height:1.5;padding-left:1.3125rem}.custom-checkbox.b-custom-control-sm .custom-control-label:before,.input-group-sm .custom-checkbox .custom-control-label:before{top:.21875rem;left:-1.3125rem;width:.875rem;height:.875rem;border-radius:.2rem}.custom-checkbox.b-custom-control-sm .custom-control-label:after,.input-group-sm .custom-checkbox .custom-control-label:after{top:.21875rem;left:-1.3125rem;width:.875rem;height:.875rem;background-size:50% 50%}.custom-switch.b-custom-control-lg,.input-group-lg .custom-switch{padding-left:2.8125rem}.custom-switch.b-custom-control-lg .custom-control-label,.input-group-lg .custom-switch .custom-control-label{font-size:1.25rem;line-height:1.5}.custom-switch.b-custom-control-lg .custom-control-label:before,.input-group-lg .custom-switch .custom-control-label:before{top:.3125rem;height:1.25rem;left:-2.8125rem;width:2.1875rem;border-radius:.625rem}.custom-switch.b-custom-control-lg .custom-control-label:after,.input-group-lg .custom-switch .custom-control-label:after{top:calc(.3125rem + 2px);left:calc(-2.8125rem + 2px);width:calc(1.25rem - 4px);height:calc(1.25rem - 4px);border-radius:.625rem;background-size:50% 50%}.custom-switch.b-custom-control-lg .custom-control-input:checked~.custom-control-label:after,.input-group-lg .custom-switch .custom-control-input:checked~.custom-control-label:after{-webkit-transform:translateX(.9375rem);transform:translate(.9375rem)}.custom-switch.b-custom-control-sm,.input-group-sm .custom-switch{padding-left:1.96875rem}.custom-switch.b-custom-control-sm .custom-control-label,.input-group-sm .custom-switch .custom-control-label{font-size:.875rem;line-height:1.5}.custom-switch.b-custom-control-sm .custom-control-label:before,.input-group-sm .custom-switch .custom-control-label:before{top:.21875rem;left:-1.96875rem;width:1.53125rem;height:.875rem;border-radius:.4375rem}.custom-switch.b-custom-control-sm .custom-control-label:after,.input-group-sm .custom-switch .custom-control-label:after{top:calc(.21875rem + 2px);left:calc(-1.96875rem + 2px);width:calc(.875rem - 4px);height:calc(.875rem - 4px);border-radius:.4375rem;background-size:50% 50%}.custom-switch.b-custom-control-sm .custom-control-input:checked~.custom-control-label:after,.input-group-sm .custom-switch .custom-control-input:checked~.custom-control-label:after{-webkit-transform:translateX(.65625rem);transform:translate(.65625rem)}.input-group>.input-group-prepend>.btn-group>.btn,.input-group>.input-group-append:not(:last-child)>.btn-group>.btn,.input-group>.input-group-append:last-child>.btn-group:not(:last-child):not(.dropdown-toggle)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn-group>.btn,.input-group>.input-group-prepend:not(:first-child)>.btn-group>.btn,.input-group>.input-group-prepend:first-child>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.b-form-btn-label-control.form-control{display:flex;align-items:stretch;height:auto;padding:0;background-image:none}.input-group .b-form-btn-label-control.form-control{padding:0}[dir=rtl] .b-form-btn-label-control.form-control,.b-form-btn-label-control.form-control[dir=rtl]{flex-direction:row-reverse}[dir=rtl] .b-form-btn-label-control.form-control>label,.b-form-btn-label-control.form-control[dir=rtl]>label{text-align:right}.b-form-btn-label-control.form-control>.btn{line-height:1;font-size:inherit;box-shadow:none!important;border:0}.b-form-btn-label-control.form-control>.btn:disabled{pointer-events:none}.b-form-btn-label-control.form-control.is-valid>.btn{color:#28a745}.b-form-btn-label-control.form-control.is-invalid>.btn{color:#dc3545}.b-form-btn-label-control.form-control>.dropdown-menu{padding:.5rem}.b-form-btn-label-control.form-control>.form-control{height:auto;min-height:calc(1.5em + .75rem + 0px);padding-left:.25rem;margin:0;border:0;outline:0;background:transparent;word-break:break-word;font-size:inherit;white-space:normal;cursor:pointer}.b-form-btn-label-control.form-control>.form-control.form-control-sm{min-height:calc(1.5em + .5rem + 0px)}.b-form-btn-label-control.form-control>.form-control.form-control-lg{min-height:calc(1.5em + 1rem + 0px)}.input-group.input-group-sm .b-form-btn-label-control.form-control>.form-control{min-height:calc(1.5em + .5rem + 0px);padding-top:.25rem;padding-bottom:.25rem}.input-group.input-group-lg .b-form-btn-label-control.form-control>.form-control{min-height:calc(1.5em + 1rem + 0px);padding-top:.5rem;padding-bottom:.5rem}.b-form-btn-label-control.form-control[aria-disabled=true],.b-form-btn-label-control.form-control[aria-readonly=true]{background-color:#e9ecef;opacity:1}.b-form-btn-label-control.form-control[aria-disabled=true]{pointer-events:none}.b-form-btn-label-control.form-control[aria-disabled=true]>label{cursor:default}.b-form-btn-label-control.btn-group>.dropdown-menu{padding:.5rem}.custom-file-label{white-space:nowrap;overflow-x:hidden}.b-custom-control-lg.custom-file,.b-custom-control-lg .custom-file-input,.b-custom-control-lg .custom-file-label,.input-group-lg.custom-file,.input-group-lg .custom-file-input,.input-group-lg .custom-file-label{font-size:1.25rem;height:calc(1.5em + 1rem + 2px)}.b-custom-control-lg .custom-file-label,.b-custom-control-lg .custom-file-label:after,.input-group-lg .custom-file-label,.input-group-lg .custom-file-label:after{padding:.5rem 1rem;line-height:1.5}.b-custom-control-lg .custom-file-label,.input-group-lg .custom-file-label{border-radius:.3rem}.b-custom-control-lg .custom-file-label:after,.input-group-lg .custom-file-label:after{font-size:inherit;height:calc(1.5em + 1rem);border-radius:0 .3rem .3rem 0}.b-custom-control-sm.custom-file,.b-custom-control-sm .custom-file-input,.b-custom-control-sm .custom-file-label,.input-group-sm.custom-file,.input-group-sm .custom-file-input,.input-group-sm .custom-file-label{font-size:.875rem;height:calc(1.5em + .5rem + 2px)}.b-custom-control-sm .custom-file-label,.b-custom-control-sm .custom-file-label:after,.input-group-sm .custom-file-label,.input-group-sm .custom-file-label:after{padding:.25rem .5rem;line-height:1.5}.b-custom-control-sm .custom-file-label,.input-group-sm .custom-file-label{border-radius:.2rem}.b-custom-control-sm .custom-file-label:after,.input-group-sm .custom-file-label:after{font-size:inherit;height:calc(1.5em + .5rem);border-radius:0 .2rem .2rem 0}.was-validated .form-control:invalid,.was-validated .form-control:valid,.form-control.is-invalid,.form-control.is-valid{background-position:right calc(.375em + .1875rem) center}input[type=color].form-control{height:calc(1.5em + .75rem + 2px);padding:.125rem .25rem}input[type=color].form-control.form-control-sm,.input-group-sm input[type=color].form-control{height:calc(1.5em + .5rem + 2px);padding:.125rem .25rem}input[type=color].form-control.form-control-lg,.input-group-lg input[type=color].form-control{height:calc(1.5em + 1rem + 2px);padding:.125rem .25rem}input[type=color].form-control:disabled{background-color:#adb5bd;opacity:.65}.input-group>.custom-range{position:relative;flex:1 1 auto;width:1%;margin-bottom:0}.input-group>.custom-range+.form-control,.input-group>.custom-range+.form-control-plaintext,.input-group>.custom-range+.custom-select,.input-group>.custom-range+.custom-range,.input-group>.custom-range+.custom-file{margin-left:-1px}.input-group>.form-control+.custom-range,.input-group>.form-control-plaintext+.custom-range,.input-group>.custom-select+.custom-range,.input-group>.custom-range+.custom-range,.input-group>.custom-file+.custom-range{margin-left:-1px}.input-group>.custom-range:focus{z-index:3}.input-group>.custom-range:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-range:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-range{padding:0 .75rem;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;height:calc(1.5em + .75rem + 2px);border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.input-group>.custom-range{transition:none}}.input-group>.custom-range:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem #007bff40}.input-group>.custom-range:disabled,.input-group>.custom-range[readonly]{background-color:#e9ecef}.input-group-lg>.custom-range{height:calc(1.5em + 1rem + 2px);padding:0 1rem;border-radius:.3rem}.input-group-sm>.custom-range{height:calc(1.5em + .5rem + 2px);padding:0 .5rem;border-radius:.2rem}.was-validated .input-group .custom-range:valid,.input-group .custom-range.is-valid{border-color:#28a745}.was-validated .input-group .custom-range:valid:focus,.input-group .custom-range.is-valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem #28a74540}.was-validated .custom-range:valid:focus::-webkit-slider-thumb,.custom-range.is-valid:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem #9be7ac}.was-validated .custom-range:valid:focus::-moz-range-thumb,.custom-range.is-valid:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem #9be7ac}.was-validated .custom-range:valid:focus::-ms-thumb,.custom-range.is-valid:focus::-ms-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem #9be7ac}.was-validated .custom-range:valid::-webkit-slider-thumb,.custom-range.is-valid::-webkit-slider-thumb{background-color:#28a745;background-image:none}.was-validated .custom-range:valid::-webkit-slider-thumb:active,.custom-range.is-valid::-webkit-slider-thumb:active{background-color:#9be7ac;background-image:none}.was-validated .custom-range:valid::-webkit-slider-runnable-track,.custom-range.is-valid::-webkit-slider-runnable-track{background-color:#28a74559}.was-validated .custom-range:valid::-moz-range-thumb,.custom-range.is-valid::-moz-range-thumb{background-color:#28a745;background-image:none}.was-validated .custom-range:valid::-moz-range-thumb:active,.custom-range.is-valid::-moz-range-thumb:active{background-color:#9be7ac;background-image:none}.was-validated .custom-range:valid::-moz-range-track,.custom-range.is-valid::-moz-range-track{background:rgba(40,167,69,.35)}.was-validated .custom-range:valid~.valid-feedback,.was-validated .custom-range:valid~.valid-tooltip,.custom-range.is-valid~.valid-feedback,.custom-range.is-valid~.valid-tooltip{display:block}.was-validated .custom-range:valid::-ms-thumb,.custom-range.is-valid::-ms-thumb{background-color:#28a745;background-image:none}.was-validated .custom-range:valid::-ms-thumb:active,.custom-range.is-valid::-ms-thumb:active{background-color:#9be7ac;background-image:none}.was-validated .custom-range:valid::-ms-track-lower,.custom-range.is-valid::-ms-track-lower{background:rgba(40,167,69,.35)}.was-validated .custom-range:valid::-ms-track-upper,.custom-range.is-valid::-ms-track-upper{background:rgba(40,167,69,.35)}.was-validated .input-group .custom-range:invalid,.input-group .custom-range.is-invalid{border-color:#dc3545}.was-validated .input-group .custom-range:invalid:focus,.input-group .custom-range.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem #dc354540}.was-validated .custom-range:invalid:focus::-webkit-slider-thumb,.custom-range.is-invalid:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem #f6cdd1}.was-validated .custom-range:invalid:focus::-moz-range-thumb,.custom-range.is-invalid:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem #f6cdd1}.was-validated .custom-range:invalid:focus::-ms-thumb,.custom-range.is-invalid:focus::-ms-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem #f6cdd1}.was-validated .custom-range:invalid::-webkit-slider-thumb,.custom-range.is-invalid::-webkit-slider-thumb{background-color:#dc3545;background-image:none}.was-validated .custom-range:invalid::-webkit-slider-thumb:active,.custom-range.is-invalid::-webkit-slider-thumb:active{background-color:#f6cdd1;background-image:none}.was-validated .custom-range:invalid::-webkit-slider-runnable-track,.custom-range.is-invalid::-webkit-slider-runnable-track{background-color:#dc354559}.was-validated .custom-range:invalid::-moz-range-thumb,.custom-range.is-invalid::-moz-range-thumb{background-color:#dc3545;background-image:none}.was-validated .custom-range:invalid::-moz-range-thumb:active,.custom-range.is-invalid::-moz-range-thumb:active{background-color:#f6cdd1;background-image:none}.was-validated .custom-range:invalid::-moz-range-track,.custom-range.is-invalid::-moz-range-track{background:rgba(220,53,69,.35)}.was-validated .custom-range:invalid~.invalid-feedback,.was-validated .custom-range:invalid~.invalid-tooltip,.custom-range.is-invalid~.invalid-feedback,.custom-range.is-invalid~.invalid-tooltip{display:block}.was-validated .custom-range:invalid::-ms-thumb,.custom-range.is-invalid::-ms-thumb{background-color:#dc3545;background-image:none}.was-validated .custom-range:invalid::-ms-thumb:active,.custom-range.is-invalid::-ms-thumb:active{background-color:#f6cdd1;background-image:none}.was-validated .custom-range:invalid::-ms-track-lower,.custom-range.is-invalid::-ms-track-lower{background:rgba(220,53,69,.35)}.was-validated .custom-range:invalid::-ms-track-upper,.custom-range.is-invalid::-ms-track-upper{background:rgba(220,53,69,.35)}.custom-radio.b-custom-control-lg,.input-group-lg .custom-radio{font-size:1.25rem;line-height:1.5;padding-left:1.875rem}.custom-radio.b-custom-control-lg .custom-control-label:before,.input-group-lg .custom-radio .custom-control-label:before{top:.3125rem;left:-1.875rem;width:1.25rem;height:1.25rem;border-radius:50%}.custom-radio.b-custom-control-lg .custom-control-label:after,.input-group-lg .custom-radio .custom-control-label:after{top:.3125rem;left:-1.875rem;width:1.25rem;height:1.25rem;background:no-repeat 50%/50% 50%}.custom-radio.b-custom-control-sm,.input-group-sm .custom-radio{font-size:.875rem;line-height:1.5;padding-left:1.3125rem}.custom-radio.b-custom-control-sm .custom-control-label:before,.input-group-sm .custom-radio .custom-control-label:before{top:.21875rem;left:-1.3125rem;width:.875rem;height:.875rem;border-radius:50%}.custom-radio.b-custom-control-sm .custom-control-label:after,.input-group-sm .custom-radio .custom-control-label:after{top:.21875rem;left:-1.3125rem;width:.875rem;height:.875rem;background:no-repeat 50%/50% 50%}.b-rating{text-align:center}.b-rating.d-inline-flex{width:auto}.b-rating .b-rating-star,.b-rating .b-rating-value{padding:0 .25em}.b-rating .b-rating-value{min-width:2.5em}.b-rating .b-rating-star{display:inline-flex;justify-content:center;outline:0}.b-rating .b-rating-star .b-rating-icon{display:inline-flex;transition:all .15s ease-in-out}.b-rating.disabled,.b-rating:disabled{background-color:#e9ecef;color:#6c757d}.b-rating:not(.disabled):not(.readonly) .b-rating-star{cursor:pointer}.b-rating:not(.disabled):not(.readonly):focus:not(:hover) .b-rating-star.focused .b-rating-icon,.b-rating:not(.disabled):not(.readonly) .b-rating-star:hover .b-rating-icon{-webkit-transform:scale(1.5);transform:scale(1.5)}.b-rating[dir=rtl] .b-rating-star-half{-webkit-transform:scale(-1,1);transform:scaleX(-1)}.b-form-spinbutton{text-align:center;overflow:hidden;background-image:none;padding:0}[dir=rtl] .b-form-spinbutton:not(.flex-column),.b-form-spinbutton[dir=rtl]:not(.flex-column){flex-direction:row-reverse}.b-form-spinbutton output{font-size:inherit;outline:0;border:0;background-color:transparent;width:auto;margin:0;padding:0 .25rem}.b-form-spinbutton output>div,.b-form-spinbutton output>bdi{display:block;min-width:2.25em;height:1.5em}.b-form-spinbutton.flex-column{height:auto;width:auto}.b-form-spinbutton.flex-column output{margin:0 .25rem;padding:.25rem 0}.b-form-spinbutton:not(.d-inline-flex):not(.flex-column){output-width:100%}.b-form-spinbutton.d-inline-flex:not(.flex-column){width:auto}.b-form-spinbutton .btn{line-height:1;box-shadow:none!important}.b-form-spinbutton .btn:disabled{pointer-events:none}.b-form-spinbutton .btn:hover:not(:disabled)>div>.b-icon{-webkit-transform:scale(1.25);transform:scale(1.25)}.b-form-spinbutton.disabled,.b-form-spinbutton.readonly{background-color:#e9ecef}.b-form-spinbutton.disabled{pointer-events:none}.b-form-tags.focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem #007bff40}.b-form-tags.focus.is-valid{border-color:#28a745;box-shadow:0 0 0 .2rem #28a74540}.b-form-tags.focus.is-invalid{border-color:#dc3545;box-shadow:0 0 0 .2rem #dc354540}.b-form-tags.disabled{background-color:#e9ecef}.b-form-tags-list{margin-top:-.25rem}.b-form-tags-list .b-form-tags-field,.b-form-tags-list .b-form-tag{margin-top:.25rem}.b-form-tags-input{color:#495057}.b-form-tag{font-size:75%;font-weight:400;line-height:1.5;margin-right:.25rem}.b-form-tag.disabled{opacity:.75}.b-form-tag>button.b-form-tag-remove{color:inherit;font-size:125%;line-height:1;float:none;margin-left:.25rem}.form-control-sm .b-form-tag,.form-control-lg .b-form-tag{line-height:1.5}.media-aside{display:flex;margin-right:1rem}.media-aside-right{margin-right:0;margin-left:1rem}.modal-backdrop{opacity:.5}.b-pagination-pills .page-item .page-link{border-radius:50rem!important;margin-left:.25rem;line-height:1}.b-pagination-pills .page-item:first-child .page-link{margin-left:0}.popover.b-popover{display:block;opacity:1;outline:0}.popover.b-popover.fade:not(.show){opacity:0}.popover.b-popover.show{opacity:1}.b-popover-primary.popover{background-color:#cce5ff;border-color:#b8daff}.b-popover-primary.bs-popover-top>.arrow:before,.b-popover-primary.bs-popover-auto[x-placement^=top]>.arrow:before{border-top-color:#b8daff}.b-popover-primary.bs-popover-top>.arrow:after,.b-popover-primary.bs-popover-auto[x-placement^=top]>.arrow:after{border-top-color:#cce5ff}.b-popover-primary.bs-popover-right>.arrow:before,.b-popover-primary.bs-popover-auto[x-placement^=right]>.arrow:before{border-right-color:#b8daff}.b-popover-primary.bs-popover-right>.arrow:after,.b-popover-primary.bs-popover-auto[x-placement^=right]>.arrow:after{border-right-color:#cce5ff}.b-popover-primary.bs-popover-bottom>.arrow:before,.b-popover-primary.bs-popover-auto[x-placement^=bottom]>.arrow:before{border-bottom-color:#b8daff}.b-popover-primary.bs-popover-bottom>.arrow:after,.b-popover-primary.bs-popover-auto[x-placement^=bottom]>.arrow:after{border-bottom-color:#bdddff}.b-popover-primary.bs-popover-bottom .popover-header:before,.b-popover-primary.bs-popover-auto[x-placement^=bottom] .popover-header:before{border-bottom-color:#bdddff}.b-popover-primary.bs-popover-left>.arrow:before,.b-popover-primary.bs-popover-auto[x-placement^=left]>.arrow:before{border-left-color:#b8daff}.b-popover-primary.bs-popover-left>.arrow:after,.b-popover-primary.bs-popover-auto[x-placement^=left]>.arrow:after{border-left-color:#cce5ff}.b-popover-primary .popover-header{color:#212529;background-color:#bdddff;border-bottom-color:#a3d0ff}.b-popover-primary .popover-body{color:#004085}.b-popover-secondary.popover{background-color:#e2e3e5;border-color:#d6d8db}.b-popover-secondary.bs-popover-top>.arrow:before,.b-popover-secondary.bs-popover-auto[x-placement^=top]>.arrow:before{border-top-color:#d6d8db}.b-popover-secondary.bs-popover-top>.arrow:after,.b-popover-secondary.bs-popover-auto[x-placement^=top]>.arrow:after{border-top-color:#e2e3e5}.b-popover-secondary.bs-popover-right>.arrow:before,.b-popover-secondary.bs-popover-auto[x-placement^=right]>.arrow:before{border-right-color:#d6d8db}.b-popover-secondary.bs-popover-right>.arrow:after,.b-popover-secondary.bs-popover-auto[x-placement^=right]>.arrow:after{border-right-color:#e2e3e5}.b-popover-secondary.bs-popover-bottom>.arrow:before,.b-popover-secondary.bs-popover-auto[x-placement^=bottom]>.arrow:before{border-bottom-color:#d6d8db}.b-popover-secondary.bs-popover-bottom>.arrow:after,.b-popover-secondary.bs-popover-auto[x-placement^=bottom]>.arrow:after{border-bottom-color:#dadbde}.b-popover-secondary.bs-popover-bottom .popover-header:before,.b-popover-secondary.bs-popover-auto[x-placement^=bottom] .popover-header:before{border-bottom-color:#dadbde}.b-popover-secondary.bs-popover-left>.arrow:before,.b-popover-secondary.bs-popover-auto[x-placement^=left]>.arrow:before{border-left-color:#d6d8db}.b-popover-secondary.bs-popover-left>.arrow:after,.b-popover-secondary.bs-popover-auto[x-placement^=left]>.arrow:after{border-left-color:#e2e3e5}.b-popover-secondary .popover-header{color:#212529;background-color:#dadbde;border-bottom-color:#ccced2}.b-popover-secondary .popover-body{color:#383d41}.b-popover-success.popover{background-color:#d4edda;border-color:#c3e6cb}.b-popover-success.bs-popover-top>.arrow:before,.b-popover-success.bs-popover-auto[x-placement^=top]>.arrow:before{border-top-color:#c3e6cb}.b-popover-success.bs-popover-top>.arrow:after,.b-popover-success.bs-popover-auto[x-placement^=top]>.arrow:after{border-top-color:#d4edda}.b-popover-success.bs-popover-right>.arrow:before,.b-popover-success.bs-popover-auto[x-placement^=right]>.arrow:before{border-right-color:#c3e6cb}.b-popover-success.bs-popover-right>.arrow:after,.b-popover-success.bs-popover-auto[x-placement^=right]>.arrow:after{border-right-color:#d4edda}.b-popover-success.bs-popover-bottom>.arrow:before,.b-popover-success.bs-popover-auto[x-placement^=bottom]>.arrow:before{border-bottom-color:#c3e6cb}.b-popover-success.bs-popover-bottom>.arrow:after,.b-popover-success.bs-popover-auto[x-placement^=bottom]>.arrow:after{border-bottom-color:#c9e8d1}.b-popover-success.bs-popover-bottom .popover-header:before,.b-popover-success.bs-popover-auto[x-placement^=bottom] .popover-header:before{border-bottom-color:#c9e8d1}.b-popover-success.bs-popover-left>.arrow:before,.b-popover-success.bs-popover-auto[x-placement^=left]>.arrow:before{border-left-color:#c3e6cb}.b-popover-success.bs-popover-left>.arrow:after,.b-popover-success.bs-popover-auto[x-placement^=left]>.arrow:after{border-left-color:#d4edda}.b-popover-success .popover-header{color:#212529;background-color:#c9e8d1;border-bottom-color:#b7e1c1}.b-popover-success .popover-body{color:#155724}.b-popover-info.popover{background-color:#d1ecf1;border-color:#bee5eb}.b-popover-info.bs-popover-top>.arrow:before,.b-popover-info.bs-popover-auto[x-placement^=top]>.arrow:before{border-top-color:#bee5eb}.b-popover-info.bs-popover-top>.arrow:after,.b-popover-info.bs-popover-auto[x-placement^=top]>.arrow:after{border-top-color:#d1ecf1}.b-popover-info.bs-popover-right>.arrow:before,.b-popover-info.bs-popover-auto[x-placement^=right]>.arrow:before{border-right-color:#bee5eb}.b-popover-info.bs-popover-right>.arrow:after,.b-popover-info.bs-popover-auto[x-placement^=right]>.arrow:after{border-right-color:#d1ecf1}.b-popover-info.bs-popover-bottom>.arrow:before,.b-popover-info.bs-popover-auto[x-placement^=bottom]>.arrow:before{border-bottom-color:#bee5eb}.b-popover-info.bs-popover-bottom>.arrow:after,.b-popover-info.bs-popover-auto[x-placement^=bottom]>.arrow:after{border-bottom-color:#c5e7ed}.b-popover-info.bs-popover-bottom .popover-header:before,.b-popover-info.bs-popover-auto[x-placement^=bottom] .popover-header:before{border-bottom-color:#c5e7ed}.b-popover-info.bs-popover-left>.arrow:before,.b-popover-info.bs-popover-auto[x-placement^=left]>.arrow:before{border-left-color:#bee5eb}.b-popover-info.bs-popover-left>.arrow:after,.b-popover-info.bs-popover-auto[x-placement^=left]>.arrow:after{border-left-color:#d1ecf1}.b-popover-info .popover-header{color:#212529;background-color:#c5e7ed;border-bottom-color:#b2dfe7}.b-popover-info .popover-body{color:#0c5460}.b-popover-warning.popover{background-color:#fff3cd;border-color:#ffeeba}.b-popover-warning.bs-popover-top>.arrow:before,.b-popover-warning.bs-popover-auto[x-placement^=top]>.arrow:before{border-top-color:#ffeeba}.b-popover-warning.bs-popover-top>.arrow:after,.b-popover-warning.bs-popover-auto[x-placement^=top]>.arrow:after{border-top-color:#fff3cd}.b-popover-warning.bs-popover-right>.arrow:before,.b-popover-warning.bs-popover-auto[x-placement^=right]>.arrow:before{border-right-color:#ffeeba}.b-popover-warning.bs-popover-right>.arrow:after,.b-popover-warning.bs-popover-auto[x-placement^=right]>.arrow:after{border-right-color:#fff3cd}.b-popover-warning.bs-popover-bottom>.arrow:before,.b-popover-warning.bs-popover-auto[x-placement^=bottom]>.arrow:before{border-bottom-color:#ffeeba}.b-popover-warning.bs-popover-bottom>.arrow:after,.b-popover-warning.bs-popover-auto[x-placement^=bottom]>.arrow:after{border-bottom-color:#ffefbe}.b-popover-warning.bs-popover-bottom .popover-header:before,.b-popover-warning.bs-popover-auto[x-placement^=bottom] .popover-header:before{border-bottom-color:#ffefbe}.b-popover-warning.bs-popover-left>.arrow:before,.b-popover-warning.bs-popover-auto[x-placement^=left]>.arrow:before{border-left-color:#ffeeba}.b-popover-warning.bs-popover-left>.arrow:after,.b-popover-warning.bs-popover-auto[x-placement^=left]>.arrow:after{border-left-color:#fff3cd}.b-popover-warning .popover-header{color:#212529;background-color:#ffefbe;border-bottom-color:#ffe9a4}.b-popover-warning .popover-body{color:#856404}.b-popover-danger.popover{background-color:#f8d7da;border-color:#f5c6cb}.b-popover-danger.bs-popover-top>.arrow:before,.b-popover-danger.bs-popover-auto[x-placement^=top]>.arrow:before{border-top-color:#f5c6cb}.b-popover-danger.bs-popover-top>.arrow:after,.b-popover-danger.bs-popover-auto[x-placement^=top]>.arrow:after{border-top-color:#f8d7da}.b-popover-danger.bs-popover-right>.arrow:before,.b-popover-danger.bs-popover-auto[x-placement^=right]>.arrow:before{border-right-color:#f5c6cb}.b-popover-danger.bs-popover-right>.arrow:after,.b-popover-danger.bs-popover-auto[x-placement^=right]>.arrow:after{border-right-color:#f8d7da}.b-popover-danger.bs-popover-bottom>.arrow:before,.b-popover-danger.bs-popover-auto[x-placement^=bottom]>.arrow:before{border-bottom-color:#f5c6cb}.b-popover-danger.bs-popover-bottom>.arrow:after,.b-popover-danger.bs-popover-auto[x-placement^=bottom]>.arrow:after{border-bottom-color:#f6cace}.b-popover-danger.bs-popover-bottom .popover-header:before,.b-popover-danger.bs-popover-auto[x-placement^=bottom] .popover-header:before{border-bottom-color:#f6cace}.b-popover-danger.bs-popover-left>.arrow:before,.b-popover-danger.bs-popover-auto[x-placement^=left]>.arrow:before{border-left-color:#f5c6cb}.b-popover-danger.bs-popover-left>.arrow:after,.b-popover-danger.bs-popover-auto[x-placement^=left]>.arrow:after{border-left-color:#f8d7da}.b-popover-danger .popover-header{color:#212529;background-color:#f6cace;border-bottom-color:#f2b4ba}.b-popover-danger .popover-body{color:#721c24}.b-popover-light.popover{background-color:#fefefe;border-color:#fdfdfe}.b-popover-light.bs-popover-top>.arrow:before,.b-popover-light.bs-popover-auto[x-placement^=top]>.arrow:before{border-top-color:#fdfdfe}.b-popover-light.bs-popover-top>.arrow:after,.b-popover-light.bs-popover-auto[x-placement^=top]>.arrow:after{border-top-color:#fefefe}.b-popover-light.bs-popover-right>.arrow:before,.b-popover-light.bs-popover-auto[x-placement^=right]>.arrow:before{border-right-color:#fdfdfe}.b-popover-light.bs-popover-right>.arrow:after,.b-popover-light.bs-popover-auto[x-placement^=right]>.arrow:after{border-right-color:#fefefe}.b-popover-light.bs-popover-bottom>.arrow:before,.b-popover-light.bs-popover-auto[x-placement^=bottom]>.arrow:before{border-bottom-color:#fdfdfe}.b-popover-light.bs-popover-bottom>.arrow:after,.b-popover-light.bs-popover-auto[x-placement^=bottom]>.arrow:after{border-bottom-color:#f6f6f6}.b-popover-light.bs-popover-bottom .popover-header:before,.b-popover-light.bs-popover-auto[x-placement^=bottom] .popover-header:before{border-bottom-color:#f6f6f6}.b-popover-light.bs-popover-left>.arrow:before,.b-popover-light.bs-popover-auto[x-placement^=left]>.arrow:before{border-left-color:#fdfdfe}.b-popover-light.bs-popover-left>.arrow:after,.b-popover-light.bs-popover-auto[x-placement^=left]>.arrow:after{border-left-color:#fefefe}.b-popover-light .popover-header{color:#212529;background-color:#f6f6f6;border-bottom-color:#eaeaea}.b-popover-light .popover-body{color:#818182}.b-popover-dark.popover{background-color:#d6d8d9;border-color:#c6c8ca}.b-popover-dark.bs-popover-top>.arrow:before,.b-popover-dark.bs-popover-auto[x-placement^=top]>.arrow:before{border-top-color:#c6c8ca}.b-popover-dark.bs-popover-top>.arrow:after,.b-popover-dark.bs-popover-auto[x-placement^=top]>.arrow:after{border-top-color:#d6d8d9}.b-popover-dark.bs-popover-right>.arrow:before,.b-popover-dark.bs-popover-auto[x-placement^=right]>.arrow:before{border-right-color:#c6c8ca}.b-popover-dark.bs-popover-right>.arrow:after,.b-popover-dark.bs-popover-auto[x-placement^=right]>.arrow:after{border-right-color:#d6d8d9}.b-popover-dark.bs-popover-bottom>.arrow:before,.b-popover-dark.bs-popover-auto[x-placement^=bottom]>.arrow:before{border-bottom-color:#c6c8ca}.b-popover-dark.bs-popover-bottom>.arrow:after,.b-popover-dark.bs-popover-auto[x-placement^=bottom]>.arrow:after{border-bottom-color:#ced0d2}.b-popover-dark.bs-popover-bottom .popover-header:before,.b-popover-dark.bs-popover-auto[x-placement^=bottom] .popover-header:before{border-bottom-color:#ced0d2}.b-popover-dark.bs-popover-left>.arrow:before,.b-popover-dark.bs-popover-auto[x-placement^=left]>.arrow:before{border-left-color:#c6c8ca}.b-popover-dark.bs-popover-left>.arrow:after,.b-popover-dark.bs-popover-auto[x-placement^=left]>.arrow:after{border-left-color:#d6d8d9}.b-popover-dark .popover-header{color:#212529;background-color:#ced0d2;border-bottom-color:#c1c4c5}.b-popover-dark .popover-body{color:#1b1e21}.b-sidebar-outer{position:fixed;top:0;left:0;right:0;height:0;overflow:visible;z-index:1035}.b-sidebar-backdrop{position:fixed;top:0;left:0;z-index:-1;width:100vw;height:100vh;opacity:.6}.b-sidebar{display:flex;flex-direction:column;position:fixed;top:0;width:320px;max-width:100%;height:100vh;max-height:100%;margin:0;outline:0;-webkit-transform:translateX(0);transform:translate(0)}.b-sidebar.slide{transition:-webkit-transform .3s ease-in-out;transition:transform .3s ease-in-out;transition:transform .3s ease-in-out,-webkit-transform .3s ease-in-out}@media (prefers-reduced-motion: reduce){.b-sidebar.slide{transition:none}}.b-sidebar:not(.b-sidebar-right){left:0;right:auto}.b-sidebar:not(.b-sidebar-right).slide:not(.show){-webkit-transform:translateX(-100%);transform:translate(-100%)}.b-sidebar:not(.b-sidebar-right)>.b-sidebar-header .close{margin-left:auto}.b-sidebar.b-sidebar-right{left:auto;right:0}.b-sidebar.b-sidebar-right.slide:not(.show){-webkit-transform:translateX(100%);transform:translate(100%)}.b-sidebar.b-sidebar-right>.b-sidebar-header .close{margin-right:auto}.b-sidebar>.b-sidebar-header{font-size:1.5rem;padding:.5rem 1rem;display:flex;flex-direction:row;flex-grow:0;align-items:center}[dir=rtl] .b-sidebar>.b-sidebar-header{flex-direction:row-reverse}.b-sidebar>.b-sidebar-header .close{float:none;font-size:1.5rem}.b-sidebar>.b-sidebar-body{flex-grow:1;height:100%;overflow-y:auto}.b-sidebar>.b-sidebar-footer{flex-grow:0}.b-skeleton-wrapper{cursor:wait}.b-skeleton{position:relative;overflow:hidden;background-color:#0000001f;cursor:wait;-webkit-mask-image:radial-gradient(white,black);mask-image:radial-gradient(white,black)}.b-skeleton:before{content:\"\\a0\"}.b-skeleton-text{height:1rem;margin-bottom:.25rem;border-radius:.25rem}.b-skeleton-button{width:75px;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem}.b-skeleton-avatar{width:2.5em;height:2.5em;border-radius:50%}.b-skeleton-input{height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;line-height:1.5;border:#ced4da solid 1px;border-radius:.25rem}.b-skeleton-icon-wrapper svg{color:#0000001f}.b-skeleton-img{height:100%;width:100%}.b-skeleton-animate-wave:after{content:\"\";position:absolute;top:0;right:0;bottom:0;left:0;z-index:0;background:linear-gradient(90deg,transparent,rgba(255,255,255,.4),transparent);-webkit-animation:b-skeleton-animate-wave 1.75s linear infinite;animation:b-skeleton-animate-wave 1.75s linear infinite}@media (prefers-reduced-motion: reduce){.b-skeleton-animate-wave:after{background:none;-webkit-animation:none;animation:none}}@-webkit-keyframes b-skeleton-animate-wave{0%{-webkit-transform:translateX(-100%);transform:translate(-100%)}to{-webkit-transform:translateX(100%);transform:translate(100%)}}@keyframes b-skeleton-animate-wave{0%{-webkit-transform:translateX(-100%);transform:translate(-100%)}to{-webkit-transform:translateX(100%);transform:translate(100%)}}.b-skeleton-animate-fade{-webkit-animation:b-skeleton-animate-fade .875s ease-in-out alternate infinite;animation:b-skeleton-animate-fade .875s ease-in-out alternate infinite}@media (prefers-reduced-motion: reduce){.b-skeleton-animate-fade{-webkit-animation:none;animation:none}}@-webkit-keyframes b-skeleton-animate-fade{0%{opacity:1}to{opacity:.4}}@keyframes b-skeleton-animate-fade{0%{opacity:1}to{opacity:.4}}.b-skeleton-animate-throb{-webkit-animation:b-skeleton-animate-throb .875s ease-in alternate infinite;animation:b-skeleton-animate-throb .875s ease-in alternate infinite}@media (prefers-reduced-motion: reduce){.b-skeleton-animate-throb{-webkit-animation:none;animation:none}}@-webkit-keyframes b-skeleton-animate-throb{0%{-webkit-transform:scale(1);transform:scale(1)}to{-webkit-transform:scale(.975);transform:scale(.975)}}@keyframes b-skeleton-animate-throb{0%{-webkit-transform:scale(1);transform:scale(1)}to{-webkit-transform:scale(.975);transform:scale(.975)}}.table.b-table.b-table-fixed{table-layout:fixed}.table.b-table.b-table-no-border-collapse{border-collapse:separate;border-spacing:0}.table.b-table[aria-busy=true]{opacity:.55}.table.b-table>tbody>tr.b-table-details>td{border-top:none!important}.table.b-table>caption{caption-side:bottom}.table.b-table.b-table-caption-top>caption{caption-side:top!important}.table.b-table>tbody>.table-active,.table.b-table>tbody>.table-active>th,.table.b-table>tbody>.table-active>td{background-color:#00000013}.table.b-table.table-hover>tbody>tr.table-active:hover td,.table.b-table.table-hover>tbody>tr.table-active:hover th{color:#212529;background-image:linear-gradient(rgba(0,0,0,.075),rgba(0,0,0,.075));background-repeat:no-repeat}.table.b-table>tbody>.bg-active,.table.b-table>tbody>.bg-active>th,.table.b-table>tbody>.bg-active>td{background-color:#ffffff13!important}.table.b-table.table-hover.table-dark>tbody>tr.bg-active:hover td,.table.b-table.table-hover.table-dark>tbody>tr.bg-active:hover th{color:#fff;background-image:linear-gradient(rgba(255,255,255,.075),rgba(255,255,255,.075));background-repeat:no-repeat}.b-table-sticky-header,.table-responsive,[class*=table-responsive-]{margin-bottom:1rem}.b-table-sticky-header>.table,.table-responsive>.table,[class*=table-responsive-]>.table{margin-bottom:0}.b-table-sticky-header{overflow-y:auto;max-height:300px}@media print{.b-table-sticky-header{overflow-y:visible!important;max-height:none!important}}@supports ((position: -webkit-sticky) or (position: sticky)){.b-table-sticky-header>.table.b-table>thead>tr>th{position:-webkit-sticky;position:sticky;top:0;z-index:2}.b-table-sticky-header>.table.b-table>thead>tr>.b-table-sticky-column,.b-table-sticky-header>.table.b-table>tbody>tr>.b-table-sticky-column,.b-table-sticky-header>.table.b-table>tfoot>tr>.b-table-sticky-column,.table-responsive>.table.b-table>thead>tr>.b-table-sticky-column,.table-responsive>.table.b-table>tbody>tr>.b-table-sticky-column,.table-responsive>.table.b-table>tfoot>tr>.b-table-sticky-column,[class*=table-responsive-]>.table.b-table>thead>tr>.b-table-sticky-column,[class*=table-responsive-]>.table.b-table>tbody>tr>.b-table-sticky-column,[class*=table-responsive-]>.table.b-table>tfoot>tr>.b-table-sticky-column{position:-webkit-sticky;position:sticky;left:0}.b-table-sticky-header>.table.b-table>thead>tr>.b-table-sticky-column,.table-responsive>.table.b-table>thead>tr>.b-table-sticky-column,[class*=table-responsive-]>.table.b-table>thead>tr>.b-table-sticky-column{z-index:5}.b-table-sticky-header>.table.b-table>tbody>tr>.b-table-sticky-column,.b-table-sticky-header>.table.b-table>tfoot>tr>.b-table-sticky-column,.table-responsive>.table.b-table>tbody>tr>.b-table-sticky-column,.table-responsive>.table.b-table>tfoot>tr>.b-table-sticky-column,[class*=table-responsive-]>.table.b-table>tbody>tr>.b-table-sticky-column,[class*=table-responsive-]>.table.b-table>tfoot>tr>.b-table-sticky-column{z-index:2}.table.b-table>thead>tr>.table-b-table-default,.table.b-table>tbody>tr>.table-b-table-default,.table.b-table>tfoot>tr>.table-b-table-default{color:#212529;background-color:#fff}.table.b-table.table-dark>thead>tr>.bg-b-table-default,.table.b-table.table-dark>tbody>tr>.bg-b-table-default,.table.b-table.table-dark>tfoot>tr>.bg-b-table-default{color:#fff;background-color:#343a40}.table.b-table.table-striped>tbody>tr:nth-of-type(odd)>.table-b-table-default{background-image:linear-gradient(rgba(0,0,0,.05),rgba(0,0,0,.05));background-repeat:no-repeat}.table.b-table.table-striped.table-dark>tbody>tr:nth-of-type(odd)>.bg-b-table-default{background-image:linear-gradient(rgba(255,255,255,.05),rgba(255,255,255,.05));background-repeat:no-repeat}.table.b-table.table-hover>tbody>tr:hover>.table-b-table-default{color:#212529;background-image:linear-gradient(rgba(0,0,0,.075),rgba(0,0,0,.075));background-repeat:no-repeat}.table.b-table.table-hover.table-dark>tbody>tr:hover>.bg-b-table-default{color:#fff;background-image:linear-gradient(rgba(255,255,255,.075),rgba(255,255,255,.075));background-repeat:no-repeat}}.table.b-table>thead>tr>[aria-sort],.table.b-table>tfoot>tr>[aria-sort]{cursor:pointer;background-image:none;background-repeat:no-repeat;background-size:.65em 1em}.table.b-table>thead>tr>[aria-sort]:not(.b-table-sort-icon-left),.table.b-table>tfoot>tr>[aria-sort]:not(.b-table-sort-icon-left){background-position:right .375rem center;padding-right:calc(.75rem + .65em)}.table.b-table>thead>tr>[aria-sort].b-table-sort-icon-left,.table.b-table>tfoot>tr>[aria-sort].b-table-sort-icon-left{background-position:left .375rem center;padding-left:calc(.75rem + .65em)}.table.b-table>thead>tr>[aria-sort=none],.table.b-table>tfoot>tr>[aria-sort=none]{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='101' height='101' view-box='0 0 101 101' preserveAspectRatio='none'%3e%3cpath fill='black' opacity='.3' d='M51 1l25 23 24 22H1l25-22zM51 101l25-23 24-22H1l25 22z'/%3e%3c/svg%3e\")}.table.b-table>thead>tr>[aria-sort=ascending],.table.b-table>tfoot>tr>[aria-sort=ascending]{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='101' height='101' view-box='0 0 101 101' preserveAspectRatio='none'%3e%3cpath fill='black' d='M51 1l25 23 24 22H1l25-22z'/%3e%3cpath fill='black' opacity='.3' d='M51 101l25-23 24-22H1l25 22z'/%3e%3c/svg%3e\")}.table.b-table>thead>tr>[aria-sort=descending],.table.b-table>tfoot>tr>[aria-sort=descending]{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='101' height='101' view-box='0 0 101 101' preserveAspectRatio='none'%3e%3cpath fill='black' opacity='.3' d='M51 1l25 23 24 22H1l25-22z'/%3e%3cpath fill='black' d='M51 101l25-23 24-22H1l25 22z'/%3e%3c/svg%3e\")}.table.b-table.table-dark>thead>tr>[aria-sort=none],.table.b-table.table-dark>tfoot>tr>[aria-sort=none],.table.b-table>.thead-dark>tr>[aria-sort=none]{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='101' height='101' view-box='0 0 101 101' preserveAspectRatio='none'%3e%3cpath fill='white' opacity='.3' d='M51 1l25 23 24 22H1l25-22zM51 101l25-23 24-22H1l25 22z'/%3e%3c/svg%3e\")}.table.b-table.table-dark>thead>tr>[aria-sort=ascending],.table.b-table.table-dark>tfoot>tr>[aria-sort=ascending],.table.b-table>.thead-dark>tr>[aria-sort=ascending]{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='101' height='101' view-box='0 0 101 101' preserveAspectRatio='none'%3e%3cpath fill='white' d='M51 1l25 23 24 22H1l25-22z'/%3e%3cpath fill='white' opacity='.3' d='M51 101l25-23 24-22H1l25 22z'/%3e%3c/svg%3e\")}.table.b-table.table-dark>thead>tr>[aria-sort=descending],.table.b-table.table-dark>tfoot>tr>[aria-sort=descending],.table.b-table>.thead-dark>tr>[aria-sort=descending]{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='101' height='101' view-box='0 0 101 101' preserveAspectRatio='none'%3e%3cpath fill='white' opacity='.3' d='M51 1l25 23 24 22H1l25-22z'/%3e%3cpath fill='white' d='M51 101l25-23 24-22H1l25 22z'/%3e%3c/svg%3e\")}.table.b-table>thead>tr>.table-dark[aria-sort=none],.table.b-table>tfoot>tr>.table-dark[aria-sort=none]{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='101' height='101' view-box='0 0 101 101' preserveAspectRatio='none'%3e%3cpath fill='white' opacity='.3' d='M51 1l25 23 24 22H1l25-22zM51 101l25-23 24-22H1l25 22z'/%3e%3c/svg%3e\")}.table.b-table>thead>tr>.table-dark[aria-sort=ascending],.table.b-table>tfoot>tr>.table-dark[aria-sort=ascending]{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='101' height='101' view-box='0 0 101 101' preserveAspectRatio='none'%3e%3cpath fill='white' d='M51 1l25 23 24 22H1l25-22z'/%3e%3cpath fill='white' opacity='.3' d='M51 101l25-23 24-22H1l25 22z'/%3e%3c/svg%3e\")}.table.b-table>thead>tr>.table-dark[aria-sort=descending],.table.b-table>tfoot>tr>.table-dark[aria-sort=descending]{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='101' height='101' view-box='0 0 101 101' preserveAspectRatio='none'%3e%3cpath fill='white' opacity='.3' d='M51 1l25 23 24 22H1l25-22z'/%3e%3cpath fill='white' d='M51 101l25-23 24-22H1l25 22z'/%3e%3c/svg%3e\")}.table.b-table.table-sm>thead>tr>[aria-sort]:not(.b-table-sort-icon-left),.table.b-table.table-sm>tfoot>tr>[aria-sort]:not(.b-table-sort-icon-left){background-position:right .15rem center;padding-right:calc(.3rem + .65em)}.table.b-table.table-sm>thead>tr>[aria-sort].b-table-sort-icon-left,.table.b-table.table-sm>tfoot>tr>[aria-sort].b-table-sort-icon-left{background-position:left .15rem center;padding-left:calc(.3rem + .65em)}.table.b-table.b-table-selectable:not(.b-table-selectable-no-click)>tbody>tr{cursor:pointer}.table.b-table.b-table-selectable:not(.b-table-selectable-no-click).b-table-selecting.b-table-select-range>tbody>tr{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}@media (max-width: 575.98px){.table.b-table.b-table-stacked-sm{display:block;width:100%}.table.b-table.b-table-stacked-sm>caption,.table.b-table.b-table-stacked-sm>tbody,.table.b-table.b-table-stacked-sm>tbody>tr,.table.b-table.b-table-stacked-sm>tbody>tr>td,.table.b-table.b-table-stacked-sm>tbody>tr>th{display:block}.table.b-table.b-table-stacked-sm>thead,.table.b-table.b-table-stacked-sm>tfoot{display:none}.table.b-table.b-table-stacked-sm>thead>tr.b-table-top-row,.table.b-table.b-table-stacked-sm>thead>tr.b-table-bottom-row,.table.b-table.b-table-stacked-sm>tfoot>tr.b-table-top-row,.table.b-table.b-table-stacked-sm>tfoot>tr.b-table-bottom-row{display:none}.table.b-table.b-table-stacked-sm>caption{caption-side:top!important}.table.b-table.b-table-stacked-sm>tbody>tr>[data-label]:before{content:attr(data-label);width:40%;float:left;text-align:right;overflow-wrap:break-word;font-weight:700;font-style:normal;padding:0 .5rem 0 0;margin:0}.table.b-table.b-table-stacked-sm>tbody>tr>[data-label]:after{display:block;clear:both;content:\"\"}.table.b-table.b-table-stacked-sm>tbody>tr>[data-label]>div{display:inline-block;width:60%;padding:0 0 0 .5rem;margin:0}.table.b-table.b-table-stacked-sm>tbody>tr.top-row,.table.b-table.b-table-stacked-sm>tbody>tr.bottom-row{display:none}.table.b-table.b-table-stacked-sm>tbody>tr>:first-child{border-top-width:3px}.table.b-table.b-table-stacked-sm>tbody>tr>[rowspan]+td,.table.b-table.b-table-stacked-sm>tbody>tr>[rowspan]+th{border-top-width:3px}}@media (max-width: 767.98px){.table.b-table.b-table-stacked-md{display:block;width:100%}.table.b-table.b-table-stacked-md>caption,.table.b-table.b-table-stacked-md>tbody,.table.b-table.b-table-stacked-md>tbody>tr,.table.b-table.b-table-stacked-md>tbody>tr>td,.table.b-table.b-table-stacked-md>tbody>tr>th{display:block}.table.b-table.b-table-stacked-md>thead,.table.b-table.b-table-stacked-md>tfoot{display:none}.table.b-table.b-table-stacked-md>thead>tr.b-table-top-row,.table.b-table.b-table-stacked-md>thead>tr.b-table-bottom-row,.table.b-table.b-table-stacked-md>tfoot>tr.b-table-top-row,.table.b-table.b-table-stacked-md>tfoot>tr.b-table-bottom-row{display:none}.table.b-table.b-table-stacked-md>caption{caption-side:top!important}.table.b-table.b-table-stacked-md>tbody>tr>[data-label]:before{content:attr(data-label);width:40%;float:left;text-align:right;overflow-wrap:break-word;font-weight:700;font-style:normal;padding:0 .5rem 0 0;margin:0}.table.b-table.b-table-stacked-md>tbody>tr>[data-label]:after{display:block;clear:both;content:\"\"}.table.b-table.b-table-stacked-md>tbody>tr>[data-label]>div{display:inline-block;width:60%;padding:0 0 0 .5rem;margin:0}.table.b-table.b-table-stacked-md>tbody>tr.top-row,.table.b-table.b-table-stacked-md>tbody>tr.bottom-row{display:none}.table.b-table.b-table-stacked-md>tbody>tr>:first-child{border-top-width:3px}.table.b-table.b-table-stacked-md>tbody>tr>[rowspan]+td,.table.b-table.b-table-stacked-md>tbody>tr>[rowspan]+th{border-top-width:3px}}@media (max-width: 991.98px){.table.b-table.b-table-stacked-lg{display:block;width:100%}.table.b-table.b-table-stacked-lg>caption,.table.b-table.b-table-stacked-lg>tbody,.table.b-table.b-table-stacked-lg>tbody>tr,.table.b-table.b-table-stacked-lg>tbody>tr>td,.table.b-table.b-table-stacked-lg>tbody>tr>th{display:block}.table.b-table.b-table-stacked-lg>thead,.table.b-table.b-table-stacked-lg>tfoot{display:none}.table.b-table.b-table-stacked-lg>thead>tr.b-table-top-row,.table.b-table.b-table-stacked-lg>thead>tr.b-table-bottom-row,.table.b-table.b-table-stacked-lg>tfoot>tr.b-table-top-row,.table.b-table.b-table-stacked-lg>tfoot>tr.b-table-bottom-row{display:none}.table.b-table.b-table-stacked-lg>caption{caption-side:top!important}.table.b-table.b-table-stacked-lg>tbody>tr>[data-label]:before{content:attr(data-label);width:40%;float:left;text-align:right;overflow-wrap:break-word;font-weight:700;font-style:normal;padding:0 .5rem 0 0;margin:0}.table.b-table.b-table-stacked-lg>tbody>tr>[data-label]:after{display:block;clear:both;content:\"\"}.table.b-table.b-table-stacked-lg>tbody>tr>[data-label]>div{display:inline-block;width:60%;padding:0 0 0 .5rem;margin:0}.table.b-table.b-table-stacked-lg>tbody>tr.top-row,.table.b-table.b-table-stacked-lg>tbody>tr.bottom-row{display:none}.table.b-table.b-table-stacked-lg>tbody>tr>:first-child{border-top-width:3px}.table.b-table.b-table-stacked-lg>tbody>tr>[rowspan]+td,.table.b-table.b-table-stacked-lg>tbody>tr>[rowspan]+th{border-top-width:3px}}@media (max-width: 1199.98px){.table.b-table.b-table-stacked-xl{display:block;width:100%}.table.b-table.b-table-stacked-xl>caption,.table.b-table.b-table-stacked-xl>tbody,.table.b-table.b-table-stacked-xl>tbody>tr,.table.b-table.b-table-stacked-xl>tbody>tr>td,.table.b-table.b-table-stacked-xl>tbody>tr>th{display:block}.table.b-table.b-table-stacked-xl>thead,.table.b-table.b-table-stacked-xl>tfoot{display:none}.table.b-table.b-table-stacked-xl>thead>tr.b-table-top-row,.table.b-table.b-table-stacked-xl>thead>tr.b-table-bottom-row,.table.b-table.b-table-stacked-xl>tfoot>tr.b-table-top-row,.table.b-table.b-table-stacked-xl>tfoot>tr.b-table-bottom-row{display:none}.table.b-table.b-table-stacked-xl>caption{caption-side:top!important}.table.b-table.b-table-stacked-xl>tbody>tr>[data-label]:before{content:attr(data-label);width:40%;float:left;text-align:right;overflow-wrap:break-word;font-weight:700;font-style:normal;padding:0 .5rem 0 0;margin:0}.table.b-table.b-table-stacked-xl>tbody>tr>[data-label]:after{display:block;clear:both;content:\"\"}.table.b-table.b-table-stacked-xl>tbody>tr>[data-label]>div{display:inline-block;width:60%;padding:0 0 0 .5rem;margin:0}.table.b-table.b-table-stacked-xl>tbody>tr.top-row,.table.b-table.b-table-stacked-xl>tbody>tr.bottom-row{display:none}.table.b-table.b-table-stacked-xl>tbody>tr>:first-child{border-top-width:3px}.table.b-table.b-table-stacked-xl>tbody>tr>[rowspan]+td,.table.b-table.b-table-stacked-xl>tbody>tr>[rowspan]+th{border-top-width:3px}}.table.b-table.b-table-stacked{display:block;width:100%}.table.b-table.b-table-stacked>caption,.table.b-table.b-table-stacked>tbody,.table.b-table.b-table-stacked>tbody>tr,.table.b-table.b-table-stacked>tbody>tr>td,.table.b-table.b-table-stacked>tbody>tr>th{display:block}.table.b-table.b-table-stacked>thead,.table.b-table.b-table-stacked>tfoot{display:none}.table.b-table.b-table-stacked>thead>tr.b-table-top-row,.table.b-table.b-table-stacked>thead>tr.b-table-bottom-row,.table.b-table.b-table-stacked>tfoot>tr.b-table-top-row,.table.b-table.b-table-stacked>tfoot>tr.b-table-bottom-row{display:none}.table.b-table.b-table-stacked>caption{caption-side:top!important}.table.b-table.b-table-stacked>tbody>tr>[data-label]:before{content:attr(data-label);width:40%;float:left;text-align:right;overflow-wrap:break-word;font-weight:700;font-style:normal;padding:0 .5rem 0 0;margin:0}.table.b-table.b-table-stacked>tbody>tr>[data-label]:after{display:block;clear:both;content:\"\"}.table.b-table.b-table-stacked>tbody>tr>[data-label]>div{display:inline-block;width:60%;padding:0 0 0 .5rem;margin:0}.table.b-table.b-table-stacked>tbody>tr.top-row,.table.b-table.b-table-stacked>tbody>tr.bottom-row{display:none}.table.b-table.b-table-stacked>tbody>tr>:first-child{border-top-width:3px}.table.b-table.b-table-stacked>tbody>tr>[rowspan]+td,.table.b-table.b-table-stacked>tbody>tr>[rowspan]+th{border-top-width:3px}.b-time{min-width:150px}.b-time[aria-disabled=true] output,.b-time[aria-readonly=true] output,.b-time output.disabled{background-color:#e9ecef;opacity:1}.b-time[aria-disabled=true] output{pointer-events:none}[dir=rtl] .b-time>.d-flex:not(.flex-column){flex-direction:row-reverse}.b-time .b-time-header{margin-bottom:.5rem}.b-time .b-time-header output{padding:.25rem;font-size:80%}.b-time .b-time-footer{margin-top:.5rem}.b-time .b-time-ampm{margin-left:.5rem}.b-toast{display:block;position:relative;max-width:350px;-webkit-backface-visibility:hidden;backface-visibility:hidden;background-clip:padding-box;z-index:1;border-radius:.25rem}.b-toast .toast{background-color:#ffffffd9}.b-toast:not(:last-child){margin-bottom:.75rem}.b-toast.b-toast-solid .toast{background-color:#fff}.b-toast .toast{opacity:1}.b-toast .toast.fade:not(.show){opacity:0}.b-toast .toast .toast-body{display:block}.b-toast-primary .toast{background-color:#e6f2ffd9;border-color:#b8daffd9;color:#004085}.b-toast-primary .toast .toast-header{color:#004085;background-color:#cce5ffd9;border-bottom-color:#b8daffd9}.b-toast-primary.b-toast-solid .toast{background-color:#e6f2ff}.b-toast-secondary .toast{background-color:#eff0f1d9;border-color:#d6d8dbd9;color:#383d41}.b-toast-secondary .toast .toast-header{color:#383d41;background-color:#e2e3e5d9;border-bottom-color:#d6d8dbd9}.b-toast-secondary.b-toast-solid .toast{background-color:#eff0f1}.b-toast-success .toast{background-color:#e6f5e9d9;border-color:#c3e6cbd9;color:#155724}.b-toast-success .toast .toast-header{color:#155724;background-color:#d4eddad9;border-bottom-color:#c3e6cbd9}.b-toast-success.b-toast-solid .toast{background-color:#e6f5e9}.b-toast-info .toast{background-color:#e5f4f7d9;border-color:#bee5ebd9;color:#0c5460}.b-toast-info .toast .toast-header{color:#0c5460;background-color:#d1ecf1d9;border-bottom-color:#bee5ebd9}.b-toast-info.b-toast-solid .toast{background-color:#e5f4f7}.b-toast-warning .toast{background-color:#fff9e7d9;border-color:#ffeebad9;color:#856404}.b-toast-warning .toast .toast-header{color:#856404;background-color:#fff3cdd9;border-bottom-color:#ffeebad9}.b-toast-warning.b-toast-solid .toast{background-color:#fff9e7}.b-toast-danger .toast{background-color:#fcedeed9;border-color:#f5c6cbd9;color:#721c24}.b-toast-danger .toast .toast-header{color:#721c24;background-color:#f8d7dad9;border-bottom-color:#f5c6cbd9}.b-toast-danger.b-toast-solid .toast{background-color:#fcedee}.b-toast-light .toast{background-color:#ffffffd9;border-color:#fdfdfed9;color:#818182}.b-toast-light .toast .toast-header{color:#818182;background-color:#fefefed9;border-bottom-color:#fdfdfed9}.b-toast-light.b-toast-solid .toast{background-color:#fff}.b-toast-dark .toast{background-color:#e3e5e5d9;border-color:#c6c8cad9;color:#1b1e21}.b-toast-dark .toast .toast-header{color:#1b1e21;background-color:#d6d8d9d9;border-bottom-color:#c6c8cad9}.b-toast-dark.b-toast-solid .toast{background-color:#e3e5e5}.b-toaster{z-index:1100}.b-toaster .b-toaster-slot{position:relative;display:block}.b-toaster .b-toaster-slot:empty{display:none!important}.b-toaster.b-toaster-top-right,.b-toaster.b-toaster-top-left,.b-toaster.b-toaster-top-center,.b-toaster.b-toaster-top-full,.b-toaster.b-toaster-bottom-right,.b-toaster.b-toaster-bottom-left,.b-toaster.b-toaster-bottom-center,.b-toaster.b-toaster-bottom-full{position:fixed;left:.5rem;right:.5rem;margin:0;padding:0;height:0;overflow:visible}.b-toaster.b-toaster-top-right .b-toaster-slot,.b-toaster.b-toaster-top-left .b-toaster-slot,.b-toaster.b-toaster-top-center .b-toaster-slot,.b-toaster.b-toaster-top-full .b-toaster-slot,.b-toaster.b-toaster-bottom-right .b-toaster-slot,.b-toaster.b-toaster-bottom-left .b-toaster-slot,.b-toaster.b-toaster-bottom-center .b-toaster-slot,.b-toaster.b-toaster-bottom-full .b-toaster-slot{position:absolute;max-width:350px;width:100%;left:0;right:0;padding:0;margin:0}.b-toaster.b-toaster-top-full .b-toaster-slot,.b-toaster.b-toaster-bottom-full .b-toaster-slot,.b-toaster.b-toaster-top-full .b-toaster-slot .b-toast,.b-toaster.b-toaster-top-full .b-toaster-slot .toast,.b-toaster.b-toaster-bottom-full .b-toaster-slot .b-toast,.b-toaster.b-toaster-bottom-full .b-toaster-slot .toast{width:100%;max-width:100%}.b-toaster.b-toaster-top-right,.b-toaster.b-toaster-top-left,.b-toaster.b-toaster-top-center,.b-toaster.b-toaster-top-full{top:0}.b-toaster.b-toaster-top-right .b-toaster-slot,.b-toaster.b-toaster-top-left .b-toaster-slot,.b-toaster.b-toaster-top-center .b-toaster-slot,.b-toaster.b-toaster-top-full .b-toaster-slot{top:.5rem}.b-toaster.b-toaster-bottom-right,.b-toaster.b-toaster-bottom-left,.b-toaster.b-toaster-bottom-center,.b-toaster.b-toaster-bottom-full{bottom:0}.b-toaster.b-toaster-bottom-right .b-toaster-slot,.b-toaster.b-toaster-bottom-left .b-toaster-slot,.b-toaster.b-toaster-bottom-center .b-toaster-slot,.b-toaster.b-toaster-bottom-full .b-toaster-slot{bottom:.5rem}.b-toaster.b-toaster-top-right .b-toaster-slot,.b-toaster.b-toaster-bottom-right .b-toaster-slot,.b-toaster.b-toaster-top-center .b-toaster-slot,.b-toaster.b-toaster-bottom-center .b-toaster-slot{margin-left:auto}.b-toaster.b-toaster-top-left .b-toaster-slot,.b-toaster.b-toaster-bottom-left .b-toaster-slot,.b-toaster.b-toaster-top-center .b-toaster-slot,.b-toaster.b-toaster-bottom-center .b-toaster-slot{margin-right:auto}.b-toaster.b-toaster-top-right .b-toast.b-toaster-enter-active,.b-toaster.b-toaster-top-right .b-toast.b-toaster-leave-active,.b-toaster.b-toaster-top-right .b-toast.b-toaster-move,.b-toaster.b-toaster-top-left .b-toast.b-toaster-enter-active,.b-toaster.b-toaster-top-left .b-toast.b-toaster-leave-active,.b-toaster.b-toaster-top-left .b-toast.b-toaster-move,.b-toaster.b-toaster-bottom-right .b-toast.b-toaster-enter-active,.b-toaster.b-toaster-bottom-right .b-toast.b-toaster-leave-active,.b-toaster.b-toaster-bottom-right .b-toast.b-toaster-move,.b-toaster.b-toaster-bottom-left .b-toast.b-toaster-enter-active,.b-toaster.b-toaster-bottom-left .b-toast.b-toaster-leave-active,.b-toaster.b-toaster-bottom-left .b-toast.b-toaster-move{transition:-webkit-transform .175s;transition:transform .175s;transition:transform .175s,-webkit-transform .175s}.b-toaster.b-toaster-top-right .b-toast.b-toaster-enter-to .toast.fade,.b-toaster.b-toaster-top-right .b-toast.b-toaster-enter-active .toast.fade,.b-toaster.b-toaster-top-left .b-toast.b-toaster-enter-to .toast.fade,.b-toaster.b-toaster-top-left .b-toast.b-toaster-enter-active .toast.fade,.b-toaster.b-toaster-bottom-right .b-toast.b-toaster-enter-to .toast.fade,.b-toaster.b-toaster-bottom-right .b-toast.b-toaster-enter-active .toast.fade,.b-toaster.b-toaster-bottom-left .b-toast.b-toaster-enter-to .toast.fade,.b-toaster.b-toaster-bottom-left .b-toast.b-toaster-enter-active .toast.fade{transition-delay:.175s}.b-toaster.b-toaster-top-right .b-toast.b-toaster-leave-active,.b-toaster.b-toaster-top-left .b-toast.b-toaster-leave-active,.b-toaster.b-toaster-bottom-right .b-toast.b-toaster-leave-active,.b-toaster.b-toaster-bottom-left .b-toast.b-toaster-leave-active{position:absolute;transition-delay:.175s}.b-toaster.b-toaster-top-right .b-toast.b-toaster-leave-active .toast.fade,.b-toaster.b-toaster-top-left .b-toast.b-toaster-leave-active .toast.fade,.b-toaster.b-toaster-bottom-right .b-toast.b-toaster-leave-active .toast.fade,.b-toaster.b-toaster-bottom-left .b-toast.b-toaster-leave-active .toast.fade{transition-delay:0s}.tooltip.b-tooltip{display:block;opacity:.9;outline:0}.tooltip.b-tooltip.fade:not(.show){opacity:0}.tooltip.b-tooltip.show{opacity:.9}.tooltip.b-tooltip.noninteractive{pointer-events:none}.tooltip.b-tooltip .arrow{margin:0 .25rem}.tooltip.b-tooltip.bs-tooltip-right .arrow,.tooltip.b-tooltip.b-tooltip-dark.bs-tooltip-auto[x-placement^=right] .arrow,.tooltip.b-tooltip.b-tooltip-light.bs-tooltip-auto[x-placement^=right] .arrow,.tooltip.b-tooltip.b-tooltip-danger.bs-tooltip-auto[x-placement^=right] .arrow,.tooltip.b-tooltip.b-tooltip-warning.bs-tooltip-auto[x-placement^=right] .arrow,.tooltip.b-tooltip.b-tooltip-info.bs-tooltip-auto[x-placement^=right] .arrow,.tooltip.b-tooltip.b-tooltip-success.bs-tooltip-auto[x-placement^=right] .arrow,.tooltip.b-tooltip.b-tooltip-secondary.bs-tooltip-auto[x-placement^=right] .arrow,.tooltip.b-tooltip.b-tooltip-primary.bs-tooltip-auto[x-placement^=right] .arrow,.tooltip.b-tooltip.bs-tooltip-left .arrow,.tooltip.b-tooltip.b-tooltip-dark.bs-tooltip-auto[x-placement^=left] .arrow,.tooltip.b-tooltip.b-tooltip-light.bs-tooltip-auto[x-placement^=left] .arrow,.tooltip.b-tooltip.b-tooltip-danger.bs-tooltip-auto[x-placement^=left] .arrow,.tooltip.b-tooltip.b-tooltip-warning.bs-tooltip-auto[x-placement^=left] .arrow,.tooltip.b-tooltip.b-tooltip-info.bs-tooltip-auto[x-placement^=left] .arrow,.tooltip.b-tooltip.b-tooltip-success.bs-tooltip-auto[x-placement^=left] .arrow,.tooltip.b-tooltip.b-tooltip-secondary.bs-tooltip-auto[x-placement^=left] .arrow,.tooltip.b-tooltip.b-tooltip-primary.bs-tooltip-auto[x-placement^=left] .arrow{margin:.25rem 0}.tooltip.b-tooltip-primary.bs-tooltip-top .arrow:before,.tooltip.b-tooltip-primary.bs-tooltip-auto[x-placement^=top] .arrow:before{border-top-color:#007bff}.tooltip.b-tooltip-primary.bs-tooltip-right .arrow:before,.tooltip.b-tooltip-primary.bs-tooltip-auto[x-placement^=right] .arrow:before{border-right-color:#007bff}.tooltip.b-tooltip-primary.bs-tooltip-bottom .arrow:before,.tooltip.b-tooltip-primary.bs-tooltip-auto[x-placement^=bottom] .arrow:before{border-bottom-color:#007bff}.tooltip.b-tooltip-primary.bs-tooltip-left .arrow:before,.tooltip.b-tooltip-primary.bs-tooltip-auto[x-placement^=left] .arrow:before{border-left-color:#007bff}.tooltip.b-tooltip-primary .tooltip-inner{color:#fff;background-color:#007bff}.tooltip.b-tooltip-secondary.bs-tooltip-top .arrow:before,.tooltip.b-tooltip-secondary.bs-tooltip-auto[x-placement^=top] .arrow:before{border-top-color:#6c757d}.tooltip.b-tooltip-secondary.bs-tooltip-right .arrow:before,.tooltip.b-tooltip-secondary.bs-tooltip-auto[x-placement^=right] .arrow:before{border-right-color:#6c757d}.tooltip.b-tooltip-secondary.bs-tooltip-bottom .arrow:before,.tooltip.b-tooltip-secondary.bs-tooltip-auto[x-placement^=bottom] .arrow:before{border-bottom-color:#6c757d}.tooltip.b-tooltip-secondary.bs-tooltip-left .arrow:before,.tooltip.b-tooltip-secondary.bs-tooltip-auto[x-placement^=left] .arrow:before{border-left-color:#6c757d}.tooltip.b-tooltip-secondary .tooltip-inner{color:#fff;background-color:#6c757d}.tooltip.b-tooltip-success.bs-tooltip-top .arrow:before,.tooltip.b-tooltip-success.bs-tooltip-auto[x-placement^=top] .arrow:before{border-top-color:#28a745}.tooltip.b-tooltip-success.bs-tooltip-right .arrow:before,.tooltip.b-tooltip-success.bs-tooltip-auto[x-placement^=right] .arrow:before{border-right-color:#28a745}.tooltip.b-tooltip-success.bs-tooltip-bottom .arrow:before,.tooltip.b-tooltip-success.bs-tooltip-auto[x-placement^=bottom] .arrow:before{border-bottom-color:#28a745}.tooltip.b-tooltip-success.bs-tooltip-left .arrow:before,.tooltip.b-tooltip-success.bs-tooltip-auto[x-placement^=left] .arrow:before{border-left-color:#28a745}.tooltip.b-tooltip-success .tooltip-inner{color:#fff;background-color:#28a745}.tooltip.b-tooltip-info.bs-tooltip-top .arrow:before,.tooltip.b-tooltip-info.bs-tooltip-auto[x-placement^=top] .arrow:before{border-top-color:#17a2b8}.tooltip.b-tooltip-info.bs-tooltip-right .arrow:before,.tooltip.b-tooltip-info.bs-tooltip-auto[x-placement^=right] .arrow:before{border-right-color:#17a2b8}.tooltip.b-tooltip-info.bs-tooltip-bottom .arrow:before,.tooltip.b-tooltip-info.bs-tooltip-auto[x-placement^=bottom] .arrow:before{border-bottom-color:#17a2b8}.tooltip.b-tooltip-info.bs-tooltip-left .arrow:before,.tooltip.b-tooltip-info.bs-tooltip-auto[x-placement^=left] .arrow:before{border-left-color:#17a2b8}.tooltip.b-tooltip-info .tooltip-inner{color:#fff;background-color:#17a2b8}.tooltip.b-tooltip-warning.bs-tooltip-top .arrow:before,.tooltip.b-tooltip-warning.bs-tooltip-auto[x-placement^=top] .arrow:before{border-top-color:#ffc107}.tooltip.b-tooltip-warning.bs-tooltip-right .arrow:before,.tooltip.b-tooltip-warning.bs-tooltip-auto[x-placement^=right] .arrow:before{border-right-color:#ffc107}.tooltip.b-tooltip-warning.bs-tooltip-bottom .arrow:before,.tooltip.b-tooltip-warning.bs-tooltip-auto[x-placement^=bottom] .arrow:before{border-bottom-color:#ffc107}.tooltip.b-tooltip-warning.bs-tooltip-left .arrow:before,.tooltip.b-tooltip-warning.bs-tooltip-auto[x-placement^=left] .arrow:before{border-left-color:#ffc107}.tooltip.b-tooltip-warning .tooltip-inner{color:#212529;background-color:#ffc107}.tooltip.b-tooltip-danger.bs-tooltip-top .arrow:before,.tooltip.b-tooltip-danger.bs-tooltip-auto[x-placement^=top] .arrow:before{border-top-color:#dc3545}.tooltip.b-tooltip-danger.bs-tooltip-right .arrow:before,.tooltip.b-tooltip-danger.bs-tooltip-auto[x-placement^=right] .arrow:before{border-right-color:#dc3545}.tooltip.b-tooltip-danger.bs-tooltip-bottom .arrow:before,.tooltip.b-tooltip-danger.bs-tooltip-auto[x-placement^=bottom] .arrow:before{border-bottom-color:#dc3545}.tooltip.b-tooltip-danger.bs-tooltip-left .arrow:before,.tooltip.b-tooltip-danger.bs-tooltip-auto[x-placement^=left] .arrow:before{border-left-color:#dc3545}.tooltip.b-tooltip-danger .tooltip-inner{color:#fff;background-color:#dc3545}.tooltip.b-tooltip-light.bs-tooltip-top .arrow:before,.tooltip.b-tooltip-light.bs-tooltip-auto[x-placement^=top] .arrow:before{border-top-color:#f8f9fa}.tooltip.b-tooltip-light.bs-tooltip-right .arrow:before,.tooltip.b-tooltip-light.bs-tooltip-auto[x-placement^=right] .arrow:before{border-right-color:#f8f9fa}.tooltip.b-tooltip-light.bs-tooltip-bottom .arrow:before,.tooltip.b-tooltip-light.bs-tooltip-auto[x-placement^=bottom] .arrow:before{border-bottom-color:#f8f9fa}.tooltip.b-tooltip-light.bs-tooltip-left .arrow:before,.tooltip.b-tooltip-light.bs-tooltip-auto[x-placement^=left] .arrow:before{border-left-color:#f8f9fa}.tooltip.b-tooltip-light .tooltip-inner{color:#212529;background-color:#f8f9fa}.tooltip.b-tooltip-dark.bs-tooltip-top .arrow:before,.tooltip.b-tooltip-dark.bs-tooltip-auto[x-placement^=top] .arrow:before{border-top-color:#343a40}.tooltip.b-tooltip-dark.bs-tooltip-right .arrow:before,.tooltip.b-tooltip-dark.bs-tooltip-auto[x-placement^=right] .arrow:before{border-right-color:#343a40}.tooltip.b-tooltip-dark.bs-tooltip-bottom .arrow:before,.tooltip.b-tooltip-dark.bs-tooltip-auto[x-placement^=bottom] .arrow:before{border-bottom-color:#343a40}.tooltip.b-tooltip-dark.bs-tooltip-left .arrow:before,.tooltip.b-tooltip-dark.bs-tooltip-auto[x-placement^=left] .arrow:before{border-left-color:#343a40}.tooltip.b-tooltip-dark .tooltip-inner{color:#fff;background-color:#343a40}.b-icon.bi{display:inline-block;overflow:visible;vertical-align:-.15em}.b-icon.b-icon-animation-cylon,.b-icon.b-iconstack .b-icon-animation-cylon>g{-webkit-transform-origin:center;transform-origin:center;-webkit-animation:.75s infinite ease-in-out alternate b-icon-animation-cylon;animation:.75s infinite ease-in-out alternate b-icon-animation-cylon}@media (prefers-reduced-motion: reduce){.b-icon.b-icon-animation-cylon,.b-icon.b-iconstack .b-icon-animation-cylon>g{-webkit-animation:none;animation:none}}.b-icon.b-icon-animation-cylon-vertical,.b-icon.b-iconstack .b-icon-animation-cylon-vertical>g{-webkit-transform-origin:center;transform-origin:center;-webkit-animation:.75s infinite ease-in-out alternate b-icon-animation-cylon-vertical;animation:.75s infinite ease-in-out alternate b-icon-animation-cylon-vertical}@media (prefers-reduced-motion: reduce){.b-icon.b-icon-animation-cylon-vertical,.b-icon.b-iconstack .b-icon-animation-cylon-vertical>g{-webkit-animation:none;animation:none}}.b-icon.b-icon-animation-fade,.b-icon.b-iconstack .b-icon-animation-fade>g{-webkit-transform-origin:center;transform-origin:center;-webkit-animation:.75s infinite ease-in-out alternate b-icon-animation-fade;animation:.75s infinite ease-in-out alternate b-icon-animation-fade}@media (prefers-reduced-motion: reduce){.b-icon.b-icon-animation-fade,.b-icon.b-iconstack .b-icon-animation-fade>g{-webkit-animation:none;animation:none}}.b-icon.b-icon-animation-spin,.b-icon.b-iconstack .b-icon-animation-spin>g{-webkit-transform-origin:center;transform-origin:center;-webkit-animation:2s infinite linear normal b-icon-animation-spin;animation:2s infinite linear normal b-icon-animation-spin}@media (prefers-reduced-motion: reduce){.b-icon.b-icon-animation-spin,.b-icon.b-iconstack .b-icon-animation-spin>g{-webkit-animation:none;animation:none}}.b-icon.b-icon-animation-spin-reverse,.b-icon.b-iconstack .b-icon-animation-spin-reverse>g{-webkit-transform-origin:center;transform-origin:center;animation:2s infinite linear reverse b-icon-animation-spin}@media (prefers-reduced-motion: reduce){.b-icon.b-icon-animation-spin-reverse,.b-icon.b-iconstack .b-icon-animation-spin-reverse>g{-webkit-animation:none;animation:none}}.b-icon.b-icon-animation-spin-pulse,.b-icon.b-iconstack .b-icon-animation-spin-pulse>g{-webkit-transform-origin:center;transform-origin:center;-webkit-animation:1s infinite steps(8) normal b-icon-animation-spin;animation:1s infinite steps(8) normal b-icon-animation-spin}@media (prefers-reduced-motion: reduce){.b-icon.b-icon-animation-spin-pulse,.b-icon.b-iconstack .b-icon-animation-spin-pulse>g{-webkit-animation:none;animation:none}}.b-icon.b-icon-animation-spin-reverse-pulse,.b-icon.b-iconstack .b-icon-animation-spin-reverse-pulse>g{-webkit-transform-origin:center;transform-origin:center;animation:1s infinite steps(8) reverse b-icon-animation-spin}@media (prefers-reduced-motion: reduce){.b-icon.b-icon-animation-spin-reverse-pulse,.b-icon.b-iconstack .b-icon-animation-spin-reverse-pulse>g{-webkit-animation:none;animation:none}}.b-icon.b-icon-animation-throb,.b-icon.b-iconstack .b-icon-animation-throb>g{-webkit-transform-origin:center;transform-origin:center;-webkit-animation:.75s infinite ease-in-out alternate b-icon-animation-throb;animation:.75s infinite ease-in-out alternate b-icon-animation-throb}@media (prefers-reduced-motion: reduce){.b-icon.b-icon-animation-throb,.b-icon.b-iconstack .b-icon-animation-throb>g{-webkit-animation:none;animation:none}}@-webkit-keyframes b-icon-animation-cylon{0%{-webkit-transform:translateX(-25%);transform:translate(-25%)}to{-webkit-transform:translateX(25%);transform:translate(25%)}}@keyframes b-icon-animation-cylon{0%{-webkit-transform:translateX(-25%);transform:translate(-25%)}to{-webkit-transform:translateX(25%);transform:translate(25%)}}@-webkit-keyframes b-icon-animation-cylon-vertical{0%{-webkit-transform:translateY(25%);transform:translateY(25%)}to{-webkit-transform:translateY(-25%);transform:translateY(-25%)}}@keyframes b-icon-animation-cylon-vertical{0%{-webkit-transform:translateY(25%);transform:translateY(25%)}to{-webkit-transform:translateY(-25%);transform:translateY(-25%)}}@-webkit-keyframes b-icon-animation-fade{0%{opacity:.1}to{opacity:1}}@keyframes b-icon-animation-fade{0%{opacity:.1}to{opacity:1}}@-webkit-keyframes b-icon-animation-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes b-icon-animation-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes b-icon-animation-throb{0%{opacity:.5;-webkit-transform:scale(.5);transform:scale(.5)}to{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes b-icon-animation-throb{0%{opacity:.5;-webkit-transform:scale(.5);transform:scale(.5)}to{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}.btn .b-icon.bi,.nav-link .b-icon.bi,.dropdown-toggle .b-icon.bi,.dropdown-item .b-icon.bi,.input-group-text .b-icon.bi{font-size:125%;vertical-align:text-bottom}\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/dist/assets/index.909977fe.js",
    "content": "(function(){const e=document.createElement(\"link\").relList;if(e&&e.supports&&e.supports(\"modulepreload\"))return;for(const i of document.querySelectorAll('link[rel=\"modulepreload\"]'))n(i);new MutationObserver(i=>{for(const a of i)if(a.type===\"childList\")for(const o of a.addedNodes)o.tagName===\"LINK\"&&o.rel===\"modulepreload\"&&n(o)}).observe(document,{childList:!0,subtree:!0});function r(i){const a={};return i.integrity&&(a.integrity=i.integrity),i.referrerpolicy&&(a.referrerPolicy=i.referrerpolicy),i.crossorigin===\"use-credentials\"?a.credentials=\"include\":i.crossorigin===\"anonymous\"?a.credentials=\"omit\":a.credentials=\"same-origin\",a}function n(i){if(i.ep)return;i.ep=!0;const a=r(i);fetch(i.href,a)}})();/*!\n * Vue.js v2.7.16\n * (c) 2014-2023 Evan You\n * Released under the MIT License.\n */var pn=Object.freeze({}),Ne=Array.isArray;function Oe(t){return t==null}function L(t){return t!=null}function _t(t){return t===!0}function vI(t){return t===!1}function ju(t){return typeof t==\"string\"||typeof t==\"number\"||typeof t==\"symbol\"||typeof t==\"boolean\"}function gt(t){return typeof t==\"function\"}function gr(t){return t!==null&&typeof t==\"object\"}var rb=Object.prototype.toString;function On(t){return rb.call(t)===\"[object Object]\"}function mI(t){return rb.call(t)===\"[object RegExp]\"}function m1(t){var e=parseFloat(String(t));return e>=0&&Math.floor(e)===e&&isFinite(t)}function pm(t){return L(t)&&typeof t.then==\"function\"&&typeof t.catch==\"function\"}function gI(t){return t==null?\"\":Array.isArray(t)||On(t)&&t.toString===rb?JSON.stringify(t,bI,2):String(t)}function bI(t,e){return e&&e.__v_isRef?e.value:e}function _u(t){var e=parseFloat(t);return isNaN(e)?t:e}function Jn(t,e){for(var r=Object.create(null),n=t.split(\",\"),i=0;i<n.length;i++)r[n[i]]=!0;return e?function(a){return r[a.toLowerCase()]}:function(a){return r[a]}}Jn(\"slot,component\",!0);var yI=Jn(\"key,ref,slot,slot-scope,is\");function Ma(t,e){var r=t.length;if(r){if(e===t[r-1]){t.length=r-1;return}var n=t.indexOf(e);if(n>-1)return t.splice(n,1)}}var OI=Object.prototype.hasOwnProperty;function Cr(t,e){return OI.call(t,e)}function No(t){var e=Object.create(null);return function(n){var i=e[n];return i||(e[n]=t(n))}}var _I=/-(\\w)/g,Oo=No(function(t){return t.replace(_I,function(e,r){return r?r.toUpperCase():\"\"})}),wI=No(function(t){return t.charAt(0).toUpperCase()+t.slice(1)}),TI=/\\B([A-Z])/g,Vu=No(function(t){return t.replace(TI,\"-$1\").toLowerCase()});function SI(t,e){function r(n){var i=arguments.length;return i?i>1?t.apply(e,arguments):t.call(e,n):t.call(e)}return r._length=t.length,r}function PI(t,e){return t.bind(e)}var g1=Function.prototype.bind?PI:SI;function hm(t,e){e=e||0;for(var r=t.length-e,n=new Array(r);r--;)n[r]=t[r+e];return n}function ut(t,e){for(var r in e)t[r]=e[r];return t}function b1(t){for(var e={},r=0;r<t.length;r++)t[r]&&ut(e,t[r]);return e}function Qt(t,e,r){}var Oc=function(t,e,r){return!1},y1=function(t){return t};function _o(t,e){if(t===e)return!0;var r=gr(t),n=gr(e);if(r&&n)try{var i=Array.isArray(t),a=Array.isArray(e);if(i&&a)return t.length===e.length&&t.every(function(l,u){return _o(l,e[u])});if(t instanceof Date&&e instanceof Date)return t.getTime()===e.getTime();if(!i&&!a){var o=Object.keys(t),s=Object.keys(e);return o.length===s.length&&o.every(function(l){return _o(t[l],e[l])})}else return!1}catch{return!1}else return!r&&!n?String(t)===String(e):!1}function O1(t,e){for(var r=0;r<t.length;r++)if(_o(t[r],e))return r;return-1}function jf(t){var e=!1;return function(){e||(e=!0,t.apply(this,arguments))}}function EI(t,e){return t===e?t===0&&1/t!==1/e:t===t||e===e}var xO=\"data-server-rendered\",Qd=[\"component\",\"directive\",\"filter\"],_1=[\"beforeCreate\",\"created\",\"beforeMount\",\"mounted\",\"beforeUpdate\",\"updated\",\"beforeDestroy\",\"destroyed\",\"activated\",\"deactivated\",\"errorCaptured\",\"serverPrefetch\",\"renderTracked\",\"renderTriggered\"],Bn={optionMergeStrategies:Object.create(null),silent:!1,productionTip:!1,devtools:!1,performance:!1,errorHandler:null,warnHandler:null,ignoredElements:[],keyCodes:Object.create(null),isReservedTag:Oc,isReservedAttr:Oc,isUnknownElement:Oc,getTagNamespace:Qt,parsePlatformTagName:y1,mustUseProp:Oc,async:!0,_lifecycleHooks:_1},$I=/a-zA-Z\\u00B7\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u203F-\\u2040\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD/;function w1(t){var e=(t+\"\").charCodeAt(0);return e===36||e===95}function ga(t,e,r,n){Object.defineProperty(t,e,{value:r,enumerable:!!n,writable:!0,configurable:!0})}var CI=new RegExp(\"[^\".concat($I.source,\".$_\\\\d]\"));function DI(t){if(!CI.test(t)){var e=t.split(\".\");return function(r){for(var n=0;n<e.length;n++){if(!r)return;r=r[e[n]]}return r}}}var AI=\"__proto__\"in{},wn=typeof window<\"u\",br=wn&&window.navigator.userAgent.toLowerCase(),Xs=br&&/msie|trident/.test(br),Js=br&&br.indexOf(\"msie 9.0\")>0,nb=br&&br.indexOf(\"edge/\")>0;br&&br.indexOf(\"android\")>0;var RI=br&&/iphone|ipad|ipod|ios/.test(br);br&&/chrome\\/\\d+/.test(br);br&&/phantomjs/.test(br);var MO=br&&br.match(/firefox\\/(\\d+)/),vm={}.watch,T1=!1;if(wn)try{var NO={};Object.defineProperty(NO,\"passive\",{get:function(){T1=!0}}),window.addEventListener(\"test-passive\",null,NO)}catch{}var _c,Hu=function(){return _c===void 0&&(!wn&&typeof global<\"u\"?_c=global.process&&global.process.env.VUE_ENV===\"server\":_c=!1),_c},Vf=wn&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function Cs(t){return typeof t==\"function\"&&/native code/.test(t.toString())}var zu=typeof Symbol<\"u\"&&Cs(Symbol)&&typeof Reflect<\"u\"&&Cs(Reflect.ownKeys),wu;typeof Set<\"u\"&&Cs(Set)?wu=Set:wu=function(){function t(){this.set=Object.create(null)}return t.prototype.has=function(e){return this.set[e]===!0},t.prototype.add=function(e){this.set[e]=!0},t.prototype.clear=function(){this.set=Object.create(null)},t}();var Ds=null;function Sa(t){t===void 0&&(t=null),t||Ds&&Ds._scope.off(),Ds=t,t&&t._scope.on()}var _n=function(){function t(e,r,n,i,a,o,s,l){this.tag=e,this.data=r,this.children=n,this.text=i,this.elm=a,this.ns=void 0,this.context=o,this.fnContext=void 0,this.fnOptions=void 0,this.fnScopeId=void 0,this.key=r&&r.key,this.componentOptions=s,this.componentInstance=void 0,this.parent=void 0,this.raw=!1,this.isStatic=!1,this.isRootInsert=!0,this.isComment=!1,this.isCloned=!1,this.isOnce=!1,this.asyncFactory=l,this.asyncMeta=void 0,this.isAsyncPlaceholder=!1}return Object.defineProperty(t.prototype,\"child\",{get:function(){return this.componentInstance},enumerable:!1,configurable:!0}),t}(),co=function(t){t===void 0&&(t=\"\");var e=new _n;return e.text=t,e.isComment=!0,e};function ys(t){return new _n(void 0,void 0,void 0,String(t))}function mm(t){var e=new _n(t.tag,t.data,t.children&&t.children.slice(),t.text,t.elm,t.context,t.componentOptions,t.asyncFactory);return e.ns=t.ns,e.isStatic=t.isStatic,e.key=t.key,e.isComment=t.isComment,e.fnContext=t.fnContext,e.fnOptions=t.fnOptions,e.fnScopeId=t.fnScopeId,e.asyncMeta=t.asyncMeta,e.isCloned=!0,e}var xI=0,tf=[],MI=function(){for(var t=0;t<tf.length;t++){var e=tf[t];e.subs=e.subs.filter(function(r){return r}),e._pending=!1}tf.length=0},Pa=function(){function t(){this._pending=!1,this.id=xI++,this.subs=[]}return t.prototype.addSub=function(e){this.subs.push(e)},t.prototype.removeSub=function(e){this.subs[this.subs.indexOf(e)]=null,this._pending||(this._pending=!0,tf.push(this))},t.prototype.depend=function(e){t.target&&t.target.addDep(this)},t.prototype.notify=function(e){for(var r=this.subs.filter(function(o){return o}),n=0,i=r.length;n<i;n++){var a=r[n];a.update()}},t}();Pa.target=null;var rf=[];function Zs(t){rf.push(t),Pa.target=t}function Qs(){rf.pop(),Pa.target=rf[rf.length-1]}var S1=Array.prototype,Hf=Object.create(S1),NI=[\"push\",\"pop\",\"shift\",\"unshift\",\"splice\",\"sort\",\"reverse\"];NI.forEach(function(t){var e=S1[t];ga(Hf,t,function(){for(var n=[],i=0;i<arguments.length;i++)n[i]=arguments[i];var a=e.apply(this,n),o=this.__ob__,s;switch(t){case\"push\":case\"unshift\":s=n;break;case\"splice\":s=n.slice(2);break}return s&&o.observeArray(s),o.dep.notify(),a})});var IO=Object.getOwnPropertyNames(Hf),P1={},ib=!0;function Ea(t){ib=t}var II={notify:Qt,depend:Qt,addSub:Qt,removeSub:Qt},BO=function(){function t(e,r,n){if(r===void 0&&(r=!1),n===void 0&&(n=!1),this.value=e,this.shallow=r,this.mock=n,this.dep=n?II:new Pa,this.vmCount=0,ga(e,\"__ob__\",this),Ne(e)){if(!n)if(AI)e.__proto__=Hf;else for(var i=0,a=IO.length;i<a;i++){var o=IO[i];ga(e,o,Hf[o])}r||this.observeArray(e)}else for(var s=Object.keys(e),i=0;i<s.length;i++){var o=s[i];wo(e,o,P1,void 0,r,n)}}return t.prototype.observeArray=function(e){for(var r=0,n=e.length;r<n;r++)Gi(e[r],!1,this.mock)},t}();function Gi(t,e,r){if(t&&Cr(t,\"__ob__\")&&t.__ob__ instanceof BO)return t.__ob__;if(ib&&(r||!Hu())&&(Ne(t)||On(t))&&Object.isExtensible(t)&&!t.__v_skip&&!hi(t)&&!(t instanceof _n))return new BO(t,e,r)}function wo(t,e,r,n,i,a,o){o===void 0&&(o=!1);var s=new Pa,l=Object.getOwnPropertyDescriptor(t,e);if(!(l&&l.configurable===!1)){var u=l&&l.get,f=l&&l.set;(!u||f)&&(r===P1||arguments.length===2)&&(r=t[e]);var d=i?r&&r.__ob__:Gi(r,!1,a);return Object.defineProperty(t,e,{enumerable:!0,configurable:!0,get:function(){var h=u?u.call(t):r;return Pa.target&&(s.depend(),d&&(d.dep.depend(),Ne(h)&&$1(h))),hi(h)&&!i?h.value:h},set:function(h){var b=u?u.call(t):r;if(!!EI(b,h)){if(f)f.call(t,h);else{if(u)return;if(!i&&hi(b)&&!hi(h)){b.value=h;return}else r=h}d=i?h&&h.__ob__:Gi(h,!1,a),s.notify()}}}),s}}function ab(t,e,r){if(!ob(t)){var n=t.__ob__;return Ne(t)&&m1(e)?(t.length=Math.max(t.length,e),t.splice(e,1,r),n&&!n.shallow&&n.mock&&Gi(r,!1,!0),r):e in t&&!(e in Object.prototype)?(t[e]=r,r):t._isVue||n&&n.vmCount?r:n?(wo(n.value,e,r,void 0,n.shallow,n.mock),n.dep.notify(),r):(t[e]=r,r)}}function E1(t,e){if(Ne(t)&&m1(e)){t.splice(e,1);return}var r=t.__ob__;t._isVue||r&&r.vmCount||ob(t)||!Cr(t,e)||(delete t[e],r&&r.dep.notify())}function $1(t){for(var e=void 0,r=0,n=t.length;r<n;r++)e=t[r],e&&e.__ob__&&e.__ob__.dep.depend(),Ne(e)&&$1(e)}function C1(t){return BI(t,!0),ga(t,\"__v_isShallow\",!0),t}function BI(t,e){ob(t)||Gi(t,e,Hu())}function ob(t){return!!(t&&t.__v_isReadonly)}function hi(t){return!!(t&&t.__v_isRef===!0)}function gm(t,e,r){Object.defineProperty(t,r,{enumerable:!0,configurable:!0,get:function(){var n=e[r];if(hi(n))return n.value;var i=n&&n.__ob__;return i&&i.dep.depend(),n},set:function(n){var i=e[r];hi(i)&&!hi(n)?i.value=n:e[r]=n}})}var Ur,kI=function(){function t(e){e===void 0&&(e=!1),this.detached=e,this.active=!0,this.effects=[],this.cleanups=[],this.parent=Ur,!e&&Ur&&(this.index=(Ur.scopes||(Ur.scopes=[])).push(this)-1)}return t.prototype.run=function(e){if(this.active){var r=Ur;try{return Ur=this,e()}finally{Ur=r}}},t.prototype.on=function(){Ur=this},t.prototype.off=function(){Ur=this.parent},t.prototype.stop=function(e){if(this.active){var r=void 0,n=void 0;for(r=0,n=this.effects.length;r<n;r++)this.effects[r].teardown();for(r=0,n=this.cleanups.length;r<n;r++)this.cleanups[r]();if(this.scopes)for(r=0,n=this.scopes.length;r<n;r++)this.scopes[r].stop(!0);if(!this.detached&&this.parent&&!e){var i=this.parent.scopes.pop();i&&i!==this&&(this.parent.scopes[this.index]=i,i.index=this.index)}this.parent=void 0,this.active=!1}},t}();function LI(t,e){e===void 0&&(e=Ur),e&&e.active&&e.effects.push(t)}function FI(){return Ur}function jI(t){var e=t._provided,r=t.$parent&&t.$parent._provided;return r===e?t._provided=Object.create(r):e}var kO=No(function(t){var e=t.charAt(0)===\"&\";t=e?t.slice(1):t;var r=t.charAt(0)===\"~\";t=r?t.slice(1):t;var n=t.charAt(0)===\"!\";return t=n?t.slice(1):t,{name:t,once:r,capture:n,passive:e}});function bm(t,e){function r(){var n=r.fns;if(Ne(n))for(var i=n.slice(),a=0;a<i.length;a++)$a(i[a],null,arguments,e,\"v-on handler\");else return $a(n,null,arguments,e,\"v-on handler\")}return r.fns=t,r}function D1(t,e,r,n,i,a){var o,s,l,u;for(o in t)s=t[o],l=e[o],u=kO(o),Oe(s)||(Oe(l)?(Oe(s.fns)&&(s=t[o]=bm(s,a)),_t(u.once)&&(s=t[o]=i(u.name,s,u.capture)),r(u.name,s,u.capture,u.passive,u.params)):s!==l&&(l.fns=s,t[o]=l));for(o in e)Oe(t[o])&&(u=kO(o),n(u.name,e[o],u.capture))}function pa(t,e,r){t instanceof _n&&(t=t.data.hook||(t.data.hook={}));var n,i=t[e];function a(){r.apply(this,arguments),Ma(n.fns,a)}Oe(i)?n=bm([a]):L(i.fns)&&_t(i.merged)?(n=i,n.fns.push(a)):n=bm([i,a]),n.merged=!0,t[e]=n}function VI(t,e,r){var n=e.options.props;if(!Oe(n)){var i={},a=t.attrs,o=t.props;if(L(a)||L(o))for(var s in n){var l=Vu(s);LO(i,o,s,l,!0)||LO(i,a,s,l,!1)}return i}}function LO(t,e,r,n,i){if(L(e)){if(Cr(e,r))return t[r]=e[r],i||delete e[r],!0;if(Cr(e,n))return t[r]=e[n],i||delete e[n],!0}return!1}function HI(t){for(var e=0;e<t.length;e++)if(Ne(t[e]))return Array.prototype.concat.apply([],t);return t}function sb(t){return ju(t)?[ys(t)]:Ne(t)?A1(t):void 0}function wl(t){return L(t)&&L(t.text)&&vI(t.isComment)}function A1(t,e){var r=[],n,i,a,o;for(n=0;n<t.length;n++)i=t[n],!(Oe(i)||typeof i==\"boolean\")&&(a=r.length-1,o=r[a],Ne(i)?i.length>0&&(i=A1(i,\"\".concat(e||\"\",\"_\").concat(n)),wl(i[0])&&wl(o)&&(r[a]=ys(o.text+i[0].text),i.shift()),r.push.apply(r,i)):ju(i)?wl(o)?r[a]=ys(o.text+i):i!==\"\"&&r.push(ys(i)):wl(i)&&wl(o)?r[a]=ys(o.text+i.text):(_t(t._isVList)&&L(i.tag)&&Oe(i.key)&&L(e)&&(i.key=\"__vlist\".concat(e,\"_\").concat(n,\"__\")),r.push(i)));return r}function zI(t,e){var r=null,n,i,a,o;if(Ne(t)||typeof t==\"string\")for(r=new Array(t.length),n=0,i=t.length;n<i;n++)r[n]=e(t[n],n);else if(typeof t==\"number\")for(r=new Array(t),n=0;n<t;n++)r[n]=e(n+1,n);else if(gr(t))if(zu&&t[Symbol.iterator]){r=[];for(var s=t[Symbol.iterator](),l=s.next();!l.done;)r.push(e(l.value,r.length)),l=s.next()}else for(a=Object.keys(t),r=new Array(a.length),n=0,i=a.length;n<i;n++)o=a[n],r[n]=e(t[o],o,n);return L(r)||(r=[]),r._isVList=!0,r}function UI(t,e,r,n){var i=this.$scopedSlots[t],a;i?(r=r||{},n&&(r=ut(ut({},n),r)),a=i(r)||(gt(e)?e():e)):a=this.$slots[t]||(gt(e)?e():e);var o=r&&r.slot;return o?this.$createElement(\"template\",{slot:o},a):a}function GI(t){return Yf(this.$options,\"filters\",t)||y1}function FO(t,e){return Ne(t)?t.indexOf(e)===-1:t!==e}function WI(t,e,r,n,i){var a=Bn.keyCodes[e]||r;return i&&n&&!Bn.keyCodes[e]?FO(i,n):a?FO(a,t):n?Vu(n)!==e:t===void 0}function KI(t,e,r,n,i){if(r&&gr(r)){Ne(r)&&(r=b1(r));var a=void 0,o=function(l){if(l===\"class\"||l===\"style\"||yI(l))a=t;else{var u=t.attrs&&t.attrs.type;a=n||Bn.mustUseProp(e,u,l)?t.domProps||(t.domProps={}):t.attrs||(t.attrs={})}var f=Oo(l),d=Vu(l);if(!(f in a)&&!(d in a)&&(a[l]=r[l],i)){var p=t.on||(t.on={});p[\"update:\".concat(l)]=function(h){r[l]=h}}};for(var s in r)o(s)}return t}function YI(t,e){var r=this._staticTrees||(this._staticTrees=[]),n=r[t];return n&&!e||(n=r[t]=this.$options.staticRenderFns[t].call(this._renderProxy,this._c,this),R1(n,\"__static__\".concat(t),!1)),n}function qI(t,e,r){return R1(t,\"__once__\".concat(e).concat(r?\"_\".concat(r):\"\"),!0),t}function R1(t,e,r){if(Ne(t))for(var n=0;n<t.length;n++)t[n]&&typeof t[n]!=\"string\"&&jO(t[n],\"\".concat(e,\"_\").concat(n),r);else jO(t,e,r)}function jO(t,e,r){t.isStatic=!0,t.key=e,t.isOnce=r}function XI(t,e){if(e&&On(e)){var r=t.on=t.on?ut({},t.on):{};for(var n in e){var i=r[n],a=e[n];r[n]=i?[].concat(i,a):a}}return t}function x1(t,e,r,n){e=e||{$stable:!r};for(var i=0;i<t.length;i++){var a=t[i];Ne(a)?x1(a,e,r):a&&(a.proxy&&(a.fn.proxy=!0),e[a.key]=a.fn)}return n&&(e.$key=n),e}function JI(t,e){for(var r=0;r<e.length;r+=2){var n=e[r];typeof n==\"string\"&&n&&(t[e[r]]=e[r+1])}return t}function ZI(t,e){return typeof t==\"string\"?e+t:t}function M1(t){t._o=qI,t._n=_u,t._s=gI,t._l=zI,t._t=UI,t._q=_o,t._i=O1,t._m=YI,t._f=GI,t._k=WI,t._b=KI,t._v=ys,t._e=co,t._u=x1,t._g=XI,t._d=JI,t._p=ZI}function lb(t,e){if(!t||!t.length)return{};for(var r={},n=0,i=t.length;n<i;n++){var a=t[n],o=a.data;if(o&&o.attrs&&o.attrs.slot&&delete o.attrs.slot,(a.context===e||a.fnContext===e)&&o&&o.slot!=null){var s=o.slot,l=r[s]||(r[s]=[]);a.tag===\"template\"?l.push.apply(l,a.children||[]):l.push(a)}else(r.default||(r.default=[])).push(a)}for(var u in r)r[u].every(QI)&&delete r[u];return r}function QI(t){return t.isComment&&!t.asyncFactory||t.text===\" \"}function Tu(t){return t.isComment&&t.asyncFactory}function uu(t,e,r,n){var i,a=Object.keys(r).length>0,o=e?!!e.$stable:!a,s=e&&e.$key;if(!e)i={};else{if(e._normalized)return e._normalized;if(o&&n&&n!==pn&&s===n.$key&&!a&&!n.$hasNormal)return n;i={};for(var l in e)e[l]&&l[0]!==\"$\"&&(i[l]=eB(t,r,l,e[l]))}for(var u in r)u in i||(i[u]=tB(r,u));return e&&Object.isExtensible(e)&&(e._normalized=i),ga(i,\"$stable\",o),ga(i,\"$key\",s),ga(i,\"$hasNormal\",a),i}function eB(t,e,r,n){var i=function(){var a=Ds;Sa(t);var o=arguments.length?n.apply(null,arguments):n({});o=o&&typeof o==\"object\"&&!Ne(o)?[o]:sb(o);var s=o&&o[0];return Sa(a),o&&(!s||o.length===1&&s.isComment&&!Tu(s))?void 0:o};return n.proxy&&Object.defineProperty(e,r,{get:i,enumerable:!0,configurable:!0}),i}function tB(t,e){return function(){return t[e]}}function rB(t){var e=t.$options,r=e.setup;if(r){var n=t._setupContext=nB(t);Sa(t),Zs();var i=$a(r,null,[t._props||C1({}),n],t,\"setup\");if(Qs(),Sa(),gt(i))e.render=i;else if(gr(i))if(t._setupState=i,i.__sfc){var o=t._setupProxy={};for(var a in i)a!==\"__sfc\"&&gm(o,i,a)}else for(var a in i)w1(a)||gm(t,i,a)}}function nB(t){return{get attrs(){if(!t._attrsProxy){var e=t._attrsProxy={};ga(e,\"_v_attr_proxy\",!0),zf(e,t.$attrs,pn,t,\"$attrs\")}return t._attrsProxy},get listeners(){if(!t._listenersProxy){var e=t._listenersProxy={};zf(e,t.$listeners,pn,t,\"$listeners\")}return t._listenersProxy},get slots(){return aB(t)},emit:g1(t.$emit,t),expose:function(e){e&&Object.keys(e).forEach(function(r){return gm(t,e,r)})}}}function zf(t,e,r,n,i){var a=!1;for(var o in e)o in t?e[o]!==r[o]&&(a=!0):(a=!0,iB(t,o,n,i));for(var o in t)o in e||(a=!0,delete t[o]);return a}function iB(t,e,r,n){Object.defineProperty(t,e,{enumerable:!0,configurable:!0,get:function(){return r[n][e]}})}function aB(t){return t._slotsProxy||N1(t._slotsProxy={},t.$scopedSlots),t._slotsProxy}function N1(t,e){for(var r in e)t[r]=e[r];for(var r in t)r in e||delete t[r]}function oB(t){t._vnode=null,t._staticTrees=null;var e=t.$options,r=t.$vnode=e._parentVnode,n=r&&r.context;t.$slots=lb(e._renderChildren,n),t.$scopedSlots=r?uu(t.$parent,r.data.scopedSlots,t.$slots):pn,t._c=function(a,o,s,l){return Uf(t,a,o,s,l,!1)},t.$createElement=function(a,o,s,l){return Uf(t,a,o,s,l,!0)};var i=r&&r.data;wo(t,\"$attrs\",i&&i.attrs||pn,null,!0),wo(t,\"$listeners\",e._parentListeners||pn,null,!0)}var nf=null;function sB(t){M1(t.prototype),t.prototype.$nextTick=function(e){return ub(e,this)},t.prototype._render=function(){var e=this,r=e.$options,n=r.render,i=r._parentVnode;i&&e._isMounted&&(e.$scopedSlots=uu(e.$parent,i.data.scopedSlots,e.$slots,e.$scopedSlots),e._slotsProxy&&N1(e._slotsProxy,e.$scopedSlots)),e.$vnode=i;var a=Ds,o=nf,s;try{Sa(e),nf=e,s=n.call(e._renderProxy,e.$createElement)}catch(l){To(l,e,\"render\"),s=e._vnode}finally{nf=o,Sa(a)}return Ne(s)&&s.length===1&&(s=s[0]),s instanceof _n||(s=co()),s.parent=i,s}}function Bh(t,e){return(t.__esModule||zu&&t[Symbol.toStringTag]===\"Module\")&&(t=t.default),gr(t)?e.extend(t):t}function lB(t,e,r,n,i){var a=co();return a.asyncFactory=t,a.asyncMeta={data:e,context:r,children:n,tag:i},a}function uB(t,e){if(_t(t.error)&&L(t.errorComp))return t.errorComp;if(L(t.resolved))return t.resolved;var r=nf;if(r&&L(t.owners)&&t.owners.indexOf(r)===-1&&t.owners.push(r),_t(t.loading)&&L(t.loadingComp))return t.loadingComp;if(r&&!L(t.owners)){var n=t.owners=[r],i=!0,a=null,o=null;r.$on(\"hook:destroyed\",function(){return Ma(n,r)});var s=function(d){for(var p=0,h=n.length;p<h;p++)n[p].$forceUpdate();d&&(n.length=0,a!==null&&(clearTimeout(a),a=null),o!==null&&(clearTimeout(o),o=null))},l=jf(function(d){t.resolved=Bh(d,e),i?n.length=0:s(!0)}),u=jf(function(d){L(t.errorComp)&&(t.error=!0,s(!0))}),f=t(l,u);return gr(f)&&(pm(f)?Oe(t.resolved)&&f.then(l,u):pm(f.component)&&(f.component.then(l,u),L(f.error)&&(t.errorComp=Bh(f.error,e)),L(f.loading)&&(t.loadingComp=Bh(f.loading,e),f.delay===0?t.loading=!0:a=setTimeout(function(){a=null,Oe(t.resolved)&&Oe(t.error)&&(t.loading=!0,s(!1))},f.delay||200)),L(f.timeout)&&(o=setTimeout(function(){o=null,Oe(t.resolved)&&u(null)},f.timeout)))),i=!1,t.loading?t.loadingComp:t.resolved}}function I1(t){if(Ne(t))for(var e=0;e<t.length;e++){var r=t[e];if(L(r)&&(L(r.componentOptions)||Tu(r)))return r}}var cB=1,B1=2;function Uf(t,e,r,n,i,a){return(Ne(r)||ju(r))&&(i=n,n=r,r=void 0),_t(a)&&(i=B1),fB(t,e,r,n,i)}function fB(t,e,r,n,i){if(L(r)&&L(r.__ob__)||(L(r)&&L(r.is)&&(e=r.is),!e))return co();Ne(n)&&gt(n[0])&&(r=r||{},r.scopedSlots={default:n[0]},n.length=0),i===B1?n=sb(n):i===cB&&(n=HI(n));var a,o;if(typeof e==\"string\"){var s=void 0;o=t.$vnode&&t.$vnode.ns||Bn.getTagNamespace(e),Bn.isReservedTag(e)?a=new _n(Bn.parsePlatformTagName(e),r,n,void 0,void 0,t):(!r||!r.pre)&&L(s=Yf(t.$options,\"components\",e))?a=YO(s,r,t,n,e):a=new _n(e,r,n,void 0,void 0,t)}else a=YO(e,r,t,n);return Ne(a)?a:L(a)?(L(o)&&k1(a,o),L(r)&&dB(r),a):co()}function k1(t,e,r){if(t.ns=e,t.tag===\"foreignObject\"&&(e=void 0,r=!0),L(t.children))for(var n=0,i=t.children.length;n<i;n++){var a=t.children[n];L(a.tag)&&(Oe(a.ns)||_t(r)&&a.tag!==\"svg\")&&k1(a,e,r)}}function dB(t){gr(t.style)&&Gf(t.style),gr(t.class)&&Gf(t.class)}function To(t,e,r){Zs();try{if(e)for(var n=e;n=n.$parent;){var i=n.$options.errorCaptured;if(i)for(var a=0;a<i.length;a++)try{var o=i[a].call(n,t,e,r)===!1;if(o)return}catch(s){VO(s,n,\"errorCaptured hook\")}}VO(t,e,r)}finally{Qs()}}function $a(t,e,r,n,i){var a;try{a=r?t.apply(e,r):t.call(e),a&&!a._isVue&&pm(a)&&!a._handled&&(a.catch(function(o){return To(o,n,i+\" (Promise/async)\")}),a._handled=!0)}catch(o){To(o,n,i)}return a}function VO(t,e,r){if(Bn.errorHandler)try{return Bn.errorHandler.call(null,t,e,r)}catch(n){n!==t&&HO(n)}HO(t)}function HO(t,e,r){if(wn&&typeof console<\"u\")console.error(t);else throw t}var ym=!1,Om=[],_m=!1;function wc(){_m=!1;var t=Om.slice(0);Om.length=0;for(var e=0;e<t.length;e++)t[e]()}var Wl;if(typeof Promise<\"u\"&&Cs(Promise)){var pB=Promise.resolve();Wl=function(){pB.then(wc),RI&&setTimeout(Qt)},ym=!0}else if(!Xs&&typeof MutationObserver<\"u\"&&(Cs(MutationObserver)||MutationObserver.toString()===\"[object MutationObserverConstructor]\")){var Tc=1,hB=new MutationObserver(wc),zO=document.createTextNode(String(Tc));hB.observe(zO,{characterData:!0}),Wl=function(){Tc=(Tc+1)%2,zO.data=String(Tc)},ym=!0}else typeof setImmediate<\"u\"&&Cs(setImmediate)?Wl=function(){setImmediate(wc)}:Wl=function(){setTimeout(wc,0)};function ub(t,e){var r;if(Om.push(function(){if(t)try{t.call(e)}catch(n){To(n,e,\"nextTick\")}else r&&r(e)}),_m||(_m=!0,Wl()),!t&&typeof Promise<\"u\")return new Promise(function(n){r=n})}var vB=\"2.7.16\",UO=new wu;function Gf(t){return af(t,UO),UO.clear(),t}function af(t,e){var r,n,i=Ne(t);if(!(!i&&!gr(t)||t.__v_skip||Object.isFrozen(t)||t instanceof _n)){if(t.__ob__){var a=t.__ob__.dep.id;if(e.has(a))return;e.add(a)}if(i)for(r=t.length;r--;)af(t[r],e);else if(hi(t))af(t.value,e);else for(n=Object.keys(t),r=n.length;r--;)af(t[n[r]],e)}}var mB=0,cb=function(){function t(e,r,n,i,a){LI(this,Ur&&!Ur._vm?Ur:e?e._scope:void 0),(this.vm=e)&&a&&(e._watcher=this),i?(this.deep=!!i.deep,this.user=!!i.user,this.lazy=!!i.lazy,this.sync=!!i.sync,this.before=i.before):this.deep=this.user=this.lazy=this.sync=!1,this.cb=n,this.id=++mB,this.active=!0,this.post=!1,this.dirty=this.lazy,this.deps=[],this.newDeps=[],this.depIds=new wu,this.newDepIds=new wu,this.expression=\"\",gt(r)?this.getter=r:(this.getter=DI(r),this.getter||(this.getter=Qt)),this.value=this.lazy?void 0:this.get()}return t.prototype.get=function(){Zs(this);var e,r=this.vm;try{e=this.getter.call(r,r)}catch(n){if(this.user)To(n,r,'getter for watcher \"'.concat(this.expression,'\"'));else throw n}finally{this.deep&&Gf(e),Qs(),this.cleanupDeps()}return e},t.prototype.addDep=function(e){var r=e.id;this.newDepIds.has(r)||(this.newDepIds.add(r),this.newDeps.push(e),this.depIds.has(r)||e.addSub(this))},t.prototype.cleanupDeps=function(){for(var e=this.deps.length;e--;){var r=this.deps[e];this.newDepIds.has(r.id)||r.removeSub(this)}var n=this.depIds;this.depIds=this.newDepIds,this.newDepIds=n,this.newDepIds.clear(),n=this.deps,this.deps=this.newDeps,this.newDeps=n,this.newDeps.length=0},t.prototype.update=function(){this.lazy?this.dirty=!0:this.sync?this.run():xB(this)},t.prototype.run=function(){if(this.active){var e=this.get();if(e!==this.value||gr(e)||this.deep){var r=this.value;if(this.value=e,this.user){var n='callback for watcher \"'.concat(this.expression,'\"');$a(this.cb,this.vm,[e,r],this.vm,n)}else this.cb.call(this.vm,e,r)}}},t.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},t.prototype.depend=function(){for(var e=this.deps.length;e--;)this.deps[e].depend()},t.prototype.teardown=function(){if(this.vm&&!this.vm._isBeingDestroyed&&Ma(this.vm._scope.effects,this),this.active){for(var e=this.deps.length;e--;)this.deps[e].removeSub(this);this.active=!1,this.onStop&&this.onStop()}},t}();function gB(t){t._events=Object.create(null),t._hasHookEvent=!1;var e=t.$options._parentListeners;e&&L1(t,e)}var Su;function bB(t,e){Su.$on(t,e)}function yB(t,e){Su.$off(t,e)}function OB(t,e){var r=Su;return function n(){var i=e.apply(null,arguments);i!==null&&r.$off(t,n)}}function L1(t,e,r){Su=t,D1(e,r||{},bB,yB,OB,t),Su=void 0}function _B(t){var e=/^hook:/;t.prototype.$on=function(r,n){var i=this;if(Ne(r))for(var a=0,o=r.length;a<o;a++)i.$on(r[a],n);else(i._events[r]||(i._events[r]=[])).push(n),e.test(r)&&(i._hasHookEvent=!0);return i},t.prototype.$once=function(r,n){var i=this;function a(){i.$off(r,a),n.apply(i,arguments)}return a.fn=n,i.$on(r,a),i},t.prototype.$off=function(r,n){var i=this;if(!arguments.length)return i._events=Object.create(null),i;if(Ne(r)){for(var a=0,o=r.length;a<o;a++)i.$off(r[a],n);return i}var s=i._events[r];if(!s)return i;if(!n)return i._events[r]=null,i;for(var l,u=s.length;u--;)if(l=s[u],l===n||l.fn===n){s.splice(u,1);break}return i},t.prototype.$emit=function(r){var n=this,i=n._events[r];if(i){i=i.length>1?hm(i):i;for(var a=hm(arguments,1),o='event handler for \"'.concat(r,'\"'),s=0,l=i.length;s<l;s++)$a(i[s],n,a,n,o)}return n}}var fo=null;function F1(t){var e=fo;return fo=t,function(){fo=e}}function wB(t){var e=t.$options,r=e.parent;if(r&&!e.abstract){for(;r.$options.abstract&&r.$parent;)r=r.$parent;r.$children.push(t)}t.$parent=r,t.$root=r?r.$root:t,t.$children=[],t.$refs={},t._provided=r?r._provided:Object.create(null),t._watcher=null,t._inactive=null,t._directInactive=!1,t._isMounted=!1,t._isDestroyed=!1,t._isBeingDestroyed=!1}function TB(t){t.prototype._update=function(e,r){var n=this,i=n.$el,a=n._vnode,o=F1(n);n._vnode=e,a?n.$el=n.__patch__(a,e):n.$el=n.__patch__(n.$el,e,r,!1),o(),i&&(i.__vue__=null),n.$el&&(n.$el.__vue__=n);for(var s=n;s&&s.$vnode&&s.$parent&&s.$vnode===s.$parent._vnode;)s.$parent.$el=s.$el,s=s.$parent},t.prototype.$forceUpdate=function(){var e=this;e._watcher&&e._watcher.update()},t.prototype.$destroy=function(){var e=this;if(!e._isBeingDestroyed){Wn(e,\"beforeDestroy\"),e._isBeingDestroyed=!0;var r=e.$parent;r&&!r._isBeingDestroyed&&!e.$options.abstract&&Ma(r.$children,e),e._scope.stop(),e._data.__ob__&&e._data.__ob__.vmCount--,e._isDestroyed=!0,e.__patch__(e._vnode,null),Wn(e,\"destroyed\"),e.$off(),e.$el&&(e.$el.__vue__=null),e.$vnode&&(e.$vnode.parent=null)}}}function SB(t,e,r){t.$el=e,t.$options.render||(t.$options.render=co),Wn(t,\"beforeMount\");var n;n=function(){t._update(t._render(),r)};var i={before:function(){t._isMounted&&!t._isDestroyed&&Wn(t,\"beforeUpdate\")}};new cb(t,n,Qt,i,!0),r=!1;var a=t._preWatchers;if(a)for(var o=0;o<a.length;o++)a[o].run();return t.$vnode==null&&(t._isMounted=!0,Wn(t,\"mounted\")),t}function PB(t,e,r,n,i){var a=n.data.scopedSlots,o=t.$scopedSlots,s=!!(a&&!a.$stable||o!==pn&&!o.$stable||a&&t.$scopedSlots.$key!==a.$key||!a&&t.$scopedSlots.$key),l=!!(i||t.$options._renderChildren||s),u=t.$vnode;t.$options._parentVnode=n,t.$vnode=n,t._vnode&&(t._vnode.parent=n),t.$options._renderChildren=i;var f=n.data.attrs||pn;t._attrsProxy&&zf(t._attrsProxy,f,u.data&&u.data.attrs||pn,t,\"$attrs\")&&(l=!0),t.$attrs=f,r=r||pn;var d=t.$options._parentListeners;if(t._listenersProxy&&zf(t._listenersProxy,r,d||pn,t,\"$listeners\"),t.$listeners=t.$options._parentListeners=r,L1(t,r,d),e&&t.$options.props){Ea(!1);for(var p=t._props,h=t.$options._propKeys||[],b=0;b<h.length;b++){var y=h[b],P=t.$options.props;p[y]=mb(y,P,e,t)}Ea(!0),t.$options.propsData=e}l&&(t.$slots=lb(i,n.context),t.$forceUpdate())}function j1(t){for(;t&&(t=t.$parent);)if(t._inactive)return!0;return!1}function fb(t,e){if(e){if(t._directInactive=!1,j1(t))return}else if(t._directInactive)return;if(t._inactive||t._inactive===null){t._inactive=!1;for(var r=0;r<t.$children.length;r++)fb(t.$children[r]);Wn(t,\"activated\")}}function V1(t,e){if(!(e&&(t._directInactive=!0,j1(t)))&&!t._inactive){t._inactive=!0;for(var r=0;r<t.$children.length;r++)V1(t.$children[r]);Wn(t,\"deactivated\")}}function Wn(t,e,r,n){n===void 0&&(n=!0),Zs();var i=Ds,a=FI();n&&Sa(t);var o=t.$options[e],s=\"\".concat(e,\" hook\");if(o)for(var l=0,u=o.length;l<u;l++)$a(o[l],t,r||null,t,s);t._hasHookEvent&&t.$emit(\"hook:\"+e),n&&(Sa(i),a&&a.on()),Qs()}var Bi=[],db=[],Wf={},wm=!1,pb=!1,Os=0;function EB(){Os=Bi.length=db.length=0,Wf={},wm=pb=!1}var H1=0,Tm=Date.now;if(wn&&!Xs){var kh=window.performance;kh&&typeof kh.now==\"function\"&&Tm()>document.createEvent(\"Event\").timeStamp&&(Tm=function(){return kh.now()})}var $B=function(t,e){if(t.post){if(!e.post)return 1}else if(e.post)return-1;return t.id-e.id};function CB(){H1=Tm(),pb=!0;var t,e;for(Bi.sort($B),Os=0;Os<Bi.length;Os++)t=Bi[Os],t.before&&t.before(),e=t.id,Wf[e]=null,t.run();var r=db.slice(),n=Bi.slice();EB(),RB(r),DB(n),MI(),Vf&&Bn.devtools&&Vf.emit(\"flush\")}function DB(t){for(var e=t.length;e--;){var r=t[e],n=r.vm;n&&n._watcher===r&&n._isMounted&&!n._isDestroyed&&Wn(n,\"updated\")}}function AB(t){t._inactive=!1,db.push(t)}function RB(t){for(var e=0;e<t.length;e++)t[e]._inactive=!0,fb(t[e],!0)}function xB(t){var e=t.id;if(Wf[e]==null&&!(t===Pa.target&&t.noRecurse)){if(Wf[e]=!0,!pb)Bi.push(t);else{for(var r=Bi.length-1;r>Os&&Bi[r].id>t.id;)r--;Bi.splice(r+1,0,t)}wm||(wm=!0,ub(CB))}}function MB(t){var e=t.$options.provide;if(e){var r=gt(e)?e.call(t):e;if(!gr(r))return;for(var n=jI(t),i=zu?Reflect.ownKeys(r):Object.keys(r),a=0;a<i.length;a++){var o=i[a];Object.defineProperty(n,o,Object.getOwnPropertyDescriptor(r,o))}}}function NB(t){var e=z1(t.$options.inject,t);e&&(Ea(!1),Object.keys(e).forEach(function(r){wo(t,r,e[r])}),Ea(!0))}function z1(t,e){if(t){for(var r=Object.create(null),n=zu?Reflect.ownKeys(t):Object.keys(t),i=0;i<n.length;i++){var a=n[i];if(a!==\"__ob__\"){var o=t[a].from;if(o in e._provided)r[a]=e._provided[o];else if(\"default\"in t[a]){var s=t[a].default;r[a]=gt(s)?s.call(e):s}}}return r}}function hb(t,e,r,n,i){var a=this,o=i.options,s;Cr(n,\"_uid\")?(s=Object.create(n),s._original=n):(s=n,n=n._original);var l=_t(o._compiled),u=!l;this.data=t,this.props=e,this.children=r,this.parent=n,this.listeners=t.on||pn,this.injections=z1(o.inject,n),this.slots=function(){return a.$slots||uu(n,t.scopedSlots,a.$slots=lb(r,n)),a.$slots},Object.defineProperty(this,\"scopedSlots\",{enumerable:!0,get:function(){return uu(n,t.scopedSlots,this.slots())}}),l&&(this.$options=o,this.$slots=this.slots(),this.$scopedSlots=uu(n,t.scopedSlots,this.$slots)),o._scopeId?this._c=function(f,d,p,h){var b=Uf(s,f,d,p,h,u);return b&&!Ne(b)&&(b.fnScopeId=o._scopeId,b.fnContext=n),b}:this._c=function(f,d,p,h){return Uf(s,f,d,p,h,u)}}M1(hb.prototype);function IB(t,e,r,n,i){var a=t.options,o={},s=a.props;if(L(s))for(var l in s)o[l]=mb(l,s,e||pn);else L(r.attrs)&&WO(o,r.attrs),L(r.props)&&WO(o,r.props);var u=new hb(r,o,i,n,t),f=a.render.call(null,u._c,u);if(f instanceof _n)return GO(f,r,u.parent,a);if(Ne(f)){for(var d=sb(f)||[],p=new Array(d.length),h=0;h<d.length;h++)p[h]=GO(d[h],r,u.parent,a);return p}}function GO(t,e,r,n,i){var a=mm(t);return a.fnContext=r,a.fnOptions=n,e.slot&&((a.data||(a.data={})).slot=e.slot),a}function WO(t,e){for(var r in e)t[Oo(r)]=e[r]}function Kf(t){return t.name||t.__name||t._componentTag}var vb={init:function(t,e){if(t.componentInstance&&!t.componentInstance._isDestroyed&&t.data.keepAlive){var r=t;vb.prepatch(r,r)}else{var n=t.componentInstance=BB(t,fo);n.$mount(e?t.elm:void 0,e)}},prepatch:function(t,e){var r=e.componentOptions,n=e.componentInstance=t.componentInstance;PB(n,r.propsData,r.listeners,e,r.children)},insert:function(t){var e=t.context,r=t.componentInstance;r._isMounted||(r._isMounted=!0,Wn(r,\"mounted\")),t.data.keepAlive&&(e._isMounted?AB(r):fb(r,!0))},destroy:function(t){var e=t.componentInstance;e._isDestroyed||(t.data.keepAlive?V1(e,!0):e.$destroy())}},KO=Object.keys(vb);function YO(t,e,r,n,i){if(!Oe(t)){var a=r.$options._base;if(gr(t)&&(t=a.extend(t)),typeof t==\"function\"){var o;if(Oe(t.cid)&&(o=t,t=uB(o,a),t===void 0))return lB(o,e,r,n,i);e=e||{},bb(t),L(e.model)&&FB(t.options,e);var s=VI(e,t);if(_t(t.options.functional))return IB(t,s,e,r,n);var l=e.on;if(e.on=e.nativeOn,_t(t.options.abstract)){var u=e.slot;e={},u&&(e.slot=u)}kB(e);var f=Kf(t.options)||i,d=new _n(\"vue-component-\".concat(t.cid).concat(f?\"-\".concat(f):\"\"),e,void 0,void 0,void 0,r,{Ctor:t,propsData:s,listeners:l,tag:i,children:n},o);return d}}}function BB(t,e){var r={_isComponent:!0,_parentVnode:t,parent:e},n=t.data.inlineTemplate;return L(n)&&(r.render=n.render,r.staticRenderFns=n.staticRenderFns),new t.componentOptions.Ctor(r)}function kB(t){for(var e=t.hook||(t.hook={}),r=0;r<KO.length;r++){var n=KO[r],i=e[n],a=vb[n];i!==a&&!(i&&i._merged)&&(e[n]=i?LB(a,i):a)}}function LB(t,e){var r=function(n,i){t(n,i),e(n,i)};return r._merged=!0,r}function FB(t,e){var r=t.model&&t.model.prop||\"value\",n=t.model&&t.model.event||\"input\";(e.attrs||(e.attrs={}))[r]=e.model.value;var i=e.on||(e.on={}),a=i[n],o=e.model.callback;L(a)?(Ne(a)?a.indexOf(o)===-1:a!==o)&&(i[n]=[o].concat(a)):i[n]=o}var jB=Qt,pi=Bn.optionMergeStrategies;function Pu(t,e,r){if(r===void 0&&(r=!0),!e)return t;for(var n,i,a,o=zu?Reflect.ownKeys(e):Object.keys(e),s=0;s<o.length;s++)n=o[s],n!==\"__ob__\"&&(i=t[n],a=e[n],!r||!Cr(t,n)?ab(t,n,a):i!==a&&On(i)&&On(a)&&Pu(i,a));return t}function qO(t,e,r){return r?function(){var i=gt(e)?e.call(r,r):e,a=gt(t)?t.call(r,r):t;return i?Pu(i,a):a}:e?t?function(){return Pu(gt(e)?e.call(this,this):e,gt(t)?t.call(this,this):t)}:e:t}pi.data=function(t,e,r){return r?qO(t,e,r):e&&typeof e!=\"function\"?t:qO(t,e)};function VB(t,e){var r=e?t?t.concat(e):Ne(e)?e:[e]:t;return r&&HB(r)}function HB(t){for(var e=[],r=0;r<t.length;r++)e.indexOf(t[r])===-1&&e.push(t[r]);return e}_1.forEach(function(t){pi[t]=VB});function zB(t,e,r,n){var i=Object.create(t||null);return e?ut(i,e):i}Qd.forEach(function(t){pi[t+\"s\"]=zB});pi.watch=function(t,e,r,n){if(t===vm&&(t=void 0),e===vm&&(e=void 0),!e)return Object.create(t||null);if(!t)return e;var i={};ut(i,t);for(var a in e){var o=i[a],s=e[a];o&&!Ne(o)&&(o=[o]),i[a]=o?o.concat(s):Ne(s)?s:[s]}return i};pi.props=pi.methods=pi.inject=pi.computed=function(t,e,r,n){if(!t)return e;var i=Object.create(null);return ut(i,t),e&&ut(i,e),i};pi.provide=function(t,e){return t?function(){var r=Object.create(null);return Pu(r,gt(t)?t.call(this):t),e&&Pu(r,gt(e)?e.call(this):e,!1),r}:e};var UB=function(t,e){return e===void 0?t:e};function GB(t,e){var r=t.props;if(!!r){var n={},i,a,o;if(Ne(r))for(i=r.length;i--;)a=r[i],typeof a==\"string\"&&(o=Oo(a),n[o]={type:null});else if(On(r))for(var s in r)a=r[s],o=Oo(s),n[o]=On(a)?a:{type:a};t.props=n}}function WB(t,e){var r=t.inject;if(!!r){var n=t.inject={};if(Ne(r))for(var i=0;i<r.length;i++)n[r[i]]={from:r[i]};else if(On(r))for(var a in r){var o=r[a];n[a]=On(o)?ut({from:a},o):{from:o}}}}function KB(t){var e=t.directives;if(e)for(var r in e){var n=e[r];gt(n)&&(e[r]={bind:n,update:n})}}function So(t,e,r){if(gt(e)&&(e=e.options),GB(e),WB(e),KB(e),!e._base&&(e.extends&&(t=So(t,e.extends,r)),e.mixins))for(var n=0,i=e.mixins.length;n<i;n++)t=So(t,e.mixins[n],r);var a={},o;for(o in t)s(o);for(o in e)Cr(t,o)||s(o);function s(l){var u=pi[l]||UB;a[l]=u(t[l],e[l],r,l)}return a}function Yf(t,e,r,n){if(typeof r==\"string\"){var i=t[e];if(Cr(i,r))return i[r];var a=Oo(r);if(Cr(i,a))return i[a];var o=wI(a);if(Cr(i,o))return i[o];var s=i[r]||i[a]||i[o];return s}}function mb(t,e,r,n){var i=e[t],a=!Cr(r,t),o=r[t],s=JO(Boolean,i.type);if(s>-1){if(a&&!Cr(i,\"default\"))o=!1;else if(o===\"\"||o===Vu(t)){var l=JO(String,i.type);(l<0||s<l)&&(o=!0)}}if(o===void 0){o=YB(n,i,t);var u=ib;Ea(!0),Gi(o),Ea(u)}return o}function YB(t,e,r){if(!!Cr(e,\"default\")){var n=e.default;return t&&t.$options.propsData&&t.$options.propsData[r]===void 0&&t._props[r]!==void 0?t._props[r]:gt(n)&&Sm(e.type)!==\"Function\"?n.call(t):n}}var qB=/^\\s*function (\\w+)/;function Sm(t){var e=t&&t.toString().match(qB);return e?e[1]:\"\"}function XO(t,e){return Sm(t)===Sm(e)}function JO(t,e){if(!Ne(e))return XO(e,t)?0:-1;for(var r=0,n=e.length;r<n;r++)if(XO(e[r],t))return r;return-1}var fa={enumerable:!0,configurable:!0,get:Qt,set:Qt};function gb(t,e,r){fa.get=function(){return this[e][r]},fa.set=function(i){this[e][r]=i},Object.defineProperty(t,r,fa)}function XB(t){var e=t.$options;if(e.props&&JB(t,e.props),rB(t),e.methods&&rk(t,e.methods),e.data)ZB(t);else{var r=Gi(t._data={});r&&r.vmCount++}e.computed&&tk(t,e.computed),e.watch&&e.watch!==vm&&nk(t,e.watch)}function JB(t,e){var r=t.$options.propsData||{},n=t._props=C1({}),i=t.$options._propKeys=[],a=!t.$parent;a||Ea(!1);var o=function(l){i.push(l);var u=mb(l,e,r,t);wo(n,l,u,void 0,!0),l in t||gb(t,\"_props\",l)};for(var s in e)o(s);Ea(!0)}function ZB(t){var e=t.$options.data;e=t._data=gt(e)?QB(e,t):e||{},On(e)||(e={});var r=Object.keys(e),n=t.$options.props;t.$options.methods;for(var i=r.length;i--;){var a=r[i];n&&Cr(n,a)||w1(a)||gb(t,\"_data\",a)}var o=Gi(e);o&&o.vmCount++}function QB(t,e){Zs();try{return t.call(e,e)}catch(r){return To(r,e,\"data()\"),{}}finally{Qs()}}var ek={lazy:!0};function tk(t,e){var r=t._computedWatchers=Object.create(null),n=Hu();for(var i in e){var a=e[i],o=gt(a)?a:a.get;n||(r[i]=new cb(t,o||Qt,Qt,ek)),i in t||U1(t,i,a)}}function U1(t,e,r){var n=!Hu();gt(r)?(fa.get=n?ZO(e):QO(r),fa.set=Qt):(fa.get=r.get?n&&r.cache!==!1?ZO(e):QO(r.get):Qt,fa.set=r.set||Qt),Object.defineProperty(t,e,fa)}function ZO(t){return function(){var r=this._computedWatchers&&this._computedWatchers[t];if(r)return r.dirty&&r.evaluate(),Pa.target&&r.depend(),r.value}}function QO(t){return function(){return t.call(this,this)}}function rk(t,e){t.$options.props;for(var r in e)t[r]=typeof e[r]!=\"function\"?Qt:g1(e[r],t)}function nk(t,e){for(var r in e){var n=e[r];if(Ne(n))for(var i=0;i<n.length;i++)Pm(t,r,n[i]);else Pm(t,r,n)}}function Pm(t,e,r,n){return On(r)&&(n=r,r=r.handler),typeof r==\"string\"&&(r=t[r]),t.$watch(e,r,n)}function ik(t){var e={};e.get=function(){return this._data};var r={};r.get=function(){return this._props},Object.defineProperty(t.prototype,\"$data\",e),Object.defineProperty(t.prototype,\"$props\",r),t.prototype.$set=ab,t.prototype.$delete=E1,t.prototype.$watch=function(n,i,a){var o=this;if(On(i))return Pm(o,n,i,a);a=a||{},a.user=!0;var s=new cb(o,n,i,a);if(a.immediate){var l='callback for immediate watcher \"'.concat(s.expression,'\"');Zs(),$a(i,o,[s.value],o,l),Qs()}return function(){s.teardown()}}}var ak=0;function ok(t){t.prototype._init=function(e){var r=this;r._uid=ak++,r._isVue=!0,r.__v_skip=!0,r._scope=new kI(!0),r._scope.parent=void 0,r._scope._vm=!0,e&&e._isComponent?sk(r,e):r.$options=So(bb(r.constructor),e||{},r),r._renderProxy=r,r._self=r,wB(r),gB(r),oB(r),Wn(r,\"beforeCreate\",void 0,!1),NB(r),XB(r),MB(r),Wn(r,\"created\"),r.$options.el&&r.$mount(r.$options.el)}}function sk(t,e){var r=t.$options=Object.create(t.constructor.options),n=e._parentVnode;r.parent=e.parent,r._parentVnode=n;var i=n.componentOptions;r.propsData=i.propsData,r._parentListeners=i.listeners,r._renderChildren=i.children,r._componentTag=i.tag,e.render&&(r.render=e.render,r.staticRenderFns=e.staticRenderFns)}function bb(t){var e=t.options;if(t.super){var r=bb(t.super),n=t.superOptions;if(r!==n){t.superOptions=r;var i=lk(t);i&&ut(t.extendOptions,i),e=t.options=So(r,t.extendOptions),e.name&&(e.components[e.name]=t)}}return e}function lk(t){var e,r=t.options,n=t.sealedOptions;for(var i in r)r[i]!==n[i]&&(e||(e={}),e[i]=r[i]);return e}function ye(t){this._init(t)}ok(ye);ik(ye);_B(ye);TB(ye);sB(ye);function uk(t){t.use=function(e){var r=this._installedPlugins||(this._installedPlugins=[]);if(r.indexOf(e)>-1)return this;var n=hm(arguments,1);return n.unshift(this),gt(e.install)?e.install.apply(e,n):gt(e)&&e.apply(null,n),r.push(e),this}}function ck(t){t.mixin=function(e){return this.options=So(this.options,e),this}}function fk(t){t.cid=0;var e=1;t.extend=function(r){r=r||{};var n=this,i=n.cid,a=r._Ctor||(r._Ctor={});if(a[i])return a[i];var o=Kf(r)||Kf(n.options),s=function(u){this._init(u)};return s.prototype=Object.create(n.prototype),s.prototype.constructor=s,s.cid=e++,s.options=So(n.options,r),s.super=n,s.options.props&&dk(s),s.options.computed&&pk(s),s.extend=n.extend,s.mixin=n.mixin,s.use=n.use,Qd.forEach(function(l){s[l]=n[l]}),o&&(s.options.components[o]=s),s.superOptions=n.options,s.extendOptions=r,s.sealedOptions=ut({},s.options),a[i]=s,s}}function dk(t){var e=t.options.props;for(var r in e)gb(t.prototype,\"_props\",r)}function pk(t){var e=t.options.computed;for(var r in e)U1(t.prototype,r,e[r])}function hk(t){Qd.forEach(function(e){t[e]=function(r,n){return n?(e===\"component\"&&On(n)&&(n.name=n.name||r,n=this.options._base.extend(n)),e===\"directive\"&&gt(n)&&(n={bind:n,update:n}),this.options[e+\"s\"][r]=n,n):this.options[e+\"s\"][r]}})}function e_(t){return t&&(Kf(t.Ctor.options)||t.tag)}function Sc(t,e){return Ne(t)?t.indexOf(e)>-1:typeof t==\"string\"?t.split(\",\").indexOf(e)>-1:mI(t)?t.test(e):!1}function t_(t,e){var r=t.cache,n=t.keys,i=t._vnode,a=t.$vnode;for(var o in r){var s=r[o];if(s){var l=s.name;l&&!e(l)&&Em(r,o,n,i)}}a.componentOptions.children=void 0}function Em(t,e,r,n){var i=t[e];i&&(!n||i.tag!==n.tag)&&i.componentInstance.$destroy(),t[e]=null,Ma(r,e)}var r_=[String,RegExp,Array],vk={name:\"keep-alive\",abstract:!0,props:{include:r_,exclude:r_,max:[String,Number]},methods:{cacheVNode:function(){var t=this,e=t.cache,r=t.keys,n=t.vnodeToCache,i=t.keyToCache;if(n){var a=n.tag,o=n.componentInstance,s=n.componentOptions;e[i]={name:e_(s),tag:a,componentInstance:o},r.push(i),this.max&&r.length>parseInt(this.max)&&Em(e,r[0],r,this._vnode),this.vnodeToCache=null}}},created:function(){this.cache=Object.create(null),this.keys=[]},destroyed:function(){for(var t in this.cache)Em(this.cache,t,this.keys)},mounted:function(){var t=this;this.cacheVNode(),this.$watch(\"include\",function(e){t_(t,function(r){return Sc(e,r)})}),this.$watch(\"exclude\",function(e){t_(t,function(r){return!Sc(e,r)})})},updated:function(){this.cacheVNode()},render:function(){var t=this.$slots.default,e=I1(t),r=e&&e.componentOptions;if(r){var n=e_(r),i=this,a=i.include,o=i.exclude;if(a&&(!n||!Sc(a,n))||o&&n&&Sc(o,n))return e;var s=this,l=s.cache,u=s.keys,f=e.key==null?r.Ctor.cid+(r.tag?\"::\".concat(r.tag):\"\"):e.key;l[f]?(e.componentInstance=l[f].componentInstance,Ma(u,f),u.push(f)):(this.vnodeToCache=e,this.keyToCache=f),e.data.keepAlive=!0}return e||t&&t[0]}},mk={KeepAlive:vk};function gk(t){var e={};e.get=function(){return Bn},Object.defineProperty(t,\"config\",e),t.util={warn:jB,extend:ut,mergeOptions:So,defineReactive:wo},t.set=ab,t.delete=E1,t.nextTick=ub,t.observable=function(r){return Gi(r),r},t.options=Object.create(null),Qd.forEach(function(r){t.options[r+\"s\"]=Object.create(null)}),t.options._base=t,ut(t.options.components,mk),uk(t),ck(t),fk(t),hk(t)}gk(ye);Object.defineProperty(ye.prototype,\"$isServer\",{get:Hu});Object.defineProperty(ye.prototype,\"$ssrContext\",{get:function(){return this.$vnode&&this.$vnode.ssrContext}});Object.defineProperty(ye,\"FunctionalRenderContext\",{value:hb});ye.version=vB;var bk=Jn(\"style,class\"),yk=Jn(\"input,textarea,option,select,progress\"),Ok=function(t,e,r){return r===\"value\"&&yk(t)&&e!==\"button\"||r===\"selected\"&&t===\"option\"||r===\"checked\"&&t===\"input\"||r===\"muted\"&&t===\"video\"},G1=Jn(\"contenteditable,draggable,spellcheck\"),_k=Jn(\"events,caret,typing,plaintext-only\"),wk=function(t,e){return qf(e)||e===\"false\"?\"false\":t===\"contenteditable\"&&_k(e)?e:\"true\"},Tk=Jn(\"allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,truespeed,typemustmatch,visible\"),$m=\"http://www.w3.org/1999/xlink\",yb=function(t){return t.charAt(5)===\":\"&&t.slice(0,5)===\"xlink\"},W1=function(t){return yb(t)?t.slice(6,t.length):\"\"},qf=function(t){return t==null||t===!1};function Sk(t){for(var e=t.data,r=t,n=t;L(n.componentInstance);)n=n.componentInstance._vnode,n&&n.data&&(e=n_(n.data,e));for(;L(r=r.parent);)r&&r.data&&(e=n_(e,r.data));return Pk(e.staticClass,e.class)}function n_(t,e){return{staticClass:Ob(t.staticClass,e.staticClass),class:L(t.class)?[t.class,e.class]:e.class}}function Pk(t,e){return L(t)||L(e)?Ob(t,_b(e)):\"\"}function Ob(t,e){return t?e?t+\" \"+e:t:e||\"\"}function _b(t){return Array.isArray(t)?Ek(t):gr(t)?$k(t):typeof t==\"string\"?t:\"\"}function Ek(t){for(var e=\"\",r,n=0,i=t.length;n<i;n++)L(r=_b(t[n]))&&r!==\"\"&&(e&&(e+=\" \"),e+=r);return e}function $k(t){var e=\"\";for(var r in t)t[r]&&(e&&(e+=\" \"),e+=r);return e}var Ck={svg:\"http://www.w3.org/2000/svg\",math:\"http://www.w3.org/1998/Math/MathML\"},Dk=Jn(\"html,body,base,head,link,meta,style,title,address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,menuitem,summary,content,element,shadow,template,blockquote,iframe,tfoot\"),wb=Jn(\"svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,foreignobject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view\",!0),K1=function(t){return Dk(t)||wb(t)};function Ak(t){if(wb(t))return\"svg\";if(t===\"math\")return\"math\"}var Pc=Object.create(null);function Rk(t){if(!wn)return!0;if(K1(t))return!1;if(t=t.toLowerCase(),Pc[t]!=null)return Pc[t];var e=document.createElement(t);return t.indexOf(\"-\")>-1?Pc[t]=e.constructor===window.HTMLUnknownElement||e.constructor===window.HTMLElement:Pc[t]=/HTMLUnknownElement/.test(e.toString())}var Cm=Jn(\"text,number,password,search,email,tel,url\");function xk(t){if(typeof t==\"string\"){var e=document.querySelector(t);return e||document.createElement(\"div\")}else return t}function Mk(t,e){var r=document.createElement(t);return t!==\"select\"||e.data&&e.data.attrs&&e.data.attrs.multiple!==void 0&&r.setAttribute(\"multiple\",\"multiple\"),r}function Nk(t,e){return document.createElementNS(Ck[t],e)}function Ik(t){return document.createTextNode(t)}function Bk(t){return document.createComment(t)}function kk(t,e,r){t.insertBefore(e,r)}function Lk(t,e){t.removeChild(e)}function Fk(t,e){t.appendChild(e)}function jk(t){return t.parentNode}function Vk(t){return t.nextSibling}function Hk(t){return t.tagName}function zk(t,e){t.textContent=e}function Uk(t,e){t.setAttribute(e,\"\")}var Gk=Object.freeze({__proto__:null,createElement:Mk,createElementNS:Nk,createTextNode:Ik,createComment:Bk,insertBefore:kk,removeChild:Lk,appendChild:Fk,parentNode:jk,nextSibling:Vk,tagName:Hk,setTextContent:zk,setStyleScope:Uk}),Wk={create:function(t,e){_s(e)},update:function(t,e){t.data.ref!==e.data.ref&&(_s(t,!0),_s(e))},destroy:function(t){_s(t,!0)}};function _s(t,e){var r=t.data.ref;if(!!L(r)){var n=t.context,i=t.componentInstance||t.elm,a=e?null:i,o=e?void 0:i;if(gt(r)){$a(r,n,[a],n,\"template ref function\");return}var s=t.data.refInFor,l=typeof r==\"string\"||typeof r==\"number\",u=hi(r),f=n.$refs;if(l||u){if(s){var d=l?f[r]:r.value;e?Ne(d)&&Ma(d,i):Ne(d)?d.includes(i)||d.push(i):l?(f[r]=[i],i_(n,r,f[r])):r.value=[i]}else if(l){if(e&&f[r]!==i)return;f[r]=o,i_(n,r,a)}else if(u){if(e&&r.value!==i)return;r.value=a}}}}function i_(t,e,r){var n=t._setupState;n&&Cr(n,e)&&(hi(n[e])?n[e].value=r:n[e]=r)}var ha=new _n(\"\",{},[]),Tl=[\"create\",\"activate\",\"update\",\"remove\",\"destroy\"];function Wa(t,e){return t.key===e.key&&t.asyncFactory===e.asyncFactory&&(t.tag===e.tag&&t.isComment===e.isComment&&L(t.data)===L(e.data)&&Kk(t,e)||_t(t.isAsyncPlaceholder)&&Oe(e.asyncFactory.error))}function Kk(t,e){if(t.tag!==\"input\")return!0;var r,n=L(r=t.data)&&L(r=r.attrs)&&r.type,i=L(r=e.data)&&L(r=r.attrs)&&r.type;return n===i||Cm(n)&&Cm(i)}function Yk(t,e,r){var n,i,a={};for(n=e;n<=r;++n)i=t[n].key,L(i)&&(a[i]=n);return a}function qk(t){var e,r,n={},i=t.modules,a=t.nodeOps;for(e=0;e<Tl.length;++e)for(n[Tl[e]]=[],r=0;r<i.length;++r)L(i[r][Tl[e]])&&n[Tl[e]].push(i[r][Tl[e]]);function o(E){return new _n(a.tagName(E).toLowerCase(),{},[],void 0,E)}function s(E,v){function w(){--w.listeners===0&&l(E)}return w.listeners=v,w}function l(E){var v=a.parentNode(E);L(v)&&a.removeChild(v,E)}function u(E,v,w,$,M,F,X){if(L(E.elm)&&L(F)&&(E=F[X]=mm(E)),E.isRootInsert=!M,!f(E,v,w,$)){var Q=E.data,q=E.children,K=E.tag;L(K)?(E.elm=E.ns?a.createElementNS(E.ns,K):a.createElement(K,E),C(E),b(E,q,v),L(Q)&&P(E,v),h(w,E.elm,$)):_t(E.isComment)?(E.elm=a.createComment(E.text),h(w,E.elm,$)):(E.elm=a.createTextNode(E.text),h(w,E.elm,$))}}function f(E,v,w,$){var M=E.data;if(L(M)){var F=L(E.componentInstance)&&M.keepAlive;if(L(M=M.hook)&&L(M=M.init)&&M(E,!1),L(E.componentInstance))return d(E,v),h(w,E.elm,$),_t(F)&&p(E,v,w,$),!0}}function d(E,v){L(E.data.pendingInsert)&&(v.push.apply(v,E.data.pendingInsert),E.data.pendingInsert=null),E.elm=E.componentInstance.$el,y(E)?(P(E,v),C(E)):(_s(E),v.push(E))}function p(E,v,w,$){for(var M,F=E;F.componentInstance;)if(F=F.componentInstance._vnode,L(M=F.data)&&L(M=M.transition)){for(M=0;M<n.activate.length;++M)n.activate[M](ha,F);v.push(F);break}h(w,E.elm,$)}function h(E,v,w){L(E)&&(L(w)?a.parentNode(w)===E&&a.insertBefore(E,v,w):a.appendChild(E,v))}function b(E,v,w){if(Ne(v))for(var $=0;$<v.length;++$)u(v[$],w,E.elm,null,!0,v,$);else ju(E.text)&&a.appendChild(E.elm,a.createTextNode(String(E.text)))}function y(E){for(;E.componentInstance;)E=E.componentInstance._vnode;return L(E.tag)}function P(E,v){for(var w=0;w<n.create.length;++w)n.create[w](ha,E);e=E.data.hook,L(e)&&(L(e.create)&&e.create(ha,E),L(e.insert)&&v.push(E))}function C(E){var v;if(L(v=E.fnScopeId))a.setStyleScope(E.elm,v);else for(var w=E;w;)L(v=w.context)&&L(v=v.$options._scopeId)&&a.setStyleScope(E.elm,v),w=w.parent;L(v=fo)&&v!==E.context&&v!==E.fnContext&&L(v=v.$options._scopeId)&&a.setStyleScope(E.elm,v)}function R(E,v,w,$,M,F){for(;$<=M;++$)u(w[$],F,E,v,!1,w,$)}function D(E){var v,w,$=E.data;if(L($))for(L(v=$.hook)&&L(v=v.destroy)&&v(E),v=0;v<n.destroy.length;++v)n.destroy[v](E);if(L(v=E.children))for(w=0;w<E.children.length;++w)D(E.children[w])}function B(E,v,w){for(;v<=w;++v){var $=E[v];L($)&&(L($.tag)?(A($),D($)):l($.elm))}}function A(E,v){if(L(v)||L(E.data)){var w,$=n.remove.length+1;for(L(v)?v.listeners+=$:v=s(E.elm,$),L(w=E.componentInstance)&&L(w=w._vnode)&&L(w.data)&&A(w,v),w=0;w<n.remove.length;++w)n.remove[w](E,v);L(w=E.data.hook)&&L(w=w.remove)?w(E,v):v()}else l(E.elm)}function V(E,v,w,$,M){for(var F=0,X=0,Q=v.length-1,q=v[0],K=v[Q],U=w.length-1,le=w[0],be=w[U],me,Ie,Te,$t,Re=!M;F<=Q&&X<=U;)Oe(q)?q=v[++F]:Oe(K)?K=v[--Q]:Wa(q,le)?(G(q,le,$,w,X),q=v[++F],le=w[++X]):Wa(K,be)?(G(K,be,$,w,U),K=v[--Q],be=w[--U]):Wa(q,be)?(G(q,be,$,w,U),Re&&a.insertBefore(E,q.elm,a.nextSibling(K.elm)),q=v[++F],be=w[--U]):Wa(K,le)?(G(K,le,$,w,X),Re&&a.insertBefore(E,K.elm,q.elm),K=v[--Q],le=w[++X]):(Oe(me)&&(me=Yk(v,F,Q)),Ie=L(le.key)?me[le.key]:N(le,v,F,Q),Oe(Ie)?u(le,$,E,q.elm,!1,w,X):(Te=v[Ie],Wa(Te,le)?(G(Te,le,$,w,X),v[Ie]=void 0,Re&&a.insertBefore(E,Te.elm,q.elm)):u(le,$,E,q.elm,!1,w,X)),le=w[++X]);F>Q?($t=Oe(w[U+1])?null:w[U+1].elm,R(E,$t,w,X,U,$)):X>U&&B(v,F,Q)}function N(E,v,w,$){for(var M=w;M<$;M++){var F=v[M];if(L(F)&&Wa(E,F))return M}}function G(E,v,w,$,M,F){if(E!==v){L(v.elm)&&L($)&&(v=$[M]=mm(v));var X=v.elm=E.elm;if(_t(E.isAsyncPlaceholder)){L(v.asyncFactory.resolved)?j(E.elm,v,w):v.isAsyncPlaceholder=!0;return}if(_t(v.isStatic)&&_t(E.isStatic)&&v.key===E.key&&(_t(v.isCloned)||_t(v.isOnce))){v.componentInstance=E.componentInstance;return}var Q,q=v.data;L(q)&&L(Q=q.hook)&&L(Q=Q.prepatch)&&Q(E,v);var K=E.children,U=v.children;if(L(q)&&y(v)){for(Q=0;Q<n.update.length;++Q)n.update[Q](E,v);L(Q=q.hook)&&L(Q=Q.update)&&Q(E,v)}Oe(v.text)?L(K)&&L(U)?K!==U&&V(X,K,U,w,F):L(U)?(L(E.text)&&a.setTextContent(X,\"\"),R(X,null,U,0,U.length-1,w)):L(K)?B(K,0,K.length-1):L(E.text)&&a.setTextContent(X,\"\"):E.text!==v.text&&a.setTextContent(X,v.text),L(q)&&L(Q=q.hook)&&L(Q=Q.postpatch)&&Q(E,v)}}function H(E,v,w){if(_t(w)&&L(E.parent))E.parent.data.pendingInsert=v;else for(var $=0;$<v.length;++$)v[$].data.hook.insert(v[$])}var W=Jn(\"attrs,class,staticClass,staticStyle,key\");function j(E,v,w,$){var M,F=v.tag,X=v.data,Q=v.children;if($=$||X&&X.pre,v.elm=E,_t(v.isComment)&&L(v.asyncFactory))return v.isAsyncPlaceholder=!0,!0;if(L(X)&&(L(M=X.hook)&&L(M=M.init)&&M(v,!0),L(M=v.componentInstance)))return d(v,w),!0;if(L(F)){if(L(Q))if(!E.hasChildNodes())b(v,Q,w);else if(L(M=X)&&L(M=M.domProps)&&L(M=M.innerHTML)){if(M!==E.innerHTML)return!1}else{for(var q=!0,K=E.firstChild,U=0;U<Q.length;U++){if(!K||!j(K,Q[U],w,$)){q=!1;break}K=K.nextSibling}if(!q||K)return!1}if(L(X)){var le=!1;for(var be in X)if(!W(be)){le=!0,P(v,w);break}!le&&X.class&&Gf(X.class)}}else E.data!==v.text&&(E.data=v.text);return!0}return function(v,w,$,M){if(Oe(w)){L(v)&&D(v);return}var F=!1,X=[];if(Oe(v))F=!0,u(w,X);else{var Q=L(v.nodeType);if(!Q&&Wa(v,w))G(v,w,X,null,null,M);else{if(Q){if(v.nodeType===1&&v.hasAttribute(xO)&&(v.removeAttribute(xO),$=!0),_t($)&&j(v,w,X))return H(w,X,!0),v;v=o(v)}var q=v.elm,K=a.parentNode(q);if(u(w,X,q._leaveCb?null:K,a.nextSibling(q)),L(w.parent))for(var U=w.parent,le=y(w);U;){for(var be=0;be<n.destroy.length;++be)n.destroy[be](U);if(U.elm=w.elm,le){for(var me=0;me<n.create.length;++me)n.create[me](ha,U);var Ie=U.data.hook.insert;if(Ie.merged)for(var Te=Ie.fns.slice(1),$t=0;$t<Te.length;$t++)Te[$t]()}else _s(U);U=U.parent}L(K)?B([v],0,0):L(v.tag)&&D(v)}}return H(w,X,F),w.elm}}var Xk={create:Lh,update:Lh,destroy:function(e){Lh(e,ha)}};function Lh(t,e){(t.data.directives||e.data.directives)&&Jk(t,e)}function Jk(t,e){var r=t===ha,n=e===ha,i=a_(t.data.directives,t.context),a=a_(e.data.directives,e.context),o=[],s=[],l,u,f;for(l in a)u=i[l],f=a[l],u?(f.oldValue=u.value,f.oldArg=u.arg,Sl(f,\"update\",e,t),f.def&&f.def.componentUpdated&&s.push(f)):(Sl(f,\"bind\",e,t),f.def&&f.def.inserted&&o.push(f));if(o.length){var d=function(){for(var p=0;p<o.length;p++)Sl(o[p],\"inserted\",e,t)};r?pa(e,\"insert\",d):d()}if(s.length&&pa(e,\"postpatch\",function(){for(var p=0;p<s.length;p++)Sl(s[p],\"componentUpdated\",e,t)}),!r)for(l in i)a[l]||Sl(i[l],\"unbind\",t,t,n)}var Zk=Object.create(null);function a_(t,e){var r=Object.create(null);if(!t)return r;var n,i;for(n=0;n<t.length;n++){if(i=t[n],i.modifiers||(i.modifiers=Zk),r[Qk(i)]=i,e._setupState&&e._setupState.__sfc){var a=i.def||Yf(e,\"_setupState\",\"v-\"+i.name);typeof a==\"function\"?i.def={bind:a,update:a}:i.def=a}i.def=i.def||Yf(e.$options,\"directives\",i.name)}return r}function Qk(t){return t.rawName||\"\".concat(t.name,\".\").concat(Object.keys(t.modifiers||{}).join(\".\"))}function Sl(t,e,r,n,i){var a=t.def&&t.def[e];if(a)try{a(r.elm,t,r,n,i)}catch(o){To(o,r.context,\"directive \".concat(t.name,\" \").concat(e,\" hook\"))}}var eL=[Wk,Xk];function o_(t,e){var r=e.componentOptions;if(!(L(r)&&r.Ctor.options.inheritAttrs===!1)&&!(Oe(t.data.attrs)&&Oe(e.data.attrs))){var n,i,a,o=e.elm,s=t.data.attrs||{},l=e.data.attrs||{};(L(l.__ob__)||_t(l._v_attr_proxy))&&(l=e.data.attrs=ut({},l));for(n in l)i=l[n],a=s[n],a!==i&&s_(o,n,i,e.data.pre);(Xs||nb)&&l.value!==s.value&&s_(o,\"value\",l.value);for(n in s)Oe(l[n])&&(yb(n)?o.removeAttributeNS($m,W1(n)):G1(n)||o.removeAttribute(n))}}function s_(t,e,r,n){n||t.tagName.indexOf(\"-\")>-1?l_(t,e,r):Tk(e)?qf(r)?t.removeAttribute(e):(r=e===\"allowfullscreen\"&&t.tagName===\"EMBED\"?\"true\":e,t.setAttribute(e,r)):G1(e)?t.setAttribute(e,wk(e,r)):yb(e)?qf(r)?t.removeAttributeNS($m,W1(e)):t.setAttributeNS($m,e,r):l_(t,e,r)}function l_(t,e,r){if(qf(r))t.removeAttribute(e);else{if(Xs&&!Js&&t.tagName===\"TEXTAREA\"&&e===\"placeholder\"&&r!==\"\"&&!t.__ieph){var n=function(i){i.stopImmediatePropagation(),t.removeEventListener(\"input\",n)};t.addEventListener(\"input\",n),t.__ieph=!0}t.setAttribute(e,r)}}var tL={create:o_,update:o_};function u_(t,e){var r=e.elm,n=e.data,i=t.data;if(!(Oe(n.staticClass)&&Oe(n.class)&&(Oe(i)||Oe(i.staticClass)&&Oe(i.class)))){var a=Sk(e),o=r._transitionClasses;L(o)&&(a=Ob(a,_b(o))),a!==r._prevClass&&(r.setAttribute(\"class\",a),r._prevClass=a)}}var rL={create:u_,update:u_},Fh=\"__r\",jh=\"__c\";function nL(t){if(L(t[Fh])){var e=Xs?\"change\":\"input\";t[e]=[].concat(t[Fh],t[e]||[]),delete t[Fh]}L(t[jh])&&(t.change=[].concat(t[jh],t.change||[]),delete t[jh])}var Eu;function iL(t,e,r){var n=Eu;return function i(){var a=e.apply(null,arguments);a!==null&&Y1(t,i,r,n)}}var aL=ym&&!(MO&&Number(MO[1])<=53);function oL(t,e,r,n){if(aL){var i=H1,a=e;e=a._wrapper=function(o){if(o.target===o.currentTarget||o.timeStamp>=i||o.timeStamp<=0||o.target.ownerDocument!==document)return a.apply(this,arguments)}}Eu.addEventListener(t,e,T1?{capture:r,passive:n}:r)}function Y1(t,e,r,n){(n||Eu).removeEventListener(t,e._wrapper||e,r)}function Vh(t,e){if(!(Oe(t.data.on)&&Oe(e.data.on))){var r=e.data.on||{},n=t.data.on||{};Eu=e.elm||t.elm,nL(r),D1(r,n,oL,Y1,iL,e.context),Eu=void 0}}var sL={create:Vh,update:Vh,destroy:function(t){return Vh(t,ha)}},Ec;function c_(t,e){if(!(Oe(t.data.domProps)&&Oe(e.data.domProps))){var r,n,i=e.elm,a=t.data.domProps||{},o=e.data.domProps||{};(L(o.__ob__)||_t(o._v_attr_proxy))&&(o=e.data.domProps=ut({},o));for(r in a)r in o||(i[r]=\"\");for(r in o){if(n=o[r],r===\"textContent\"||r===\"innerHTML\"){if(e.children&&(e.children.length=0),n===a[r])continue;i.childNodes.length===1&&i.removeChild(i.childNodes[0])}if(r===\"value\"&&i.tagName!==\"PROGRESS\"){i._value=n;var s=Oe(n)?\"\":String(n);lL(i,s)&&(i.value=s)}else if(r===\"innerHTML\"&&wb(i.tagName)&&Oe(i.innerHTML)){Ec=Ec||document.createElement(\"div\"),Ec.innerHTML=\"<svg>\".concat(n,\"</svg>\");for(var l=Ec.firstChild;i.firstChild;)i.removeChild(i.firstChild);for(;l.firstChild;)i.appendChild(l.firstChild)}else if(n!==a[r])try{i[r]=n}catch{}}}}function lL(t,e){return!t.composing&&(t.tagName===\"OPTION\"||uL(t,e)||cL(t,e))}function uL(t,e){var r=!0;try{r=document.activeElement!==t}catch{}return r&&t.value!==e}function cL(t,e){var r=t.value,n=t._vModifiers;if(L(n)){if(n.number)return _u(r)!==_u(e);if(n.trim)return r.trim()!==e.trim()}return r!==e}var fL={create:c_,update:c_},dL=No(function(t){var e={},r=/;(?![^(]*\\))/g,n=/:(.+)/;return t.split(r).forEach(function(i){if(i){var a=i.split(n);a.length>1&&(e[a[0].trim()]=a[1].trim())}}),e});function Hh(t){var e=q1(t.style);return t.staticStyle?ut(t.staticStyle,e):e}function q1(t){return Array.isArray(t)?b1(t):typeof t==\"string\"?dL(t):t}function pL(t,e){var r={},n;if(e)for(var i=t;i.componentInstance;)i=i.componentInstance._vnode,i&&i.data&&(n=Hh(i.data))&&ut(r,n);(n=Hh(t.data))&&ut(r,n);for(var a=t;a=a.parent;)a.data&&(n=Hh(a.data))&&ut(r,n);return r}var hL=/^--/,f_=/\\s*!important$/,d_=function(t,e,r){if(hL.test(e))t.style.setProperty(e,r);else if(f_.test(r))t.style.setProperty(Vu(e),r.replace(f_,\"\"),\"important\");else{var n=vL(e);if(Array.isArray(r))for(var i=0,a=r.length;i<a;i++)t.style[n]=r[i];else t.style[n]=r}},p_=[\"Webkit\",\"Moz\",\"ms\"],$c,vL=No(function(t){if($c=$c||document.createElement(\"div\").style,t=Oo(t),t!==\"filter\"&&t in $c)return t;for(var e=t.charAt(0).toUpperCase()+t.slice(1),r=0;r<p_.length;r++){var n=p_[r]+e;if(n in $c)return n}});function h_(t,e){var r=e.data,n=t.data;if(!(Oe(r.staticStyle)&&Oe(r.style)&&Oe(n.staticStyle)&&Oe(n.style))){var i,a,o=e.elm,s=n.staticStyle,l=n.normalizedStyle||n.style||{},u=s||l,f=q1(e.data.style)||{};e.data.normalizedStyle=L(f.__ob__)?ut({},f):f;var d=pL(e,!0);for(a in u)Oe(d[a])&&d_(o,a,\"\");for(a in d)i=d[a],d_(o,a,i==null?\"\":i)}}var mL={create:h_,update:h_},X1=/\\s+/;function J1(t,e){if(!(!e||!(e=e.trim())))if(t.classList)e.indexOf(\" \")>-1?e.split(X1).forEach(function(n){return t.classList.add(n)}):t.classList.add(e);else{var r=\" \".concat(t.getAttribute(\"class\")||\"\",\" \");r.indexOf(\" \"+e+\" \")<0&&t.setAttribute(\"class\",(r+e).trim())}}function Z1(t,e){if(!(!e||!(e=e.trim())))if(t.classList)e.indexOf(\" \")>-1?e.split(X1).forEach(function(i){return t.classList.remove(i)}):t.classList.remove(e),t.classList.length||t.removeAttribute(\"class\");else{for(var r=\" \".concat(t.getAttribute(\"class\")||\"\",\" \"),n=\" \"+e+\" \";r.indexOf(n)>=0;)r=r.replace(n,\" \");r=r.trim(),r?t.setAttribute(\"class\",r):t.removeAttribute(\"class\")}}function Q1(t){if(!!t){if(typeof t==\"object\"){var e={};return t.css!==!1&&ut(e,v_(t.name||\"v\")),ut(e,t),e}else if(typeof t==\"string\")return v_(t)}}var v_=No(function(t){return{enterClass:\"\".concat(t,\"-enter\"),enterToClass:\"\".concat(t,\"-enter-to\"),enterActiveClass:\"\".concat(t,\"-enter-active\"),leaveClass:\"\".concat(t,\"-leave\"),leaveToClass:\"\".concat(t,\"-leave-to\"),leaveActiveClass:\"\".concat(t,\"-leave-active\")}}),e$=wn&&!Js,hs=\"transition\",zh=\"animation\",of=\"transition\",Xf=\"transitionend\",Dm=\"animation\",t$=\"animationend\";e$&&(window.ontransitionend===void 0&&window.onwebkittransitionend!==void 0&&(of=\"WebkitTransition\",Xf=\"webkitTransitionEnd\"),window.onanimationend===void 0&&window.onwebkitanimationend!==void 0&&(Dm=\"WebkitAnimation\",t$=\"webkitAnimationEnd\"));var m_=wn?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(t){return t()};function r$(t){m_(function(){m_(t)})}function po(t,e){var r=t._transitionClasses||(t._transitionClasses=[]);r.indexOf(e)<0&&(r.push(e),J1(t,e))}function ki(t,e){t._transitionClasses&&Ma(t._transitionClasses,e),Z1(t,e)}function n$(t,e,r){var n=i$(t,e),i=n.type,a=n.timeout,o=n.propCount;if(!i)return r();var s=i===hs?Xf:t$,l=0,u=function(){t.removeEventListener(s,f),r()},f=function(d){d.target===t&&++l>=o&&u()};setTimeout(function(){l<o&&u()},a+1),t.addEventListener(s,f)}var gL=/\\b(transform|all)(,|$)/;function i$(t,e){var r=window.getComputedStyle(t),n=(r[of+\"Delay\"]||\"\").split(\", \"),i=(r[of+\"Duration\"]||\"\").split(\", \"),a=g_(n,i),o=(r[Dm+\"Delay\"]||\"\").split(\", \"),s=(r[Dm+\"Duration\"]||\"\").split(\", \"),l=g_(o,s),u,f=0,d=0;e===hs?a>0&&(u=hs,f=a,d=i.length):e===zh?l>0&&(u=zh,f=l,d=s.length):(f=Math.max(a,l),u=f>0?a>l?hs:zh:null,d=u?u===hs?i.length:s.length:0);var p=u===hs&&gL.test(r[of+\"Property\"]);return{type:u,timeout:f,propCount:d,hasTransform:p}}function g_(t,e){for(;t.length<e.length;)t=t.concat(t);return Math.max.apply(null,e.map(function(r,n){return b_(r)+b_(t[n])}))}function b_(t){return Number(t.slice(0,-1).replace(\",\",\".\"))*1e3}function Am(t,e){var r=t.elm;L(r._leaveCb)&&(r._leaveCb.cancelled=!0,r._leaveCb());var n=Q1(t.data.transition);if(!Oe(n)&&!(L(r._enterCb)||r.nodeType!==1)){for(var i=n.css,a=n.type,o=n.enterClass,s=n.enterToClass,l=n.enterActiveClass,u=n.appearClass,f=n.appearToClass,d=n.appearActiveClass,p=n.beforeEnter,h=n.enter,b=n.afterEnter,y=n.enterCancelled,P=n.beforeAppear,C=n.appear,R=n.afterAppear,D=n.appearCancelled,B=n.duration,A=fo,V=fo.$vnode;V&&V.parent;)A=V.context,V=V.parent;var N=!A._isMounted||!t.isRootInsert;if(!(N&&!C&&C!==\"\")){var G=N&&u?u:o,H=N&&d?d:l,W=N&&f?f:s,j=N&&P||p,E=N&&gt(C)?C:h,v=N&&R||b,w=N&&D||y,$=_u(gr(B)?B.enter:B),M=i!==!1&&!Js,F=Tb(E),X=r._enterCb=jf(function(){M&&(ki(r,W),ki(r,H)),X.cancelled?(M&&ki(r,G),w&&w(r)):v&&v(r),r._enterCb=null});t.data.show||pa(t,\"insert\",function(){var Q=r.parentNode,q=Q&&Q._pending&&Q._pending[t.key];q&&q.tag===t.tag&&q.elm._leaveCb&&q.elm._leaveCb(),E&&E(r,X)}),j&&j(r),M&&(po(r,G),po(r,H),r$(function(){ki(r,G),X.cancelled||(po(r,W),F||(o$($)?setTimeout(X,$):n$(r,a,X)))})),t.data.show&&(e&&e(),E&&E(r,X)),!M&&!F&&X()}}}function a$(t,e){var r=t.elm;L(r._enterCb)&&(r._enterCb.cancelled=!0,r._enterCb());var n=Q1(t.data.transition);if(Oe(n)||r.nodeType!==1)return e();if(L(r._leaveCb))return;var i=n.css,a=n.type,o=n.leaveClass,s=n.leaveToClass,l=n.leaveActiveClass,u=n.beforeLeave,f=n.leave,d=n.afterLeave,p=n.leaveCancelled,h=n.delayLeave,b=n.duration,y=i!==!1&&!Js,P=Tb(f),C=_u(gr(b)?b.leave:b),R=r._leaveCb=jf(function(){r.parentNode&&r.parentNode._pending&&(r.parentNode._pending[t.key]=null),y&&(ki(r,s),ki(r,l)),R.cancelled?(y&&ki(r,o),p&&p(r)):(e(),d&&d(r)),r._leaveCb=null});h?h(D):D();function D(){R.cancelled||(!t.data.show&&r.parentNode&&((r.parentNode._pending||(r.parentNode._pending={}))[t.key]=t),u&&u(r),y&&(po(r,o),po(r,l),r$(function(){ki(r,o),R.cancelled||(po(r,s),P||(o$(C)?setTimeout(R,C):n$(r,a,R)))})),f&&f(r,R),!y&&!P&&R())}}function o$(t){return typeof t==\"number\"&&!isNaN(t)}function Tb(t){if(Oe(t))return!1;var e=t.fns;return L(e)?Tb(Array.isArray(e)?e[0]:e):(t._length||t.length)>1}function y_(t,e){e.data.show!==!0&&Am(e)}var bL=wn?{create:y_,activate:y_,remove:function(t,e){t.data.show!==!0?a$(t,e):e()}}:{},yL=[tL,rL,sL,fL,mL,bL],OL=yL.concat(eL),_L=qk({nodeOps:Gk,modules:OL});Js&&document.addEventListener(\"selectionchange\",function(){var t=document.activeElement;t&&t.vmodel&&Sb(t,\"input\")});var s$={inserted:function(t,e,r,n){r.tag===\"select\"?(n.elm&&!n.elm._vOptions?pa(r,\"postpatch\",function(){s$.componentUpdated(t,e,r)}):O_(t,e,r.context),t._vOptions=[].map.call(t.options,Jf)):(r.tag===\"textarea\"||Cm(t.type))&&(t._vModifiers=e.modifiers,e.modifiers.lazy||(t.addEventListener(\"compositionstart\",wL),t.addEventListener(\"compositionend\",T_),t.addEventListener(\"change\",T_),Js&&(t.vmodel=!0)))},componentUpdated:function(t,e,r){if(r.tag===\"select\"){O_(t,e,r.context);var n=t._vOptions,i=t._vOptions=[].map.call(t.options,Jf);if(i.some(function(o,s){return!_o(o,n[s])})){var a=t.multiple?e.value.some(function(o){return w_(o,i)}):e.value!==e.oldValue&&w_(e.value,i);a&&Sb(t,\"change\")}}}};function O_(t,e,r){__(t,e),(Xs||nb)&&setTimeout(function(){__(t,e)},0)}function __(t,e,r){var n=e.value,i=t.multiple;if(!(i&&!Array.isArray(n))){for(var a,o,s=0,l=t.options.length;s<l;s++)if(o=t.options[s],i)a=O1(n,Jf(o))>-1,o.selected!==a&&(o.selected=a);else if(_o(Jf(o),n)){t.selectedIndex!==s&&(t.selectedIndex=s);return}i||(t.selectedIndex=-1)}}function w_(t,e){return e.every(function(r){return!_o(r,t)})}function Jf(t){return\"_value\"in t?t._value:t.value}function wL(t){t.target.composing=!0}function T_(t){!t.target.composing||(t.target.composing=!1,Sb(t.target,\"input\"))}function Sb(t,e){var r=document.createEvent(\"HTMLEvents\");r.initEvent(e,!0,!0),t.dispatchEvent(r)}function Rm(t){return t.componentInstance&&(!t.data||!t.data.transition)?Rm(t.componentInstance._vnode):t}var TL={bind:function(t,e,r){var n=e.value;r=Rm(r);var i=r.data&&r.data.transition,a=t.__vOriginalDisplay=t.style.display===\"none\"?\"\":t.style.display;n&&i?(r.data.show=!0,Am(r,function(){t.style.display=a})):t.style.display=n?a:\"none\"},update:function(t,e,r){var n=e.value,i=e.oldValue;if(!n!=!i){r=Rm(r);var a=r.data&&r.data.transition;a?(r.data.show=!0,n?Am(r,function(){t.style.display=t.__vOriginalDisplay}):a$(r,function(){t.style.display=\"none\"})):t.style.display=n?t.__vOriginalDisplay:\"none\"}},unbind:function(t,e,r,n,i){i||(t.style.display=t.__vOriginalDisplay)}},SL={model:s$,show:TL},l$={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function xm(t){var e=t&&t.componentOptions;return e&&e.Ctor.options.abstract?xm(I1(e.children)):t}function u$(t){var e={},r=t.$options;for(var n in r.propsData)e[n]=t[n];var i=r._parentListeners;for(var n in i)e[Oo(n)]=i[n];return e}function S_(t,e){if(/\\d-keep-alive$/.test(e.tag))return t(\"keep-alive\",{props:e.componentOptions.propsData})}function PL(t){for(;t=t.parent;)if(t.data.transition)return!0}function EL(t,e){return e.key===t.key&&e.tag===t.tag}var $L=function(t){return t.tag||Tu(t)},CL=function(t){return t.name===\"show\"},DL={name:\"transition\",props:l$,abstract:!0,render:function(t){var e=this,r=this.$slots.default;if(!!r&&(r=r.filter($L),!!r.length)){var n=this.mode,i=r[0];if(PL(this.$vnode))return i;var a=xm(i);if(!a)return i;if(this._leaving)return S_(t,i);var o=\"__transition-\".concat(this._uid,\"-\");a.key=a.key==null?a.isComment?o+\"comment\":o+a.tag:ju(a.key)?String(a.key).indexOf(o)===0?a.key:o+a.key:a.key;var s=(a.data||(a.data={})).transition=u$(this),l=this._vnode,u=xm(l);if(a.data.directives&&a.data.directives.some(CL)&&(a.data.show=!0),u&&u.data&&!EL(a,u)&&!Tu(u)&&!(u.componentInstance&&u.componentInstance._vnode.isComment)){var f=u.data.transition=ut({},s);if(n===\"out-in\")return this._leaving=!0,pa(f,\"afterLeave\",function(){e._leaving=!1,e.$forceUpdate()}),S_(t,i);if(n===\"in-out\"){if(Tu(a))return l;var d,p=function(){d()};pa(s,\"afterEnter\",p),pa(s,\"enterCancelled\",p),pa(f,\"delayLeave\",function(h){d=h})}}return i}}},c$=ut({tag:String,moveClass:String},l$);delete c$.mode;var AL={props:c$,beforeMount:function(){var t=this,e=this._update;this._update=function(r,n){var i=F1(t);t.__patch__(t._vnode,t.kept,!1,!0),t._vnode=t.kept,i(),e.call(t,r,n)}},render:function(t){for(var e=this.tag||this.$vnode.data.tag||\"span\",r=Object.create(null),n=this.prevChildren=this.children,i=this.$slots.default||[],a=this.children=[],o=u$(this),s=0;s<i.length;s++){var l=i[s];l.tag&&l.key!=null&&String(l.key).indexOf(\"__vlist\")!==0&&(a.push(l),r[l.key]=l,(l.data||(l.data={})).transition=o)}if(n){for(var u=[],f=[],s=0;s<n.length;s++){var l=n[s];l.data.transition=o,l.data.pos=l.elm.getBoundingClientRect(),r[l.key]?u.push(l):f.push(l)}this.kept=t(e,null,u),this.removed=f}return t(e,null,a)},updated:function(){var t=this.prevChildren,e=this.moveClass||(this.name||\"v\")+\"-move\";!t.length||!this.hasMove(t[0].elm,e)||(t.forEach(RL),t.forEach(xL),t.forEach(ML),this._reflow=document.body.offsetHeight,t.forEach(function(r){if(r.data.moved){var n=r.elm,i=n.style;po(n,e),i.transform=i.WebkitTransform=i.transitionDuration=\"\",n.addEventListener(Xf,n._moveCb=function a(o){o&&o.target!==n||(!o||/transform$/.test(o.propertyName))&&(n.removeEventListener(Xf,a),n._moveCb=null,ki(n,e))})}}))},methods:{hasMove:function(t,e){if(!e$)return!1;if(this._hasMove)return this._hasMove;var r=t.cloneNode();t._transitionClasses&&t._transitionClasses.forEach(function(i){Z1(r,i)}),J1(r,e),r.style.display=\"none\",this.$el.appendChild(r);var n=i$(r);return this.$el.removeChild(r),this._hasMove=n.hasTransform}}};function RL(t){t.elm._moveCb&&t.elm._moveCb(),t.elm._enterCb&&t.elm._enterCb()}function xL(t){t.data.newPos=t.elm.getBoundingClientRect()}function ML(t){var e=t.data.pos,r=t.data.newPos,n=e.left-r.left,i=e.top-r.top;if(n||i){t.data.moved=!0;var a=t.elm.style;a.transform=a.WebkitTransform=\"translate(\".concat(n,\"px,\").concat(i,\"px)\"),a.transitionDuration=\"0s\"}}var NL={Transition:DL,TransitionGroup:AL};ye.config.mustUseProp=Ok;ye.config.isReservedTag=K1;ye.config.isReservedAttr=bk;ye.config.getTagNamespace=Ak;ye.config.isUnknownElement=Rk;ut(ye.options.directives,SL);ut(ye.options.components,NL);ye.prototype.__patch__=wn?_L:Qt;ye.prototype.$mount=function(t,e){return t=t&&wn?xk(t):void 0,SB(this,t,e)};wn&&setTimeout(function(){Bn.devtools&&Vf&&Vf.emit(\"init\",ye)},0);var f$=function(){return(f$=Object.assign||function(t){for(var e,r=1,n=arguments.length;r<n;r++)for(var i in e=arguments[r])Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i]);return t}).apply(this,arguments)},Uh={kebab:/-(\\w)/g,styleProp:/:(.*)/,styleList:/;(?![^(]*\\))/g};function IL(t,e){return e?e.toUpperCase():\"\"}function BL(t){for(var e,r={},n=0,i=t.split(Uh.styleList);n<i.length;n++){var a=i[n].split(Uh.styleProp),o=a[0],s=a[1];(o=o.trim())&&(typeof s==\"string\"&&(s=s.trim()),r[e=o,e.replace(Uh.kebab,IL)]=s)}return r}function oe(){for(var t,e,r={},n=arguments.length;n--;)for(var i=0,a=Object.keys(arguments[n]);i<a.length;i++)switch(t=a[i]){case\"class\":case\"style\":case\"directives\":if(Array.isArray(r[t])||(r[t]=[]),t===\"style\"){var o=void 0;o=Array.isArray(arguments[n].style)?arguments[n].style:[arguments[n].style];for(var s=0;s<o.length;s++){var l=o[s];typeof l==\"string\"&&(o[s]=BL(l))}arguments[n].style=o}r[t]=r[t].concat(arguments[n][t]);break;case\"staticClass\":if(!arguments[n][t])break;r[t]===void 0&&(r[t]=\"\"),r[t]&&(r[t]+=\" \"),r[t]+=arguments[n][t].trim();break;case\"on\":case\"nativeOn\":r[t]||(r[t]={});for(var u=0,f=Object.keys(arguments[n][t]||{});u<f.length;u++)e=f[u],r[t][e]?r[t][e]=[].concat(r[t][e],arguments[n][t][e]):r[t][e]=arguments[n][t][e];break;case\"attrs\":case\"props\":case\"domProps\":case\"scopedSlots\":case\"staticStyle\":case\"hook\":case\"transition\":r[t]||(r[t]={}),r[t]=f$({},arguments[n][t],r[t]);break;case\"slot\":case\"key\":case\"ref\":case\"tag\":case\"show\":case\"keepAlive\":default:r[t]||(r[t]=arguments[n][t])}return r}function P_(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Pl(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?P_(Object(r),!0).forEach(function(n){kL(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):P_(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function kL(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function LL(t,e){if(t==null)return{};var r=FL(t,e),n,i;if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);for(i=0;i<a.length;i++)n=a[i],!(e.indexOf(n)>=0)&&(!Object.prototype.propertyIsEnumerable.call(t,n)||(r[n]=t[n]))}return r}function FL(t,e){if(t==null)return{};var r={},n=Object.keys(t),i,a;for(a=0;a<n.length;a++)i=n[a],!(e.indexOf(i)>=0)&&(r[i]=t[i]);return r}function Zf(t){return Zf=typeof Symbol==\"function\"&&typeof Symbol.iterator==\"symbol\"?function(e){return typeof e}:function(e){return e&&typeof Symbol==\"function\"&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},Zf(t)}var ji=\"_uid\",Nr=ye.version.startsWith(\"3\"),Pb=Nr?\"ref_for\":\"refInFor\",jL=[\"class\",\"staticClass\",\"style\",\"attrs\",\"props\",\"domProps\",\"on\",\"nativeOn\",\"directives\",\"scopedSlots\",\"slot\",\"key\",\"ref\",\"refInFor\"],I=ye.extend.bind(ye);if(Nr){var VL=ye.extend,HL=[\"router-link\",\"transition\",\"transition-group\"],zL=ye.vModelDynamic.created,UL=ye.vModelDynamic.beforeUpdate;ye.vModelDynamic.created=function(t,e,r){zL.call(this,t,e,r),t._assign||(t._assign=function(){})},ye.vModelDynamic.beforeUpdate=function(t,e,r){UL.call(this,t,e,r),t._assign||(t._assign=function(){})},I=function(e){if(Zf(e)===\"object\"&&e.render&&!e.__alreadyPatched){var r=e.render;e.__alreadyPatched=!0,e.render=function(n){var i=function(p,h,b){var y=b===void 0?[]:[Array.isArray(b)?b.filter(Boolean):b],P=typeof p==\"string\"&&!HL.includes(p),C=h&&Zf(h)===\"object\"&&!Array.isArray(h);if(!C)return n.apply(void 0,[p,h].concat(y));var R=h.attrs,D=h.props,B=LL(h,[\"attrs\",\"props\"]),A=Pl(Pl({},B),{},{attrs:R,props:P?{}:D});return p===\"router-link\"&&!A.slots&&!A.scopedSlots&&(A.scopedSlots={$hasNormal:function(){}}),n.apply(void 0,[p,A].concat(y))};if(e.functional){var a,o,s=arguments[1],l=Pl({},s);l.data={attrs:Pl({},s.data.attrs||{}),props:Pl({},s.data.props||{})},Object.keys(s.data||{}).forEach(function(d){jL.includes(d)?l.data[d]=s.data[d]:d in s.props?l.data.props[d]=s.data[d]:d.startsWith(\"on\")||(l.data.attrs[d]=s.data[d])});var u=[\"_ctx\"],f=((a=s.children)===null||a===void 0||(o=a.default)===null||o===void 0?void 0:o.call(a))||s.children;return f&&Object.keys(l.children).filter(function(d){return!u.includes(d)}).length===0?delete l.children:l.children=f,l.data.on=s.listeners,r.call(this,i,l)}return r.call(this,i)}}return VL.call(this,e)}.bind(ye)}var Eb=ye.nextTick,el=typeof window<\"u\",d$=typeof document<\"u\",p$=typeof navigator<\"u\",h$=typeof Promise<\"u\",GL=typeof MutationObserver<\"u\"||typeof WebKitMutationObserver<\"u\"||typeof MozMutationObserver<\"u\",Je=el&&d$&&p$,wt=el?window:{},tl=d$?document:{},v$=p$?navigator:{},m$=(v$.userAgent||\"\").toLowerCase(),WL=m$.indexOf(\"jsdom\")>0;/msie|trident/.test(m$);var KL=function(){var t=!1;if(Je)try{var e={get passive(){t=!0}};wt.addEventListener(\"test\",e,e),wt.removeEventListener(\"test\",e,e)}catch{t=!1}return t}(),Qf=Je&&(\"ontouchstart\"in tl.documentElement||v$.maxTouchPoints>0),El=Je&&Boolean(wt.PointerEvent||wt.MSPointerEvent),E_=Je&&\"IntersectionObserver\"in wt&&\"IntersectionObserverEntry\"in wt&&\"intersectionRatio\"in wt.IntersectionObserverEntry.prototype,YL=\"BvConfig\",vs=\"$bvConfig\",qL=[\"xs\",\"sm\",\"md\",\"lg\",\"xl\"],XL=/\\[(\\d+)]/g,JL=/^(BV?)/,g$=/^\\d+$/,ZL=/^\\..+/,QL=/^#/,eF=/^#[A-Za-z]+[\\w\\-:.]*$/,tF=/(<([^>]+)>)/gi,rF=/\\B([A-Z])/g,nF=/([a-z])([A-Z])/g,iF=/^[0-9]*\\.?[0-9]+$/,aF=/\\+/g,oF=/[-/\\\\^$*+?.()|[\\]{}]/g,b$=/[\\s\\uFEFF\\xA0]+/g,sf=/\\s+/,sF=/\\/\\*$/,lF=/(\\s|^)(\\w)/g,uF=/^\\s+/,cF=/_/g,fF=/-(\\w)/g,dF=/^\\d+-\\d\\d?-\\d\\d?(?:\\s|T|$)/,pF=/-|\\s|T/,hF=/^([0-1]?[0-9]|2[0-3]):[0-5]?[0-9](:[0-5]?[0-9])?$/,$_=/^.*(#[^#]+)$/,vF=/%2C/g,mF=/[!'()*]/g,gF=/^(\\?|#|&)/,bF=/^\\d+(\\.\\d*)?[/:]\\d+(\\.\\d*)?$/,yF=/[/:]/,OF=/^col-/,_F=/^BIcon/,wF=/-u-.+/;function Mm(t){return Mm=typeof Symbol==\"function\"&&typeof Symbol.iterator==\"symbol\"?function(e){return typeof e}:function(e){return e&&typeof Symbol==\"function\"&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},Mm(t)}function ep(t,e){if(!(t instanceof e))throw new TypeError(\"Cannot call a class as a function\")}function tp(t,e){if(typeof e!=\"function\"&&e!==null)throw new TypeError(\"Super expression must either be null or a function\");Object.defineProperty(t,\"prototype\",{value:Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),writable:!1}),e&&$u(t,e)}function rp(t){var e=y$();return function(){var n=Cu(t),i;if(e){var a=Cu(this).constructor;i=Reflect.construct(n,arguments,a)}else i=n.apply(this,arguments);return TF(this,i)}}function TF(t,e){if(e&&(Mm(e)===\"object\"||typeof e==\"function\"))return e;if(e!==void 0)throw new TypeError(\"Derived constructors may only return object or undefined\");return SF(t)}function SF(t){if(t===void 0)throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");return t}function ed(t){var e=typeof Map==\"function\"?new Map:void 0;return ed=function(n){if(n===null||!PF(n))return n;if(typeof n!=\"function\")throw new TypeError(\"Super expression must either be null or a function\");if(typeof e<\"u\"){if(e.has(n))return e.get(n);e.set(n,i)}function i(){return lf(n,arguments,Cu(this).constructor)}return i.prototype=Object.create(n.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),$u(i,n)},ed(t)}function lf(t,e,r){return y$()?lf=Reflect.construct:lf=function(i,a,o){var s=[null];s.push.apply(s,a);var l=Function.bind.apply(i,s),u=new l;return o&&$u(u,o.prototype),u},lf.apply(null,arguments)}function y$(){if(typeof Reflect>\"u\"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy==\"function\")return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch{return!1}}function PF(t){return Function.toString.call(t).indexOf(\"[native code]\")!==-1}function $u(t,e){return $u=Object.setPrototypeOf||function(n,i){return n.__proto__=i,n},$u(t,e)}function Cu(t){return Cu=Object.setPrototypeOf?Object.getPrototypeOf:function(r){return r.__proto__||Object.getPrototypeOf(r)},Cu(t)}var $b=el?wt.Element:function(t){tp(r,t);var e=rp(r);function r(){return ep(this,r),e.apply(this,arguments)}return r}(ed(Object)),ba=el?wt.HTMLElement:function(t){tp(r,t);var e=rp(r);function r(){return ep(this,r),e.apply(this,arguments)}return r}($b),O$=el?wt.SVGElement:function(t){tp(r,t);var e=rp(r);function r(){return ep(this,r),e.apply(this,arguments)}return r}($b),_$=el?wt.File:function(t){tp(r,t);var e=rp(r);function r(){return ep(this,r),e.apply(this,arguments)}return r}(ed(Object));function td(t){return td=typeof Symbol==\"function\"&&typeof Symbol.iterator==\"symbol\"?function(e){return typeof e}:function(e){return e&&typeof Symbol==\"function\"&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},td(t)}var np=function(e){return td(e)},EF=function(e){return Object.prototype.toString.call(e).slice(8,-1)},Et=function(e){return e===void 0},nt=function(e){return e===null},Ge=function(e){return Et(e)||nt(e)},se=function(e){return np(e)===\"function\"},Mn=function(e){return np(e)===\"boolean\"},Ae=function(e){return np(e)===\"string\"},Kn=function(e){return np(e)===\"number\"},cu=function(e){return iF.test(String(e))},He=function(e){return Array.isArray(e)},St=function(e){return e!==null&&td(e)===\"object\"},yr=function(e){return Object.prototype.toString.call(e)===\"[object Object]\"},xs=function(e){return e instanceof Date},Po=function(e){return e instanceof Event},$F=function(e){return e instanceof _$},C_=function(e){return EF(e)===\"RegExp\"},CF=function(e){return!Ge(e)&&se(e.then)&&se(e.catch)};function D_(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Eo(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?D_(Object(r),!0).forEach(function(n){Uu(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):D_(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Uu(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Gu=function(){return Object.assign.apply(Object,arguments)},va=function(e,r){return Object.create(e,r)},ip=function(e,r){return Object.defineProperties(e,r)},Cb=function(e,r,n){return Object.defineProperty(e,r,n)},A_=function(e){return Object.getOwnPropertyNames(e)},ge=function(e){return Object.keys(e)},$o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},DF=function(e){return Object.prototype.toString.call(e)},Na=function(e){return Eo({},e)},Zn=function(e,r){return ge(e).filter(function(n){return r.indexOf(n)!==-1}).reduce(function(n,i){return Eo(Eo({},n),{},Uu({},i,e[i]))},{})},Pe=function(e,r){return ge(e).filter(function(n){return r.indexOf(n)===-1}).reduce(function(n,i){return Eo(Eo({},n),{},Uu({},i,e[i]))},{})},AF=function t(e,r){return St(e)&&St(r)&&ge(r).forEach(function(n){St(r[n])?((!e[n]||!St(e[n]))&&(e[n]=r[n]),t(e[n],r[n])):Gu(e,Uu({},n,r[n]))}),e},ie=function(e){return ge(e).sort().reduce(function(r,n){return Eo(Eo({},r),{},Uu({},n,e[n]))},{})},xn=function(){return{enumerable:!0,configurable:!1,writable:!1}};function R_(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function x_(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?R_(Object(r),!0).forEach(function(n){w$(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):R_(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function w$(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function RF(t){return IF(t)||NF(t)||MF(t)||xF()}function xF(){throw new TypeError(`Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function MF(t,e){if(!!t){if(typeof t==\"string\")return Nm(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);if(r===\"Object\"&&t.constructor&&(r=t.constructor.name),r===\"Map\"||r===\"Set\")return Array.from(t);if(r===\"Arguments\"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return Nm(t,e)}}function NF(t){if(typeof Symbol<\"u\"&&t[Symbol.iterator]!=null||t[\"@@iterator\"]!=null)return Array.from(t)}function IF(t){if(Array.isArray(t))return Nm(t)}function Nm(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}var Nn=function t(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:e;return He(e)?e.reduce(function(n,i){return[].concat(RF(n),[t(i,i)])},[]):yr(e)?ge(e).reduce(function(n,i){return x_(x_({},n),{},w$({},i,t(e[i],e[i])))},{}):r},pe=function(e){return e},T$=function(e,r){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:void 0;if(r=He(r)?r.join(\".\"):r,!r||!St(e))return n;if(r in e)return e[r];r=String(r).replace(XL,\".$1\");var i=r.split(\".\").filter(pe);return i.length===0?n:i.every(function(a){return St(e)&&a in e&&!Ge(e=e[a])})?e:nt(e)?null:n},ur=function(e,r){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:null,i=T$(e,r);return Ge(i)?n:i},M_=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:null,n=typeof process<\"u\"&&process?process.env||{}:{};return e?n[e]||r:n},BF=function(){return M_(\"BOOTSTRAP_VUE_NO_WARN\")||M_(\"NODE_ENV\")===\"production\"},jt=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:null;BF()||console.warn(\"[BootstrapVue warn]: \".concat(r?\"\".concat(r,\" - \"):\"\").concat(e))},rd=function(e){return Je?!1:(jt(\"\".concat(e,\": Can not be called during SSR.\")),!0)},N_=function(e){return h$?!1:(jt(\"\".concat(e,\": Requires Promise support.\")),!0)},kF=function(e){return GL?!1:(jt(\"\".concat(e,\": Requires MutationObserver support.\")),!0)};function LF(t,e){if(!(t instanceof e))throw new TypeError(\"Cannot call a class as a function\")}function I_(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,\"value\"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}function FF(t,e,r){return e&&I_(t.prototype,e),r&&I_(t,r),Object.defineProperty(t,\"prototype\",{writable:!1}),t}var jF=function(){function t(){LF(this,t),this.$_config={}}return FF(t,[{key:\"setConfig\",value:function(){var r=this,n=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};if(!!yr(n)){var i=A_(n);i.forEach(function(a){var o=n[a];a===\"breakpoints\"?!He(o)||o.length<2||o.some(function(s){return!Ae(s)||s.length===0})?jt('\"breakpoints\" must be an array of at least 2 breakpoint names',YL):r.$_config[a]=Nn(o):yr(o)&&(r.$_config[a]=A_(o).reduce(function(s,l){return Et(o[l])||(s[l]=Nn(o[l])),s},r.$_config[a]||{}))})}}},{key:\"resetConfig\",value:function(){this.$_config={}}},{key:\"getConfig\",value:function(){return Nn(this.$_config)}},{key:\"getConfigValue\",value:function(r){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:void 0;return Nn(T$(this.$_config,r,n))}}]),t}(),VF=function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:ye;r.prototype[vs]=ye.prototype[vs]=r.prototype[vs]||ye.prototype[vs]||new jF,r.prototype[vs].setConfig(e)};function B_(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function k_(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?B_(Object(r),!0).forEach(function(n){HF(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):B_(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function HF(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var zF=function(){var t=!1,e=[\"Multiple instances of Vue detected!\",\"You may need to set up an alias for Vue in your bundler config.\",\"See: https://bootstrap-vue.org/docs#using-module-bundlers\"].join(`\n`);return function(r){!t&&ye!==r&&!WL&&jt(e),t=!0}}(),S$=function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},r=e.components,n=e.directives,i=e.plugins,a=function o(s){var l=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};o.installed||(o.installed=!0,zF(s),VF(l,s),WF(s,r),YF(s,n),UF(s,i))};return a.installed=!1,a},ae=function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return k_(k_({},r),{},{install:S$(e)})},UF=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};for(var n in r)n&&r[n]&&e.use(r[n])},GF=function(e,r,n){e&&r&&n&&e.component(r,n)},WF=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};for(var n in r)GF(e,n,r[n])},KF=function(e,r,n){e&&r&&n&&e.directive(r.replace(/^VB/,\"B\"),n)},YF=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};for(var n in r)KF(e,n,r[n])},P$=\"BAlert\",E$=\"BAspect\",$$=\"BAvatar\",C$=\"BAvatarGroup\",D$=\"BBadge\",A$=\"BBreadcrumb\",R$=\"BBreadcrumbItem\",x$=\"BBreadcrumbLink\",M$=\"BButton\",N$=\"BButtonClose\",I$=\"BButtonGroup\",B$=\"BButtonToolbar\",k$=\"BCalendar\",Db=\"BCard\",L$=\"BCardBody\",F$=\"BCardFooter\",j$=\"BCardGroup\",V$=\"BCardHeader\",H$=\"BCardImg\",z$=\"BCardImgLazy\",U$=\"BCardSubTitle\",G$=\"BCardText\",W$=\"BCardTitle\",K$=\"BCarousel\",Y$=\"BCarouselSlide\",q$=\"BCol\",fr=\"BCollapse\",X$=\"BContainer\",Co=\"BDropdown\",J$=\"BDropdownDivider\",Z$=\"BDropdownForm\",Q$=\"BDropdownGroup\",eC=\"BDropdownHeader\",tC=\"BDropdownItem\",rC=\"BDropdownItemButton\",nC=\"BDropdownText\",iC=\"BEmbed\",aC=\"BForm\",oC=\"BFormCheckbox\",sC=\"BFormCheckboxGroup\",lC=\"BFormDatalist\",uC=\"BFormDatepicker\",Ab=\"BFormFile\",cC=\"BFormGroup\",fC=\"BFormInput\",dC=\"BFormInvalidFeedback\",pC=\"BFormRadio\",hC=\"BFormRadioGroup\",vC=\"BFormRating\",mC=\"BFormRow\",gC=\"BFormSelect\",bC=\"BFormSelectOption\",yC=\"BFormSelectOptionGroup\",OC=\"BFormSpinbutton\",_C=\"BFormTag\",wC=\"BFormTags\",TC=\"BFormText\",SC=\"BFormTextarea\",PC=\"BFormTimepicker\",EC=\"BFormValidFeedback\",$C=\"BIcon\",qF=\"BIconBase\",CC=\"BImg\",DC=\"BImgLazy\",AC=\"BInputGroup\",RC=\"BInputGroupAddon\",xC=\"BInputGroupAppend\",MC=\"BInputGroupPrepend\",NC=\"BInputGroupText\",IC=\"BJumbotron\",Rb=\"BLink\",BC=\"BListGroup\",kC=\"BListGroupItem\",LC=\"BMedia\",FC=\"BMediaAside\",jC=\"BMediaBody\",Gr=\"BModal\",XF=\"BMsgBox\",VC=\"BNav\",HC=\"BNavbar\",zC=\"BNavbarBrand\",UC=\"BNavbarNav\",GC=\"BNavbarToggle\",WC=\"BNavForm\",KC=\"BNavItem\",YC=\"BNavItemDropdown\",JF=\"BNavText\",qC=\"BOverlay\",ap=\"BPagination\",Im=\"BPaginationNav\",no=\"BPopover\",XC=\"BProgress\",JC=\"BProgressBar\",ZC=\"BRow\",QC=\"BSidebar\",eD=\"BSkeleton\",tD=\"BSkeletonIcon\",rD=\"BSkeletonImg\",nD=\"BSkeletonTable\",iD=\"BSkeletonWrapper\",aD=\"BSpinner\",oD=\"BTab\",Do=\"BTable\",sD=\"BTableCell\",lD=\"BTableLite\",uD=\"BTableSimple\",cD=\"BTabs\",fD=\"BTbody\",dD=\"BTfoot\",pD=\"BTh\",hD=\"BThead\",vD=\"BTime\",Li=\"BToast\",As=\"BToaster\",io=\"BTooltip\",mD=\"BTr\",ZF=\"BVCollapse\",QF=\"BVFormBtnLabelControl\",ej=\"BVFormRatingStar\",tj=\"BVPopover\",rj=\"BVPopoverTemplate\",nj=\"BVPopper\",ij=\"BVTabButton\",aj=\"BVToastPop\",oj=\"BVTooltip\",sj=\"BVTooltipTemplate\",lj=\"BVTransition\",gD=\"BVTransporter\",uj=\"BVTransporterTarget\",cj=\"activate-tab\",bD=\"blur\",fj=\"cancel\",en=\"change\",dj=\"changed\",Ln=\"click\",Bm=\"close\",Ms=\"context\",yD=\"context-changed\",xb=\"destroyed\",km=\"disable\",uf=\"disabled\",pj=\"dismissed\",hj=\"dismiss-count-down\",Lm=\"enable\",cf=\"enabled\",Fm=\"filtered\",OD=\"first\",vj=\"focus\",nd=\"focusin\",id=\"focusout\",fu=\"head-clicked\",Pt=\"hidden\",Xr=\"hide\",mj=\"img-error\",_D=\"input\",wD=\"last\",TD=\"mouseenter\",SD=\"mouseleave\",PD=\"next\",gj=\"ok\",L_=\"open\",ED=\"page-click\",bj=\"paused\",$D=\"prev\",yj=\"refresh\",Kl=\"refreshed\",Oj=\"remove\",ad=\"row-clicked\",_j=\"row-contextmenu\",wj=\"row-dblclicked\",Tj=\"row-hovered\",Sj=\"row-middle-clicked\",Pj=\"row-selected\",Ej=\"row-unhovered\",CD=\"selected\",tr=\"show\",Dr=\"shown\",Gh=\"sliding-end\",$j=\"sliding-start\",Cj=\"sort-changed\",Dj=\"tag-state\",DD=\"toggle\",Aj=\"unpaused\",Rj=\"update\",AD=Nr?\"vnodeBeforeUnmount\":\"hook:beforeDestroy\",Du=Nr?\"vNodeUnmounted\":\"hook:destroyed\",Ia=\"update:\",RD=\"bv\",xD=\"::\",Yr={passive:!0},De={passive:!0,capture:!1},Ns=void 0,Ar=Array,_=Boolean,xj=Date,xr=Function,mr=Number,Mt=Object,Mj=RegExp,g=String,MD=[Ar,xr],Nj=[Ar,Mt],de=[Ar,Mt,g],Or=[Ar,g],Ij=[_,mr],Au=[_,mr,g],_r=[_,g],ho=[xj,g],Bj=[xr,g],re=[mr,g],kj=[mr,Mt,g],Lj=[Mt,xr],ND=[Mt,g],Fj=\"add-button-text\",F_=\"append\",jj=\"aside\",j_=\"badge\",V_=\"bottom-row\",Wi=\"button-content\",H_=\"custom-foot\",Vj=\"decrement\",kt=\"default\",Hj=\"description\",zj=\"dismiss\",Uj=\"drop-placeholder\",Gj=\"ellipsis-text\",ID=\"empty\",Wj=\"emptyfiltered\",z_=\"file-name\",Mb=\"first\",Kj=\"first-text\",jm=\"footer\",Ca=\"header\",Yj=\"header-close\",qj=\"icon-clear\",Xj=\"icon-empty\",Jj=\"icon-full\",Zj=\"icon-half\",Qj=\"img\",e2=\"increment\",t2=\"invalid-feedback\",BD=\"label\",r2=\"last-text\",U_=\"lead\",n2=\"loading\",i2=\"modal-backdrop\",G_=\"modal-cancel\",a2=\"modal-footer\",o2=\"modal-header\",s2=\"modal-header-close\",W_=\"modal-ok\",Wh=\"modal-title\",l2=\"nav-next-decade\",u2=\"nav-next-month\",c2=\"nav-next-year\",f2=\"nav-prev-decade\",d2=\"nav-prev-month\",p2=\"nav-prev-year\",h2=\"nav-this-month\",v2=\"next-text\",m2=\"overlay\",g2=\"page\",b2=\"placeholder\",K_=\"prepend\",y2=\"prev-text\",$l=\"row-details\",Yl=\"table-busy\",Y_=\"table-caption\",q_=\"table-colgroup\",O2=\"tabs-end\",_2=\"tabs-start\",w2=\"text\",T2=\"thead-top\",Wu=\"title\",S2=\"toast-title\",X_=\"top-row\",P2=\"valid-feedback\",Ao=function(){return Array.from.apply(Array,arguments)},he=function(e,r){return e.indexOf(r)!==-1},Me=function(){for(var e=arguments.length,r=new Array(e),n=0;n<e;n++)r[n]=arguments[n];return Array.prototype.concat.apply([],r)},du=function(e,r){var n=se(r)?r:function(){return r};return Array.apply(null,{length:e}).map(n)},E2=function(e){return e.reduce(function(r,n){return Me(r,n)},[])},Cl=function t(e){return e.reduce(function(r,n){return Me(r,Array.isArray(n)?t(n):n)},[])},Ki=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};return e=Me(e).filter(pe),e.some(function(i){return r[i]||n[i]})},rr=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},i=arguments.length>3&&arguments[3]!==void 0?arguments[3]:{};e=Me(e).filter(pe);for(var a,o=0;o<e.length&&!a;o++){var s=e[o];a=n[s]||i[s]}return se(a)?a(r):a},ve=I({methods:{hasNormalizedSlot:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:kt,r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:this.$scopedSlots,n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:this.$slots;return Ki(e,r,n)},normalizeSlot:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:kt,r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:this.$scopedSlots,i=arguments.length>3&&arguments[3]!==void 0?arguments[3]:this.$slots,a=rr(e,r,n,i);return a&&Me(a)}}}),ee=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:NaN,n=parseInt(e,10);return isNaN(n)?r:n},Ee=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:NaN,n=parseFloat(e);return isNaN(n)?r:n},Kh=function(e,r){return Ee(e).toFixed(ee(r,0))},Nb=function(e){return e.replace(rF,\"-$1\").toLowerCase()},kD=function(e){return e=Nb(e).replace(fF,function(r,n){return n?n.toUpperCase():\"\"}),e.charAt(0).toUpperCase()+e.slice(1)},ff=function(e){return e.replace(cF,\" \").replace(nF,function(r,n,i){return n+\" \"+i}).replace(lF,function(r,n,i){return n+i.toUpperCase()})},$2=function(e){return e=Ae(e)?e.trim():String(e),e.charAt(0).toLowerCase()+e.slice(1)},LD=function(e){return e=Ae(e)?e.trim():String(e),e.charAt(0).toUpperCase()+e.slice(1)},Ib=function(e){return e.replace(oF,\"\\\\$&\")},ce=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:2;return Ge(e)?\"\":He(e)||yr(e)&&e.toString===Object.prototype.toString?JSON.stringify(e,null,r):String(e)},C2=function(e){return ce(e).replace(uF,\"\")},ya=function(e){return ce(e).trim()},od=function(e){return ce(e).toLowerCase()},df=$b.prototype,D2=[\"button\",\"[href]:not(.disabled)\",\"input\",\"select\",\"textarea\",\"[tabindex]\",\"[contenteditable]\"].map(function(t){return\"\".concat(t,\":not(:disabled):not([disabled])\")}).join(\", \"),A2=df.matches||df.msMatchesSelector||df.webkitMatchesSelector,R2=df.closest||function(t){var e=this;do{if(Vi(e,t))return e;e=e.parentElement||e.parentNode}while(!nt(e)&&e.nodeType===Node.ELEMENT_NODE);return null},We=(wt.requestAnimationFrame||wt.webkitRequestAnimationFrame||wt.mozRequestAnimationFrame||wt.msRequestAnimationFrame||wt.oRequestAnimationFrame||function(t){return setTimeout(t,16)}).bind(wt),x2=wt.MutationObserver||wt.WebKitMutationObserver||wt.MozMutationObserver||null,M2=function(e){return e&&e.parentNode&&e.parentNode.removeChild(e)},et=function(e){return!!(e&&e.nodeType===Node.ELEMENT_NODE)},Da=function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:[],r=tl.activeElement;return r&&!e.some(function(n){return n===r})?r:null},wi=function(e,r){return ce(e).toLowerCase()===ce(r).toLowerCase()},Bb=function(e){return et(e)&&e===Da()},Yn=function(e){if(!et(e)||!e.parentNode||!Rt(tl.body,e)||ws(e,\"display\")===\"none\")return!1;var r=Ro(e);return!!(r&&r.height>0&&r.width>0)},lo=function(e){return!et(e)||e.disabled||mi(e,\"disabled\")||Ru(e,\"disabled\")},kb=function(e){return et(e)&&e.offsetHeight},yn=function(e,r){return Ao((et(r)?r:tl).querySelectorAll(e))},gn=function(e,r){return(et(r)?r:tl).querySelector(e)||null},Vi=function(e,r){return et(e)?A2.call(e,r):!1},Jr=function(e,r){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:!1;if(!et(r))return null;var i=R2.call(r,e);return n?i:i===r?null:i},Rt=function(e,r){return e&&se(e.contains)?e.contains(r):!1},Vm=function(e){return tl.getElementById(/^#/.test(e)?e.slice(1):e)||null},$r=function(e,r){r&&et(e)&&e.classList&&e.classList.add(r)},hr=function(e,r){r&&et(e)&&e.classList&&e.classList.remove(r)},Ru=function(e,r){return r&&et(e)&&e.classList?e.classList.contains(r):!1},st=function(e,r,n){r&&et(e)&&e.setAttribute(r,n)},vi=function(e,r){r&&et(e)&&e.removeAttribute(r)},bn=function(e,r){return r&&et(e)?e.getAttribute(r):null},mi=function(e,r){return r&&et(e)?e.hasAttribute(r):null},lr=function(e,r,n){r&&et(e)&&(e.style[r]=n)},op=function(e,r){r&&et(e)&&(e.style[r]=\"\")},ws=function(e,r){return r&&et(e)&&e.style[r]||null},Ro=function(e){return et(e)?e.getBoundingClientRect():null},hn=function(e){var r=wt.getComputedStyle;return r&&et(e)?r(e):{}},N2=function(){var e=wt.getSelection;return e?wt.getSelection():null},Hm=function(e){var r={top:0,left:0};if(!et(e)||e.getClientRects().length===0)return r;var n=Ro(e);if(n){var i=e.ownerDocument.defaultView;r.top=n.top+i.pageYOffset,r.left=n.left+i.pageXOffset}return r},I2=function(e){var r={top:0,left:0};if(!et(e))return r;var n={top:0,left:0},i=hn(e);if(i.position===\"fixed\")r=Ro(e)||r;else{r=Hm(e);for(var a=e.ownerDocument,o=e.offsetParent||a.documentElement;o&&(o===a.body||o===a.documentElement)&&hn(o).position===\"static\";)o=o.parentNode;if(o&&o!==e&&o.nodeType===Node.ELEMENT_NODE){n=Hm(o);var s=hn(o);n.top+=Ee(s.borderTopWidth,0),n.left+=Ee(s.borderLeftWidth,0)}}return{top:r.top-n.top-Ee(i.marginTop,0),left:r.left-n.left-Ee(i.marginLeft,0)}},zm=function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:document;return yn(D2,e).filter(Yn).filter(function(r){return r.tabIndex>-1&&!r.disabled})},we=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};try{e.focus(r)}catch{}return Bb(e)},rn=function(e){try{e.blur()}catch{}return!Bb(e)},Ku=function(e){var r=va(null);return function(){for(var n=arguments.length,i=new Array(n),a=0;a<n;a++)i[a]=arguments[a];var o=JSON.stringify(i);return r[o]=r[o]||e.apply(null,i)}},B2=ye.prototype,Um=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:void 0,n=B2[vs];return n?n.getConfigValue(e,r):Nn(r)},vn=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:null,n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:void 0;return r?Um(\"\".concat(e,\".\").concat(r),n):Um(e,{})},FD=function(){return Um(\"breakpoints\",qL)},k2=Ku(function(){return FD()}),L2=function(){return Nn(k2())},xu=Ku(function(){var t=L2();return t[0]=\"\",t});function J_(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function vo(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?J_(Object(r),!0).forEach(function(n){jD(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):J_(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function jD(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var sp=function(e,r){return e+LD(r)},VD=function(e,r){return $2(r.replace(e,\"\"))},Oa=function(e,r){return r+(e?LD(e):\"\")},c=function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:Ns,r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:void 0,n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:void 0,i=arguments.length>3&&arguments[3]!==void 0?arguments[3]:void 0,a=n===!0;return i=a?i:n,vo(vo(vo({},e?{type:e}:{}),a?{required:a}:Et(r)?{}:{default:St(r)?function(){return r}:r}),Et(i)?{}:{validator:i})},lp=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:pe;if(He(e))return e.map(r);var n={};for(var i in e)$o(e,i)&&(n[r(i)]=St(e[i])?Na(e[i]):e[i]);return n},at=function(e,r){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:pe;return(He(e)?e.slice():ge(e)).reduce(function(i,a){return i[n(a)]=r[a],i},{})},HD=function(e,r,n){return vo(vo({},Nn(e)),{},{default:function(){var a=vn(n,r,e.default);return se(a)?a():a}})},z=function(e,r){return ge(e).reduce(function(n,i){return vo(vo({},n),{},jD({},i,HD(e[i],i,r)))},{})},F2=HD({},\"\",\"\").default.name,yi=function(e){return se(e)&&e.name&&e.name!==F2};function j2(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Nt=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=r.type,i=n===void 0?Ns:n,a=r.defaultValue,o=a===void 0?void 0:a,s=r.validator,l=s===void 0?void 0:s,u=r.event,f=u===void 0?_D:u,d=j2({},e,c(i,o,l)),p=I({model:{prop:e,event:f},props:d});return{mixin:p,props:d,prop:e,event:f}},zD=function(e){return KL?St(e)?e:{capture:!!e||!1}:!!(St(e)?e.capture:e)},it=function(e,r,n,i){e&&e.addEventListener&&e.addEventListener(r,n,zD(i))},ft=function(e,r,n,i){e&&e.removeEventListener&&e.removeEventListener(r,n,zD(i))},qn=function(e){for(var r=e?it:ft,n=arguments.length,i=new Array(n>1?n-1:0),a=1;a<n;a++)i[a-1]=arguments[a];r.apply(void 0,i)},_e=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=r.preventDefault,i=n===void 0?!0:n,a=r.propagation,o=a===void 0?!0:a,s=r.immediatePropagation,l=s===void 0?!1:s;i&&e.preventDefault(),o&&e.stopPropagation(),l&&e.stopImmediatePropagation()},UD=function(e){return Nb(e.replace(JL,\"\"))},bt=function(e,r){return[RD,UD(e),r].join(xD)},xt=function(e,r){return[RD,r,UD(e)].join(xD)};function V2(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var H2=z({ariaLabel:c(g,\"Close\"),content:c(g,\"&times;\"),disabled:c(_,!1),textVariant:c(g)},N$),xo=I({name:N$,functional:!0,props:H2,render:function(e,r){var n=r.props,i=r.data,a=r.slots,o=r.scopedSlots,s=a(),l=o||{},u={staticClass:\"close\",class:V2({},\"text-\".concat(n.textVariant),n.textVariant),attrs:{type:\"button\",disabled:n.disabled,\"aria-label\":n.ariaLabel?String(n.ariaLabel):null},on:{click:function(d){n.disabled&&Po(d)&&_e(d)}}};return Ki(kt,l,s)||(u.domProps={innerHTML:n.content}),e(\"button\",oe(i,u),rr(kt,{},l,s))}});function Z_(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function ao(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?Z_(Object(r),!0).forEach(function(n){z2(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):Z_(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function z2(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var GD={name:\"\",enterClass:\"\",enterActiveClass:\"\",enterToClass:\"show\",leaveClass:\"show\",leaveActiveClass:\"\",leaveToClass:\"\"},U2=ao(ao({},GD),{},{enterActiveClass:\"fade\",leaveActiveClass:\"fade\"}),G2={appear:c(_,!1),mode:c(g),noFade:c(_,!1),transProps:c(Mt)},Io=I({name:lj,functional:!0,props:G2,render:function(e,r){var n=r.children,i=r.data,a=r.props,o=a.transProps;yr(o)||(o=a.noFade?GD:U2,a.appear&&(o=ao(ao({},o),{},{appear:!0,appearClass:o.enterClass,appearActiveClass:o.enterActiveClass,appearToClass:o.enterToClass}))),o=ao(ao({mode:a.mode},o),{},{css:!0});var s=ao({},i);return delete s.props,e(\"transition\",oe(s,{props:o}),n)}}),Dl;function Q_(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function ew(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?Q_(Object(r),!0).forEach(function(n){ql(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):Q_(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function ql(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var up=Nt(\"show\",{type:Au,defaultValue:!1}),W2=up.mixin,K2=up.props,Al=up.prop,tw=up.event,rw=function(e){return e===\"\"||Mn(e)?0:(e=ee(e,0),e>0?e:0)},Yh=function(e){return e===\"\"||e===!0?!0:ee(e,0)<1?!1:!!e},Y2=z(ie(ew(ew({},K2),{},{dismissLabel:c(g,\"Close\"),dismissible:c(_,!1),fade:c(_,!1),variant:c(g,\"info\")})),P$),q2=I({name:P$,mixins:[W2,ve],props:Y2,data:function(){return{countDown:0,localShow:Yh(this[Al])}},watch:(Dl={},ql(Dl,Al,function(t){this.countDown=rw(t),this.localShow=Yh(t)}),ql(Dl,\"countDown\",function(e){var r=this;this.clearCountDownInterval();var n=this[Al];cu(n)&&(this.$emit(hj,e),n!==e&&this.$emit(tw,e),e>0?(this.localShow=!0,this.$_countDownTimeout=setTimeout(function(){r.countDown--},1e3)):this.$nextTick(function(){We(function(){r.localShow=!1})}))}),ql(Dl,\"localShow\",function(e){var r=this[Al];!e&&(this.dismissible||cu(r))&&this.$emit(pj),!cu(r)&&r!==e&&this.$emit(tw,e)}),Dl),created:function(){this.$_filterTimer=null;var e=this[Al];this.countDown=rw(e),this.localShow=Yh(e)},beforeDestroy:function(){this.clearCountDownInterval()},methods:{dismiss:function(){this.clearCountDownInterval(),this.countDown=0,this.localShow=!1},clearCountDownInterval:function(){clearTimeout(this.$_countDownTimeout),this.$_countDownTimeout=null}},render:function(e){var r=e();if(this.localShow){var n=this.dismissible,i=this.variant,a=e();n&&(a=e(xo,{attrs:{\"aria-label\":this.dismissLabel},on:{click:this.dismiss}},[this.normalizeSlot(zj)])),r=e(\"div\",{staticClass:\"alert\",class:ql({\"alert-dismissible\":n},\"alert-\".concat(i),i),attrs:{role:\"alert\",\"aria-live\":\"polite\",\"aria-atomic\":!0},key:this[ji]},[a,this.normalizeSlot()])}return e(Io,{props:{noFade:!this.fade}},[r])}}),X2=ae({components:{BAlert:q2}}),Fi=Math.min,Fe=Math.max,WD=Math.abs,KD=Math.ceil,Mu=Math.floor,YD=Math.pow,Gm=Math.round;function J2(t,e){return tV(t)||eV(t,e)||Q2(t,e)||Z2()}function Z2(){throw new TypeError(`Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function Q2(t,e){if(!!t){if(typeof t==\"string\")return nw(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);if(r===\"Object\"&&t.constructor&&(r=t.constructor.name),r===\"Map\"||r===\"Set\")return Array.from(t);if(r===\"Arguments\"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return nw(t,e)}}function nw(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}function eV(t,e){var r=t==null?null:typeof Symbol<\"u\"&&t[Symbol.iterator]||t[\"@@iterator\"];if(r!=null){var n=[],i=!0,a=!1,o,s;try{for(r=r.call(t);!(i=(o=r.next()).done)&&(n.push(o.value),!(e&&n.length===e));i=!0);}catch(l){a=!0,s=l}finally{try{!i&&r.return!=null&&r.return()}finally{if(a)throw s}}return n}}function tV(t){if(Array.isArray(t))return t}var qh=\"b-aspect\",rV=z({aspect:c(re,\"1:1\"),tag:c(g,\"div\")},E$),qD=I({name:E$,mixins:[ve],props:rV,computed:{padding:function(){var e=this.aspect,r=1;if(bF.test(e)){var n=e.split(yF).map(function(s){return Ee(s)||1}),i=J2(n,2),a=i[0],o=i[1];r=a/o}else r=Ee(e)||1;return\"\".concat(100/WD(r),\"%\")}},render:function(e){var r=e(\"div\",{staticClass:\"\".concat(qh,\"-sizer flex-grow-1\"),style:{paddingBottom:this.padding,height:0}}),n=e(\"div\",{staticClass:\"\".concat(qh,\"-content flex-grow-1 w-100 mw-100\"),style:{marginLeft:\"-100%\"}},this.normalizeSlot());return e(this.tag,{staticClass:\"\".concat(qh,\" d-flex\")},[r,n])}}),nV=ae({components:{BAspect:qD}});function Tt(t){return Nr?new Proxy(t,{get:function(r,n){return n in r?r[n]:void 0}}):t}var XD=\"a\",iV=function(e){return\"%\"+e.charCodeAt(0).toString(16)},Zo=function(e){return encodeURIComponent(ce(e)).replace(mF,iV).replace(vF,\",\")},iw=decodeURIComponent,aV=function(e){if(!yr(e))return\"\";var r=ge(e).map(function(n){var i=e[n];return Et(i)?\"\":nt(i)?Zo(n):He(i)?i.reduce(function(a,o){return nt(o)?a.push(Zo(n)):Et(o)||a.push(Zo(n)+\"=\"+Zo(o)),a},[]).join(\"&\"):Zo(n)+\"=\"+Zo(i)}).filter(function(n){return n.length>0}).join(\"&\");return r?\"?\".concat(r):\"\"},aw=function(e){var r={};return e=ce(e).trim().replace(gF,\"\"),e&&e.split(\"&\").forEach(function(n){var i=n.replace(aF,\" \").split(\"=\"),a=iw(i.shift()),o=i.length>0?iw(i.join(\"=\")):null;Et(r[a])?r[a]=o:He(r[a])?r[a].push(o):r[a]=[r[a],o]}),r},Yu=function(e){return!!(e.href||e.to)},JD=function(e){return!!(e&&!wi(e,\"a\"))},oV=function(e,r){var n=e.to,i=e.disabled,a=e.routerComponentName,o=!!Tt(r).$router,s=!!Tt(r).$nuxt;return!o||o&&(i||!n)?XD:a||(s?\"nuxt-link\":\"router-link\")},sV=function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},r=e.target,n=e.rel;return r===\"_blank\"&&nt(n)?\"noopener\":n||null},ZD=function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},r=e.href,n=e.to,i=arguments.length>1&&arguments[1]!==void 0?arguments[1]:XD,a=arguments.length>2&&arguments[2]!==void 0?arguments[2]:\"#\",o=arguments.length>3&&arguments[3]!==void 0?arguments[3]:\"/\";if(r)return r;if(JD(i))return null;if(Ae(n))return n||o;if(yr(n)&&(n.path||n.query||n.hash)){var s=ce(n.path),l=aV(n.query),u=ce(n.hash);return u=!u||u.charAt(0)===\"#\"?u:\"#\".concat(u),\"\".concat(s).concat(l).concat(u)||o}return a};function ow(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var lV={viewBox:\"0 0 16 16\",width:\"1em\",height:\"1em\",focusable:\"false\",role:\"img\",\"aria-label\":\"icon\"},uV={width:null,height:null,focusable:null,role:null,\"aria-label\":null},Lb={animation:c(g),content:c(g),flipH:c(_,!1),flipV:c(_,!1),fontScale:c(re,1),rotate:c(re,0),scale:c(re,1),shiftH:c(re,0),shiftV:c(re,0),stacked:c(_,!1),title:c(g),variant:c(g)},cV=I({name:qF,functional:!0,props:Lb,render:function(e,r){var n,i=r.data,a=r.props,o=r.children,s=a.animation,l=a.content,u=a.flipH,f=a.flipV,d=a.stacked,p=a.title,h=a.variant,b=Fe(Ee(a.fontScale,1),0)||1,y=Fe(Ee(a.scale,1),0)||1,P=Ee(a.rotate,0),C=Ee(a.shiftH,0),R=Ee(a.shiftV,0),D=u||f||y!==1,B=D||P,A=C||R,V=!Ge(l),N=[B?\"translate(8 8)\":null,D?\"scale(\".concat((u?-1:1)*y,\" \").concat((f?-1:1)*y,\")\"):null,P?\"rotate(\".concat(P,\")\"):null,B?\"translate(-8 -8)\":null].filter(pe),G=e(\"g\",{attrs:{transform:N.join(\" \")||null},domProps:V?{innerHTML:l||\"\"}:{}},o);A&&(G=e(\"g\",{attrs:{transform:\"translate(\".concat(16*C/16,\" \").concat(-16*R/16,\")\")}},[G])),d&&(G=e(\"g\",[G]));var H=p?e(\"title\",p):null,W=[H,G].filter(pe);return e(\"svg\",oe({staticClass:\"b-icon bi\",class:(n={},ow(n,\"text-\".concat(h),h),ow(n,\"b-icon-animation-\".concat(s),s),n),attrs:lV,style:d?{}:{fontSize:b===1?null:\"\".concat(b*100,\"%\")}},i,d?{attrs:uV}:{},{attrs:{xmlns:d?null:\"http://www.w3.org/2000/svg\",fill:\"currentColor\"}}),W)}});function sw(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function lw(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?sw(Object(r),!0).forEach(function(n){fV(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):sw(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function fV(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var dV=Pe(Lb,[\"content\"]),pt=function(e,r){var n=Nb(e),i=\"BIcon\".concat(kD(e)),a=\"bi-\".concat(n),o=n.replace(/-/g,\" \"),s=ya(r||\"\");return I({name:i,functional:!0,props:dV,render:function(u,f){var d=f.data,p=f.props;return u(cV,oe({props:{title:o},attrs:{\"aria-label\":o}},d,{staticClass:a,props:lw(lw({},p),{},{content:s})}))}})},uw=pt(\"Blank\",\"\"),PZ=pt(\"ArrowClockwise\",'<path fill-rule=\"evenodd\" d=\"M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z\"/><path d=\"M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z\"/>'),EZ=pt(\"ArrowRepeat\",'<path d=\"M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41zm-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9z\"/><path fill-rule=\"evenodd\" d=\"M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5.002 5.002 0 0 0 8 3zM3.1 9a5.002 5.002 0 0 0 8.757 2.182.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9H3.1z\"/>'),pV=pt(\"Calendar\",'<path d=\"M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z\"/>'),hV=pt(\"CalendarFill\",'<path d=\"M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V5h16V4H0V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5z\"/>'),cw=pt(\"ChevronBarLeft\",'<path fill-rule=\"evenodd\" d=\"M11.854 3.646a.5.5 0 0 1 0 .708L8.207 8l3.647 3.646a.5.5 0 0 1-.708.708l-4-4a.5.5 0 0 1 0-.708l4-4a.5.5 0 0 1 .708 0zM4.5 1a.5.5 0 0 0-.5.5v13a.5.5 0 0 0 1 0v-13a.5.5 0 0 0-.5-.5z\"/>'),fw=pt(\"ChevronDoubleLeft\",'<path fill-rule=\"evenodd\" d=\"M8.354 1.646a.5.5 0 0 1 0 .708L2.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z\"/><path fill-rule=\"evenodd\" d=\"M12.354 1.646a.5.5 0 0 1 0 .708L6.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z\"/>'),vV=pt(\"ChevronDown\",'<path fill-rule=\"evenodd\" d=\"M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z\"/>'),dw=pt(\"ChevronLeft\",'<path fill-rule=\"evenodd\" d=\"M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z\"/>'),pw=pt(\"ChevronUp\",'<path fill-rule=\"evenodd\" d=\"M7.646 4.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1-.708.708L8 5.707l-5.646 5.647a.5.5 0 0 1-.708-.708l6-6z\"/>'),Wm=pt(\"CircleFill\",'<circle cx=\"8\" cy=\"8\" r=\"8\"/>'),mV=pt(\"Clock\",'<path d=\"M8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71V3.5z\"/><path d=\"M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm7-8A7 7 0 1 1 1 8a7 7 0 0 1 14 0z\"/>'),gV=pt(\"ClockFill\",'<path d=\"M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71V3.5z\"/>'),bV=pt(\"Dash\",'<path d=\"M4 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 4 8z\"/>'),yV=pt(\"Github\",'<path d=\"M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z\"/>'),$Z=pt(\"InfoCircleFill\",'<path d=\"M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm.93-9.412-1 4.705c-.07.34.029.533.304.533.194 0 .487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703 0-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381 2.29-.287zM8 5.5a1 1 0 1 1 0-2 1 1 0 0 1 0 2z\"/>'),OV=pt(\"PersonFill\",'<path d=\"M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z\"/>'),_V=pt(\"Plus\",'<path d=\"M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z\"/>'),CZ=pt(\"Search\",'<path d=\"M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z\"/>'),DZ=pt(\"Speedometer2\",'<path d=\"M8 4a.5.5 0 0 1 .5.5V6a.5.5 0 0 1-1 0V4.5A.5.5 0 0 1 8 4zM3.732 5.732a.5.5 0 0 1 .707 0l.915.914a.5.5 0 1 1-.708.708l-.914-.915a.5.5 0 0 1 0-.707zM2 10a.5.5 0 0 1 .5-.5h1.586a.5.5 0 0 1 0 1H2.5A.5.5 0 0 1 2 10zm9.5 0a.5.5 0 0 1 .5-.5h1.5a.5.5 0 0 1 0 1H12a.5.5 0 0 1-.5-.5zm.754-4.246a.389.389 0 0 0-.527-.02L7.547 9.31a.91.91 0 1 0 1.302 1.258l3.434-4.297a.389.389 0 0 0-.029-.518z\"/><path fill-rule=\"evenodd\" d=\"M0 10a8 8 0 1 1 15.547 2.661c-.442 1.253-1.845 1.602-2.932 1.25C11.309 13.488 9.475 13 8 13c-1.474 0-3.31.488-4.615.911-1.087.352-2.49.003-2.932-1.25A7.988 7.988 0 0 1 0 10zm8-7a7 7 0 0 0-6.603 9.329c.203.575.923.876 1.68.63C4.397 12.533 6.358 12 8 12s3.604.532 4.923.96c.757.245 1.477-.056 1.68-.631A7 7 0 0 0 8 3z\"/>'),wV=pt(\"Star\",'<path d=\"M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256 4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73 3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356-.83 4.73zm4.905-2.767-3.686 1.894.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957-3.686-1.894a.503.503 0 0 0-.461 0z\"/>'),TV=pt(\"StarFill\",'<path d=\"M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z\"/>'),SV=pt(\"StarHalf\",'<path d=\"M5.354 5.119 7.538.792A.516.516 0 0 1 8 .5c.183 0 .366.097.465.292l2.184 4.327 4.898.696A.537.537 0 0 1 16 6.32a.548.548 0 0 1-.17.445l-3.523 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256a.52.52 0 0 1-.146.05c-.342.06-.668-.254-.6-.642l.83-4.73L.173 6.765a.55.55 0 0 1-.172-.403.58.58 0 0 1 .085-.302.513.513 0 0 1 .37-.245l4.898-.696zM8 12.027a.5.5 0 0 1 .232.056l3.686 1.894-.694-3.957a.565.565 0 0 1 .162-.505l2.907-2.77-4.052-.576a.525.525 0 0 1-.393-.288L8.001 2.223 8 2.226v9.8z\"/>'),AZ=pt(\"Trash\",'<path d=\"M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z\"/><path fill-rule=\"evenodd\" d=\"M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z\"/>'),QD=pt(\"X\",'<path d=\"M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z\"/>');function hw(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function vw(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?hw(Object(r),!0).forEach(function(n){PV(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):hw(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function PV(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var EV=function t(e,r){if(!e)return ye.component(r);var n=(e.$options||{}).components,i=n&&n[r];return i||t(e.$parent,r)},eA=Pe(Lb,[\"content\"]),$V=z(ie(vw(vw({},eA),{},{icon:c(g)})),$C),sd=I({name:$C,functional:!0,props:$V,render:function(e,r){var n=r.data,i=r.props,a=r.parent,o=kD(ya(i.icon||\"\")).replace(_F,\"\");return e(o&&EV(a,\"BIcon\".concat(o))||uw,oe(n,{props:at(eA,i)}))}}),CV=8,tA=46,Rr=40,Aa=35,Ji=13,Fb=27,Ra=36,Xn=37,ld=34,ud=33,Yi=39,Ti=32,Zr=38,DV=function(e,r){if(e.length!==r.length)return!1;for(var n=!0,i=0;n&&i<e.length;i++)n=je(e[i],r[i]);return n},je=function t(e,r){if(e===r)return!0;var n=xs(e),i=xs(r);if(n||i)return n&&i?e.getTime()===r.getTime():!1;if(n=He(e),i=He(r),n||i)return n&&i?DV(e,r):!1;if(n=St(e),i=St(r),n||i){if(!n||!i)return!1;var a=ge(e).length,o=ge(r).length;if(a!==o)return!1;for(var s in e){var l=$o(e,s),u=$o(r,s);if(l&&!u||!l&&u||!t(e[s],r[s]))return!1}}return String(e)===String(r)};function mw(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var gw=function(e){return!e||ge(e).length===0},AV=function(e){return{handler:function(n,i){if(!je(n,i)){if(gw(n)||gw(i)){this[e]=Nn(n);return}for(var a in i)$o(n,a)||this.$delete(this.$data[e],a);for(var o in n)this.$set(this.$data[e],o,n[o])}}}},rA=function(e,r){return I({data:function(){return mw({},r,Nn(this[e]))},watch:mw({},e,AV(r))})};function bw(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function RV(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?bw(Object(r),!0).forEach(function(n){xV(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):bw(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function xV(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var MV=rA(\"$attrs\",\"bvAttrs\"),NV=I({computed:{bvAttrs:function(){var e=RV({},this.$attrs);return Object.keys(e).forEach(function(r){e[r]===void 0&&delete e[r]}),e}}}),Vt=Nr?NV:MV,Oi=function(e){return e.$root.$options.bvEventRoot||e.$root},on=\"$_rootListeners\",Qn=I({computed:{bvEventRoot:function(){return Oi(this)}},created:function(){this[on]={}},beforeDestroy:function(){var e=this;ge(this[on]||{}).forEach(function(r){e[on][r].forEach(function(n){e.listenOffRoot(r,n)})}),this[on]=null},methods:{registerRootListener:function(e,r){this[on]&&(this[on][e]=this[on][e]||[],he(this[on][e],r)||this[on][e].push(r))},unregisterRootListener:function(e,r){this[on]&&this[on][e]&&(this[on][e]=this[on][e].filter(function(n){return n!==r}))},listenOnRoot:function(e,r){this.bvEventRoot&&(this.bvEventRoot.$on(e,r),this.registerRootListener(e,r))},listenOnRootOnce:function(e,r){var n=this;if(this.bvEventRoot){var i=function a(){n.unregisterRootListener(a),r.apply(void 0,arguments)};this.bvEventRoot.$once(e,i),this.registerRootListener(e,i)}},listenOffRoot:function(e,r){this.unregisterRootListener(e,r),this.bvEventRoot&&this.bvEventRoot.$off(e,r)},emitOnRoot:function(e){if(this.bvEventRoot){for(var r,n=arguments.length,i=new Array(n>1?n-1:0),a=1;a<n;a++)i[a-1]=arguments[a];(r=this.bvEventRoot).$emit.apply(r,[e].concat(i))}}}});function yw(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Ow(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?yw(Object(r),!0).forEach(function(n){IV(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):yw(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function IV(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var BV=rA(\"$listeners\",\"bvListeners\"),kV=I({data:function(){return{bvListeners:{}}},created:function(){this.bvListeners=Ow({},this.$listeners)},beforeUpdate:function(){this.bvListeners=Ow({},this.$listeners)}}),Zi=Nr?kV:BV;function LV(t){return HV(t)||VV(t)||jV(t)||FV()}function FV(){throw new TypeError(`Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function jV(t,e){if(!!t){if(typeof t==\"string\")return Km(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);if(r===\"Object\"&&t.constructor&&(r=t.constructor.name),r===\"Map\"||r===\"Set\")return Array.from(t);if(r===\"Arguments\"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return Km(t,e)}}function VV(t){if(typeof Symbol<\"u\"&&t[Symbol.iterator]!=null||t[\"@@iterator\"]!=null)return Array.from(t)}function HV(t){if(Array.isArray(t))return Km(t)}function Km(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}function _w(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Pr(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?_w(Object(r),!0).forEach(function(n){nA(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):_w(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function nA(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var zV=bt(Rb,\"clicked\"),iA={activeClass:c(g),append:c(_,!1),event:c(Or),exact:c(_,!1),exactActiveClass:c(g),exactPath:c(_,!1),exactPathActiveClass:c(g),replace:c(_,!1),routerTag:c(g),to:c(ND)},aA={noPrefetch:c(_,!1),prefetch:c(_,null)},ei=z(ie(Pr(Pr(Pr({},aA),iA),{},{active:c(_,!1),disabled:c(_,!1),href:c(g),rel:c(g,null),routerComponentName:c(g),target:c(g,\"_self\")})),Rb),tn=I({name:Rb,mixins:[Vt,Zi,Qn,ve],inheritAttrs:!1,props:ei,computed:{computedTag:function(){var e=this.to,r=this.disabled,n=this.routerComponentName;return oV({to:e,disabled:r,routerComponentName:n},this)},isRouterLink:function(){return JD(this.computedTag)},computedRel:function(){var e=this.target,r=this.rel;return sV({target:e,rel:r})},computedHref:function(){var e=this.to,r=this.href;return ZD({to:e,href:r},this.computedTag)},computedProps:function(){var e=this.event,r=this.prefetch,n=this.routerTag;return this.isRouterLink?Pr(Pr(Pr(Pr({},at(Pe(Pr(Pr({},iA),this.computedTag===\"nuxt-link\"?aA:{}),[\"event\",\"prefetch\",\"routerTag\"]),this)),e?{event:e}:{}),Mn(r)?{prefetch:r}:{}),n?{tag:n}:{}):{}},computedAttrs:function(){var e=this.bvAttrs,r=this.computedHref,n=this.computedRel,i=this.disabled,a=this.target,o=this.routerTag,s=this.isRouterLink;return Pr(Pr(Pr(Pr({},e),r?{href:r}:{}),s&&o&&!wi(o,\"a\")?{}:{rel:n,target:a}),{},{tabindex:i?\"-1\":Et(e.tabindex)?null:e.tabindex,\"aria-disabled\":i?\"true\":null})},computedListeners:function(){return Pr(Pr({},this.bvListeners),{},{click:this.onClick})}},methods:{onClick:function(e){var r=arguments,n=Po(e),i=this.isRouterLink,a=this.bvListeners.click;if(n&&this.disabled)_e(e,{immediatePropagation:!0});else{if(i){var o;(o=e.currentTarget.__vue__)===null||o===void 0||o.$emit(Ln,e)}Me(a).filter(function(s){return se(s)}).forEach(function(s){s.apply(void 0,LV(r))}),this.emitOnRoot(zV,e),this.emitOnRoot(\"clicked::link\",e)}n&&!i&&this.computedHref===\"#\"&&_e(e,{propagation:!1})},focus:function(){we(this.$el)},blur:function(){rn(this.$el)}},render:function(e){var r=this.active,n=this.disabled;return e(this.computedTag,nA({class:{active:r,disabled:n},attrs:this.computedAttrs,props:this.computedProps},this.isRouterLink?\"nativeOn\":\"on\",this.computedListeners),this.normalizeSlot())}});function ww(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function cd(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?ww(Object(r),!0).forEach(function(n){Qa(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):ww(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Qa(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var cp=Pe(ei,[\"event\",\"routerTag\"]);delete cp.href.default;delete cp.to.default;var oA=z(ie(cd(cd({},cp),{},{block:c(_,!1),disabled:c(_,!1),pill:c(_,!1),pressed:c(_,null),size:c(g),squared:c(_,!1),tag:c(g,\"button\"),type:c(g,\"button\"),variant:c(g,\"secondary\")})),M$),Tw=function(e){e.type===\"focusin\"?$r(e.target,\"focus\"):e.type===\"focusout\"&&hr(e.target,\"focus\")},qu=function(e){return Yu(e)||wi(e.tag,\"a\")},sA=function(e){return Mn(e.pressed)},lA=function(e){return!(qu(e)||e.tag&&!wi(e.tag,\"button\"))},uA=function(e){return!qu(e)&&!lA(e)},UV=function(e){var r;return[\"btn-\".concat(e.variant||\"secondary\"),(r={},Qa(r,\"btn-\".concat(e.size),e.size),Qa(r,\"btn-block\",e.block),Qa(r,\"rounded-pill\",e.pill),Qa(r,\"rounded-0\",e.squared&&!e.pill),Qa(r,\"disabled\",e.disabled),Qa(r,\"active\",e.pressed),r)]},GV=function(e){return qu(e)?at(cp,e):{}},WV=function(e,r){var n=lA(e),i=qu(e),a=sA(e),o=uA(e),s=i&&e.href===\"#\",l=r.attrs&&r.attrs.role?r.attrs.role:null,u=r.attrs?r.attrs.tabindex:null;return(o||s)&&(u=\"0\"),{type:n&&!i?e.type:null,disabled:n?e.disabled:null,role:o||s?\"button\":l,\"aria-disabled\":o?String(e.disabled):null,\"aria-pressed\":a?String(e.pressed):null,autocomplete:a?\"off\":null,tabindex:e.disabled&&!n?\"-1\":u}},Qr=I({name:M$,functional:!0,props:oA,render:function(e,r){var n=r.props,i=r.data,a=r.listeners,o=r.children,s=sA(n),l=qu(n),u=uA(n),f=l&&n.href===\"#\",d={keydown:function(b){if(!(n.disabled||!(u||f))){var y=b.keyCode;if(y===Ti||y===Ji&&u){var P=b.currentTarget||b.target;_e(b,{propagation:!1}),P.click()}}},click:function(b){n.disabled&&Po(b)?_e(b):s&&a&&a[\"update:pressed\"]&&Me(a[\"update:pressed\"]).forEach(function(y){se(y)&&y(!n.pressed)})}};s&&(d.focusin=Tw,d.focusout=Tw);var p={staticClass:\"btn\",class:UV(n),props:GV(n),attrs:WV(n,i),on:d};return e(l?tn:n.tag,oe(cd(cd({},i),{},{props:void 0}),p),o)}});function Sw(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function fd(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?Sw(Object(r),!0).forEach(function(n){eo(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):Sw(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function eo(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Pw=\"b-avatar\",Xh=[\"sm\",null,\"lg\"],cA=.4,KV=cA*.7,fA=function(e){return e=Ae(e)&&cu(e)?Ee(e,0):e,Kn(e)?\"\".concat(e,\"px\"):e||null},dA=Pe(ei,[\"active\",\"event\",\"routerTag\"]),YV=z(ie(fd(fd({},dA),{},{alt:c(g,\"avatar\"),ariaLabel:c(g),badge:c(_r,!1),badgeLeft:c(_,!1),badgeOffset:c(g),badgeTop:c(_,!1),badgeVariant:c(g,\"primary\"),button:c(_,!1),buttonType:c(g,\"button\"),icon:c(g),rounded:c(_r,!1),size:c(re),square:c(_,!1),src:c(g),text:c(g),variant:c(g,\"secondary\")})),$$),qV=I({name:$$,mixins:[ve],inject:{getBvAvatarGroup:{default:function(){return function(){return null}}}},props:YV,data:function(){return{localSrc:this.src||null}},computed:{bvAvatarGroup:function(){return this.getBvAvatarGroup()},computedSize:function(){var e=this.bvAvatarGroup;return fA(e?e.size:this.size)},computedVariant:function(){var e=this.bvAvatarGroup;return e&&e.variant?e.variant:this.variant},computedRounded:function(){var e=this.bvAvatarGroup,r=e&&e.square?!0:this.square,n=e&&e.rounded?e.rounded:this.rounded;return r?\"0\":n===\"\"?!0:n||\"circle\"},fontStyle:function(){var e=this.computedSize,r=Xh.indexOf(e)===-1?\"calc(\".concat(e,\" * \").concat(cA,\")\"):null;return r?{fontSize:r}:{}},marginStyle:function(){var e=this.computedSize,r=this.bvAvatarGroup,n=r?r.overlapScale:0,i=e&&n?\"calc(\".concat(e,\" * -\").concat(n,\")\"):null;return i?{marginLeft:i,marginRight:i}:{}},badgeStyle:function(){var e=this.computedSize,r=this.badgeTop,n=this.badgeLeft,i=this.badgeOffset,a=i||\"0px\";return{fontSize:Xh.indexOf(e)===-1?\"calc(\".concat(e,\" * \").concat(KV,\" )\"):null,top:r?a:null,bottom:r?null:a,left:n?a:null,right:n?null:a}}},watch:{src:function(e,r){e!==r&&(this.localSrc=e||null)}},methods:{onImgError:function(e){this.localSrc=null,this.$emit(mj,e)},onClick:function(e){this.$emit(Ln,e)}},render:function(e){var r,n=this.computedVariant,i=this.disabled,a=this.computedRounded,o=this.icon,s=this.localSrc,l=this.text,u=this.fontStyle,f=this.marginStyle,d=this.computedSize,p=this.button,h=this.buttonType,b=this.badge,y=this.badgeVariant,P=this.badgeStyle,C=!p&&Yu(this),R=p?Qr:C?tn:\"span\",D=this.alt,B=this.ariaLabel||null,A=null;this.hasNormalizedSlot()?A=e(\"span\",{staticClass:\"b-avatar-custom\"},[this.normalizeSlot()]):s?(A=e(\"img\",{style:n?{}:{width:\"100%\",height:\"100%\"},attrs:{src:s,alt:D},on:{error:this.onImgError}}),A=e(\"span\",{staticClass:\"b-avatar-img\"},[A])):o?A=e(sd,{props:{icon:o},attrs:{\"aria-hidden\":\"true\",alt:D}}):l?A=e(\"span\",{staticClass:\"b-avatar-text\",style:u},[e(\"span\",l)]):A=e(OV,{attrs:{\"aria-hidden\":\"true\",alt:D}});var V=e(),N=this.hasNormalizedSlot(j_);if(b||b===\"\"||N){var G=b===!0?\"\":b;V=e(\"span\",{staticClass:\"b-avatar-badge\",class:eo({},\"badge-\".concat(y),y),style:P},[N?this.normalizeSlot(j_):G])}var H={staticClass:Pw,class:(r={},eo(r,\"\".concat(Pw,\"-\").concat(d),d&&Xh.indexOf(d)!==-1),eo(r,\"badge-\".concat(n),!p&&n),eo(r,\"rounded\",a===!0),eo(r,\"rounded-\".concat(a),a&&a!==!0),eo(r,\"disabled\",i),r),style:fd(fd({},f),{},{width:d,height:d}),attrs:{\"aria-label\":B||null},props:p?{variant:n,disabled:i,type:h}:C?at(dA,this):{},on:p||C?{click:this.onClick}:{}};return e(R,H,[A,V])}}),XV=z({overlap:c(re,.3),rounded:c(_r,!1),size:c(g),square:c(_,!1),tag:c(g,\"div\"),variant:c(g)},C$),JV=I({name:C$,mixins:[ve],provide:function(){var e=this;return{getBvAvatarGroup:function(){return e}}},props:XV,computed:{computedSize:function(){return fA(this.size)},overlapScale:function(){return Fi(Fe(Ee(this.overlap,0),0),1)/2},paddingStyle:function(){var e=this.computedSize;return e=e?\"calc(\".concat(e,\" * \").concat(this.overlapScale,\")\"):null,e?{paddingLeft:e,paddingRight:e}:{}}},render:function(e){var r=e(\"div\",{staticClass:\"b-avatar-group-inner\",style:this.paddingStyle},this.normalizeSlot());return e(this.tag,{staticClass:\"b-avatar-group\",attrs:{role:\"group\"}},[r])}}),ZV=ae({components:{BAvatar:qV,BAvatarGroup:JV}});function Ew(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function $w(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?Ew(Object(r),!0).forEach(function(n){QV(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):Ew(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function QV(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var fp=Pe(ei,[\"event\",\"routerTag\"]);delete fp.href.default;delete fp.to.default;var eH=z(ie($w($w({},fp),{},{pill:c(_,!1),tag:c(g,\"span\"),variant:c(g,\"secondary\")})),D$),jb=I({name:D$,functional:!0,props:eH,render:function(e,r){var n=r.props,i=r.data,a=r.children,o=n.active,s=n.disabled,l=Yu(n),u=l?tn:n.tag,f=n.variant||\"secondary\";return e(u,oe(i,{staticClass:\"badge\",class:[\"badge-\".concat(f),{\"badge-pill\":n.pill,active:o,disabled:s}],props:l?at(fp,n):{}}),a)}}),tH=ae({components:{BBadge:jb}}),Cw=function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:\"\";return String(e).replace(tF,\"\")},dt=function(e,r){return e?{innerHTML:e}:r?{textContent:r}:{}};function Dw(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Aw(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?Dw(Object(r),!0).forEach(function(n){rH(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):Dw(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function rH(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Ym=z(ie(Aw(Aw({},Pe(ei,[\"event\",\"routerTag\"])),{},{ariaCurrent:c(g,\"location\"),html:c(g),text:c(g)})),x$),pA=I({name:x$,functional:!0,props:Ym,render:function(e,r){var n=r.props,i=r.data,a=r.children,o=n.active,s=o?\"span\":tn,l={attrs:{\"aria-current\":o?n.ariaCurrent:null},props:at(Ym,n)};return a||(l.domProps=dt(n.html,n.text)),e(s,oe(i,l),a)}}),nH=z(Ym,R$),hA=I({name:R$,functional:!0,props:nH,render:function(e,r){var n=r.props,i=r.data,a=r.children;return e(\"li\",oe(i,{staticClass:\"breadcrumb-item\",class:{active:n.active}}),[e(pA,{props:n},a)])}});function Rw(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function xw(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?Rw(Object(r),!0).forEach(function(n){iH(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):Rw(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function iH(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var aH=z({items:c(Ar)},A$),oH=I({name:A$,functional:!0,props:aH,render:function(e,r){var n=r.props,i=r.data,a=r.children,o=n.items,s=a;if(He(o)){var l=!1;s=o.map(function(u,f){St(u)||(u={text:ce(u)});var d=u,p=d.active;return p&&(l=!0),!p&&!l&&(p=f+1===o.length),e(hA,{props:xw(xw({},u),{},{active:p})})})}return e(\"ol\",oe(i,{staticClass:\"breadcrumb\"}),s)}}),sH=ae({components:{BBreadcrumb:oH,BBreadcrumbItem:hA,BBreadcrumbLink:pA}}),lH=ae({components:{BButton:Qr,BBtn:Qr,BButtonClose:xo,BBtnClose:xo}});function Mw(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Nw(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?Mw(Object(r),!0).forEach(function(n){vA(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):Mw(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function vA(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var uH=z(ie(Nw(Nw({},Zn(oA,[\"size\"])),{},{ariaRole:c(g,\"group\"),size:c(g),tag:c(g,\"div\"),vertical:c(_,!1)})),I$),Iw=I({name:I$,functional:!0,props:uH,render:function(e,r){var n=r.props,i=r.data,a=r.children;return e(n.tag,oe(i,{class:vA({\"btn-group\":!n.vertical,\"btn-group-vertical\":n.vertical},\"btn-group-\".concat(n.size),n.size),attrs:{role:n.ariaRole}}),a)}}),cH=ae({components:{BButtonGroup:Iw,BBtnGroup:Iw}}),fH=[\".btn:not(.disabled):not([disabled]):not(.dropdown-item)\",\".form-control:not(.disabled):not([disabled])\",\"select:not(.disabled):not([disabled])\",'input[type=\"checkbox\"]:not(.disabled)','input[type=\"radio\"]:not(.disabled)'].join(\",\"),dH=z({justify:c(_,!1),keyNav:c(_,!1)},B$),Bw=I({name:B$,mixins:[ve],props:dH,mounted:function(){this.keyNav&&this.getItems()},methods:{getItems:function(){var e=yn(fH,this.$el);return e.forEach(function(r){r.tabIndex=-1}),e.filter(function(r){return Yn(r)})},focusFirst:function(){var e=this.getItems();we(e[0])},focusPrev:function(e){var r=this.getItems(),n=r.indexOf(e.target);n>-1&&(r=r.slice(0,n).reverse(),we(r[0]))},focusNext:function(e){var r=this.getItems(),n=r.indexOf(e.target);n>-1&&(r=r.slice(n+1),we(r[0]))},focusLast:function(){var e=this.getItems().reverse();we(e[0])},onFocusin:function(e){var r=this.$el;e.target===r&&!Rt(r,e.relatedTarget)&&(_e(e),this.focusFirst(e))},onKeydown:function(e){var r=e.keyCode,n=e.shiftKey;r===Zr||r===Xn?(_e(e),n?this.focusFirst(e):this.focusPrev(e)):(r===Rr||r===Yi)&&(_e(e),n?this.focusLast(e):this.focusNext(e))}},render:function(e){var r=this.keyNav;return e(\"div\",{staticClass:\"btn-toolbar\",class:{\"justify-content-between\":this.justify},attrs:{role:\"toolbar\",tabindex:r?\"0\":null},on:r?{focusin:this.onFocusin,keydown:this.onKeydown}:{}},[this.normalizeSlot()])}}),pH=ae({components:{BButtonToolbar:Bw,BBtnToolbar:Bw}}),aa=\"gregory\",pu=\"long\",hH=\"narrow\",qm=\"short\",kw=\"2-digit\",dd=\"numeric\";function vH(t,e){return yH(t)||bH(t,e)||gH(t,e)||mH()}function mH(){throw new TypeError(`Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function gH(t,e){if(!!t){if(typeof t==\"string\")return Lw(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);if(r===\"Object\"&&t.constructor&&(r=t.constructor.name),r===\"Map\"||r===\"Set\")return Array.from(t);if(r===\"Arguments\"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return Lw(t,e)}}function Lw(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}function bH(t,e){var r=t==null?null:typeof Symbol<\"u\"&&t[Symbol.iterator]||t[\"@@iterator\"];if(r!=null){var n=[],i=!0,a=!1,o,s;try{for(r=r.call(t);!(i=(o=r.next()).done)&&(n.push(o.value),!(e&&n.length===e));i=!0);}catch(l){a=!0,s=l}finally{try{!i&&r.return!=null&&r.return()}finally{if(a)throw s}}return n}}function yH(t){if(Array.isArray(t))return t}function pf(t,e,r){return OH()?pf=Reflect.construct:pf=function(i,a,o){var s=[null];s.push.apply(s,a);var l=Function.bind.apply(i,s),u=new l;return o&&Xm(u,o.prototype),u},pf.apply(null,arguments)}function OH(){if(typeof Reflect>\"u\"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy==\"function\")return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch{return!1}}function Xm(t,e){return Xm=Object.setPrototypeOf||function(n,i){return n.__proto__=i,n},Xm(t,e)}var Jt=function(){for(var e=arguments.length,r=new Array(e),n=0;n<e;n++)r[n]=arguments[n];return pf(Date,r)},At=function(e){if(Ae(e)&&dF.test(e.trim())){var r=e.split(pF).map(function(s){return ee(s,1)}),n=vH(r,3),i=n[0],a=n[1],o=n[2];return Jt(i,a-1,o)}else if(xs(e))return Jt(e.getFullYear(),e.getMonth(),e.getDate());return null},rt=function(e){if(e=At(e),!e)return null;var r=e.getFullYear(),n=\"0\".concat(e.getMonth()+1).slice(-2),i=\"0\".concat(e.getDate()).slice(-2);return\"\".concat(r,\"-\").concat(n,\"-\").concat(i)},_H=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:aa;e=Me(e).filter(pe);var n=new Intl.DateTimeFormat(e,{calendar:r});return n.resolvedOptions().locale},Xl=function(e,r){var n=new Intl.DateTimeFormat(e,r);return n.format},Cc=function(e,r){return rt(e)===rt(r)},Jh=function(e){return e=Jt(e),e.setDate(1),e},Zh=function(e){return e=Jt(e),e.setMonth(e.getMonth()+1),e.setDate(0),e},dp=function(e,r){e=Jt(e);var n=e.getMonth();return e.setFullYear(e.getFullYear()+r),e.getMonth()!==n&&e.setDate(0),e},Qh=function(e){e=Jt(e);var r=e.getMonth();return e.setMonth(r-1),e.getMonth()===r&&e.setDate(0),e},ev=function(e){e=Jt(e);var r=e.getMonth();return e.setMonth(r+1),e.getMonth()===(r+2)%12&&e.setDate(0),e},tv=function(e){return dp(e,-1)},rv=function(e){return dp(e,1)},nv=function(e){return dp(e,-10)},iv=function(e){return dp(e,10)},pd=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:null,n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:null;return e=At(e),r=At(r)||e,n=At(n)||e,e?e<r?r:e>n?n:e:null},Fw=[\"ar\",\"az\",\"ckb\",\"fa\",\"he\",\"ks\",\"lrc\",\"mzn\",\"ps\",\"sd\",\"te\",\"ug\",\"ur\",\"yi\"].map(function(t){return t.toLowerCase()}),pp=function(e){var r=ce(e).toLowerCase().replace(wF,\"\").split(\"-\"),n=r.slice(0,2).join(\"-\"),i=r[0];return he(Fw,n)||he(Fw,i)},Ke={id:c(g)},Ze=I({props:Ke,data:function(){return{localId_:null}},computed:{safeId:function(){var e=this.id||this.localId_,r=function(i){return e?(i=String(i||\"\").replace(/\\s+/g,\"_\"),i?e+\"_\"+i:e):null};return r}},mounted:function(){var e=this;this.$nextTick(function(){e.localId_=\"__BVID__\".concat(e[ji])})}}),Qo;function jw(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function ui(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?jw(Object(r),!0).forEach(function(n){Cn(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):jw(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Cn(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var hp=Nt(\"value\",{type:ho}),wH=hp.mixin,TH=hp.props,av=hp.prop,SH=hp.event,mA=z(ie(ui(ui(ui({},Ke),TH),{},{ariaControls:c(g),block:c(_,!1),dateDisabledFn:c(xr),dateFormatOptions:c(Mt,{year:dd,month:pu,day:dd,weekday:pu}),dateInfoFn:c(xr),direction:c(g),disabled:c(_,!1),headerTag:c(g,\"header\"),hidden:c(_,!1),hideHeader:c(_,!1),initialDate:c(ho),labelCalendar:c(g,\"Calendar\"),labelCurrentMonth:c(g,\"Current month\"),labelHelp:c(g,\"Use cursor keys to navigate calendar dates\"),labelNav:c(g,\"Calendar navigation\"),labelNextDecade:c(g,\"Next decade\"),labelNextMonth:c(g,\"Next month\"),labelNextYear:c(g,\"Next year\"),labelNoDateSelected:c(g,\"No date selected\"),labelPrevDecade:c(g,\"Previous decade\"),labelPrevMonth:c(g,\"Previous month\"),labelPrevYear:c(g,\"Previous year\"),labelSelected:c(g,\"Selected date\"),labelToday:c(g,\"Today\"),locale:c(Or),max:c(ho),min:c(ho),navButtonVariant:c(g,\"secondary\"),noHighlightToday:c(_,!1),noKeyNav:c(_,!1),readonly:c(_,!1),roleDescription:c(g),selectedVariant:c(g,\"primary\"),showDecadeNav:c(_,!1),startWeekday:c(re,0),todayVariant:c(g),valueAsDate:c(_,!1),weekdayHeaderFormat:c(g,qm,function(t){return he([pu,qm,hH],t)}),width:c(g,\"270px\")})),k$),gA=I({name:k$,mixins:[Vt,Ze,wH,ve],props:mA,data:function(){var e=rt(this[av])||\"\";return{selectedYMD:e,activeYMD:e||rt(pd(this.initialDate||this.getToday()),this.min,this.max),gridHasFocus:!1,isLive:!1}},computed:{valueId:function(){return this.safeId()},widgetId:function(){return this.safeId(\"_calendar-wrapper_\")},navId:function(){return this.safeId(\"_calendar-nav_\")},gridId:function(){return this.safeId(\"_calendar-grid_\")},gridCaptionId:function(){return this.safeId(\"_calendar-grid-caption_\")},gridHelpId:function(){return this.safeId(\"_calendar-grid-help_\")},activeId:function(){return this.activeYMD?this.safeId(\"_cell-\".concat(this.activeYMD,\"_\")):null},selectedDate:function(){return At(this.selectedYMD)},activeDate:function(){return At(this.activeYMD)},computedMin:function(){return At(this.min)},computedMax:function(){return At(this.max)},computedWeekStarts:function(){return Fe(ee(this.startWeekday,0),0)%7},computedLocale:function(){return _H(Me(this.locale).filter(pe),aa)},computedDateDisabledFn:function(){var e=this.dateDisabledFn;return yi(e)?e:function(){return!1}},computedDateInfoFn:function(){var e=this.dateInfoFn;return yi(e)?e:function(){return{}}},calendarLocale:function(){var e=new Intl.DateTimeFormat(this.computedLocale,{calendar:aa}),r=e.resolvedOptions().calendar,n=e.resolvedOptions().locale;return r!==aa&&(n=n.replace(/-u-.+$/i,\"\").concat(\"-u-ca-gregory\")),n},calendarYear:function(){return this.activeDate.getFullYear()},calendarMonth:function(){return this.activeDate.getMonth()},calendarFirstDay:function(){return Jt(this.calendarYear,this.calendarMonth,1,12)},calendarDaysInMonth:function(){var e=Jt(this.calendarFirstDay);return e.setMonth(e.getMonth()+1,0),e.getDate()},computedVariant:function(){return\"btn-\".concat(this.selectedVariant||\"primary\")},computedTodayVariant:function(){return\"btn-outline-\".concat(this.todayVariant||this.selectedVariant||\"primary\")},computedNavButtonVariant:function(){return\"btn-outline-\".concat(this.navButtonVariant||\"primary\")},isRTL:function(){var e=ce(this.direction).toLowerCase();return e===\"rtl\"?!0:e===\"ltr\"?!1:pp(this.computedLocale)},context:function(){var e=this.selectedYMD,r=this.activeYMD,n=At(e),i=At(r);return{selectedYMD:e,selectedDate:n,selectedFormatted:n?this.formatDateString(n):this.labelNoDateSelected,activeYMD:r,activeDate:i,activeFormatted:i?this.formatDateString(i):\"\",disabled:this.dateDisabled(i),locale:this.computedLocale,calendarLocale:this.calendarLocale,rtl:this.isRTL}},dateOutOfRange:function(){var e=this.computedMin,r=this.computedMax;return function(n){return n=At(n),e&&n<e||r&&n>r}},dateDisabled:function(){var e=this,r=this.dateOutOfRange;return function(n){n=At(n);var i=rt(n);return!!(r(n)||e.computedDateDisabledFn(i,n))}},formatDateString:function(){return Xl(this.calendarLocale,ui(ui({year:dd,month:kw,day:kw},this.dateFormatOptions),{},{hour:void 0,minute:void 0,second:void 0,calendar:aa}))},formatYearMonth:function(){return Xl(this.calendarLocale,{year:dd,month:pu,calendar:aa})},formatWeekdayName:function(){return Xl(this.calendarLocale,{weekday:pu,calendar:aa})},formatWeekdayNameShort:function(){return Xl(this.calendarLocale,{weekday:this.weekdayHeaderFormat||qm,calendar:aa})},formatDay:function(){var e=new Intl.NumberFormat([this.computedLocale],{style:\"decimal\",minimumIntegerDigits:1,minimumFractionDigits:0,maximumFractionDigits:0,notation:\"standard\"});return function(r){return e.format(r.getDate())}},prevDecadeDisabled:function(){var e=this.computedMin;return this.disabled||e&&Zh(nv(this.activeDate))<e},prevYearDisabled:function(){var e=this.computedMin;return this.disabled||e&&Zh(tv(this.activeDate))<e},prevMonthDisabled:function(){var e=this.computedMin;return this.disabled||e&&Zh(Qh(this.activeDate))<e},thisMonthDisabled:function(){return this.disabled},nextMonthDisabled:function(){var e=this.computedMax;return this.disabled||e&&Jh(ev(this.activeDate))>e},nextYearDisabled:function(){var e=this.computedMax;return this.disabled||e&&Jh(rv(this.activeDate))>e},nextDecadeDisabled:function(){var e=this.computedMax;return this.disabled||e&&Jh(iv(this.activeDate))>e},calendar:function(){for(var e=[],r=this.calendarFirstDay,n=r.getFullYear(),i=r.getMonth(),a=this.calendarDaysInMonth,o=r.getDay(),s=(this.computedWeekStarts>o?7:0)-this.computedWeekStarts,l=0-s-o,u=0;u<6&&l<a;u++){e[u]=[];for(var f=0;f<7;f++){l++;var d=Jt(n,i,l),p=d.getMonth(),h=rt(d),b=this.dateDisabled(d),y=this.computedDateInfoFn(h,At(h));y=Ae(y)||He(y)?{class:y}:yr(y)?ui({class:\"\"},y):{class:\"\"},e[u].push({ymd:h,day:this.formatDay(d),label:this.formatDateString(d),isThisMonth:p===i,isDisabled:b,info:y})}}return e},calendarHeadings:function(){var e=this;return this.calendar[0].map(function(r){return{text:e.formatWeekdayNameShort(At(r.ymd)),label:e.formatWeekdayName(At(r.ymd))}})}},watch:(Qo={},Cn(Qo,av,function(t,e){var r=rt(t)||\"\",n=rt(e)||\"\";Cc(r,n)||(this.activeYMD=r||this.activeYMD,this.selectedYMD=r)}),Cn(Qo,\"selectedYMD\",function(e,r){e!==r&&this.$emit(SH,this.valueAsDate?At(e)||null:e||\"\")}),Cn(Qo,\"context\",function(e,r){je(e,r)||this.$emit(Ms,e)}),Cn(Qo,\"hidden\",function(e){this.activeYMD=this.selectedYMD||rt(this[av]||this.constrainDate(this.initialDate||this.getToday())),this.setLive(!e)}),Qo),created:function(){var e=this;this.$nextTick(function(){e.$emit(Ms,e.context)})},mounted:function(){this.setLive(!0)},activated:function(){this.setLive(!0)},deactivated:function(){this.setLive(!1)},beforeDestroy:function(){this.setLive(!1)},methods:{focus:function(){this.disabled||we(this.$refs.grid)},blur:function(){this.disabled||rn(this.$refs.grid)},setLive:function(e){var r=this;e?this.$nextTick(function(){We(function(){r.isLive=!0})}):this.isLive=!1},getToday:function(){return At(Jt())},constrainDate:function(e){return pd(e,this.computedMin,this.computedMax)},emitSelected:function(e){var r=this;this.$nextTick(function(){r.$emit(CD,rt(e)||\"\",At(e)||null)})},setGridFocusFlag:function(e){this.gridHasFocus=!this.disabled&&e.type===\"focus\"},onKeydownWrapper:function(e){if(!this.noKeyNav){var r=e.altKey,n=e.ctrlKey,i=e.keyCode;if(!!he([ud,ld,Aa,Ra,Xn,Zr,Yi,Rr],i)){_e(e);var a=Jt(this.activeDate),o=Jt(this.activeDate),s=a.getDate(),l=this.constrainDate(this.getToday()),u=this.isRTL;i===ud?(a=(r?n?nv:tv:Qh)(a),o=Jt(a),o.setDate(1)):i===ld?(a=(r?n?iv:rv:ev)(a),o=Jt(a),o.setMonth(o.getMonth()+1),o.setDate(0)):i===Xn?(a.setDate(s+(u?1:-1)),a=this.constrainDate(a),o=a):i===Yi?(a.setDate(s+(u?-1:1)),a=this.constrainDate(a),o=a):i===Zr?(a.setDate(s-7),a=this.constrainDate(a),o=a):i===Rr?(a.setDate(s+7),a=this.constrainDate(a),o=a):i===Ra?(a=l,o=a):i===Aa&&(a=At(this.selectedDate)||l,o=a),!this.dateOutOfRange(o)&&!Cc(a,this.activeDate)&&(this.activeYMD=rt(a)),this.focus()}}},onKeydownGrid:function(e){var r=e.keyCode,n=this.activeDate;(r===Ji||r===Ti)&&(_e(e),!this.disabled&&!this.readonly&&!this.dateDisabled(n)&&(this.selectedYMD=rt(n),this.emitSelected(n)),this.focus())},onClickDay:function(e){var r=this.selectedDate,n=this.activeDate,i=At(e.ymd);!this.disabled&&!e.isDisabled&&!this.dateDisabled(i)&&(this.readonly||(this.selectedYMD=rt(Cc(i,r)?r:i),this.emitSelected(i)),this.activeYMD=rt(Cc(i,n)?n:Jt(i)),this.focus())},gotoPrevDecade:function(){this.activeYMD=rt(this.constrainDate(nv(this.activeDate)))},gotoPrevYear:function(){this.activeYMD=rt(this.constrainDate(tv(this.activeDate)))},gotoPrevMonth:function(){this.activeYMD=rt(this.constrainDate(Qh(this.activeDate)))},gotoCurrentMonth:function(){this.activeYMD=rt(this.constrainDate(this.getToday()))},gotoNextMonth:function(){this.activeYMD=rt(this.constrainDate(ev(this.activeDate)))},gotoNextYear:function(){this.activeYMD=rt(this.constrainDate(rv(this.activeDate)))},gotoNextDecade:function(){this.activeYMD=rt(this.constrainDate(iv(this.activeDate)))},onHeaderClick:function(){this.disabled||(this.activeYMD=this.selectedYMD||rt(this.getToday()),this.focus())}},render:function(e){var r=this;if(this.hidden)return e();var n=this.valueId,i=this.widgetId,a=this.navId,o=this.gridId,s=this.gridCaptionId,l=this.gridHelpId,u=this.activeId,f=this.disabled,d=this.noKeyNav,p=this.isLive,h=this.isRTL,b=this.activeYMD,y=this.selectedYMD,P=this.safeId,C=!this.showDecadeNav,R=rt(this.getToday()),D=!this.noHighlightToday,B=e(\"output\",{staticClass:\"form-control form-control-sm text-center\",class:{\"text-muted\":f,readonly:this.readonly||f},attrs:{id:n,for:o,role:\"status\",tabindex:f?null:\"-1\",\"data-selected\":ce(y),\"aria-live\":p?\"polite\":\"off\",\"aria-atomic\":p?\"true\":null},on:{click:this.onHeaderClick,focus:this.onHeaderClick}},this.selectedDate?[e(\"bdi\",{staticClass:\"sr-only\"},\" (\".concat(ce(this.labelSelected),\") \")),e(\"bdi\",this.formatDateString(this.selectedDate))]:this.labelNoDateSelected||\"\\xA0\");B=e(this.headerTag,{staticClass:\"b-calendar-header\",class:{\"sr-only\":this.hideHeader},attrs:{title:this.selectedDate&&this.labelSelected||null}},[B]);var A={isRTL:h},V={shiftV:.5},N=ui(ui({},V),{},{flipH:h}),G=ui(ui({},V),{},{flipH:!h}),H=this.normalizeSlot(f2,A)||e(cw,{props:N}),W=this.normalizeSlot(p2,A)||e(fw,{props:N}),j=this.normalizeSlot(d2,A)||e(dw,{props:N}),E=this.normalizeSlot(h2,A)||e(Wm,{props:V}),v=this.normalizeSlot(u2,A)||e(dw,{props:G}),w=this.normalizeSlot(c2,A)||e(fw,{props:G}),$=this.normalizeSlot(l2,A)||e(cw,{props:G}),M=function(Ie,Te,$t,Re,Qe){return e(\"button\",{staticClass:\"btn btn-sm border-0 flex-fill\",class:[r.computedNavButtonVariant,{disabled:Re}],attrs:{title:Te||null,type:\"button\",tabindex:d?\"-1\":null,\"aria-label\":Te||null,\"aria-disabled\":Re?\"true\":null,\"aria-keyshortcuts\":Qe||null},on:Re?{}:{click:$t}},[e(\"div\",{attrs:{\"aria-hidden\":\"true\"}},[Ie])])},F=e(\"div\",{staticClass:\"b-calendar-nav d-flex\",attrs:{id:a,role:\"group\",tabindex:d?\"-1\":null,\"aria-hidden\":f?\"true\":null,\"aria-label\":this.labelNav||null,\"aria-controls\":o}},[C?e():M(H,this.labelPrevDecade,this.gotoPrevDecade,this.prevDecadeDisabled,\"Ctrl+Alt+PageDown\"),M(W,this.labelPrevYear,this.gotoPrevYear,this.prevYearDisabled,\"Alt+PageDown\"),M(j,this.labelPrevMonth,this.gotoPrevMonth,this.prevMonthDisabled,\"PageDown\"),M(E,this.labelCurrentMonth,this.gotoCurrentMonth,this.thisMonthDisabled,\"Home\"),M(v,this.labelNextMonth,this.gotoNextMonth,this.nextMonthDisabled,\"PageUp\"),M(w,this.labelNextYear,this.gotoNextYear,this.nextYearDisabled,\"Alt+PageUp\"),C?e():M($,this.labelNextDecade,this.gotoNextDecade,this.nextDecadeDisabled,\"Ctrl+Alt+PageUp\")]),X=e(\"div\",{staticClass:\"b-calendar-grid-caption text-center font-weight-bold\",class:{\"text-muted\":f},attrs:{id:s,\"aria-live\":p?\"polite\":null,\"aria-atomic\":p?\"true\":null},key:\"grid-caption\"},this.formatYearMonth(this.calendarFirstDay)),Q=e(\"div\",{staticClass:\"b-calendar-grid-weekdays row no-gutters border-bottom\",attrs:{\"aria-hidden\":\"true\"}},this.calendarHeadings.map(function(me,Ie){return e(\"small\",{staticClass:\"col text-truncate\",class:{\"text-muted\":f},attrs:{title:me.label===me.text?null:me.label,\"aria-label\":me.label},key:Ie},me.text)})),q=this.calendar.map(function(me){var Ie=me.map(function(Te,$t){var Re,Qe=Te.ymd===y,Ir=Te.ymd===b,Pn=Te.ymd===R,ul=P(\"_cell-\".concat(Te.ymd,\"_\")),zo=e(\"span\",{staticClass:\"btn border-0 rounded-circle text-nowrap\",class:(Re={focus:Ir&&r.gridHasFocus,disabled:Te.isDisabled||f,active:Qe},Cn(Re,r.computedVariant,Qe),Cn(Re,r.computedTodayVariant,Pn&&D&&!Qe&&Te.isThisMonth),Cn(Re,\"btn-outline-light\",!(Pn&&D)&&!Qe&&!Ir),Cn(Re,\"btn-light\",!(Pn&&D)&&!Qe&&Ir),Cn(Re,\"text-muted\",!Te.isThisMonth&&!Qe),Cn(Re,\"text-dark\",!(Pn&&D)&&!Qe&&!Ir&&Te.isThisMonth),Cn(Re,\"font-weight-bold\",(Qe||Te.isThisMonth)&&!Te.isDisabled),Re),on:{click:function(){return r.onClickDay(Te)}}},Te.day);return e(\"div\",{staticClass:\"col p-0\",class:Te.isDisabled?\"bg-light\":Te.info.class||\"\",attrs:{id:ul,role:\"button\",\"data-date\":Te.ymd,\"aria-hidden\":Te.isThisMonth?null:\"true\",\"aria-disabled\":Te.isDisabled||f?\"true\":null,\"aria-label\":[Te.label,Qe?\"(\".concat(r.labelSelected,\")\"):null,Pn?\"(\".concat(r.labelToday,\")\"):null].filter(pe).join(\" \"),\"aria-selected\":Qe?\"true\":null,\"aria-current\":Qe?\"date\":null},key:$t},[zo])});return e(\"div\",{staticClass:\"row no-gutters\",key:me[0].ymd},Ie)});q=e(\"div\",{staticClass:\"b-calendar-grid-body\",style:f?{pointerEvents:\"none\"}:{}},q);var K=e(\"div\",{staticClass:\"b-calendar-grid-help border-top small text-muted text-center bg-light\",attrs:{id:l}},[e(\"div\",{staticClass:\"small\"},this.labelHelp)]),U=e(\"div\",{staticClass:\"b-calendar-grid form-control h-auto text-center\",attrs:{id:o,role:\"application\",tabindex:d?\"-1\":f?null:\"0\",\"data-month\":b.slice(0,-3),\"aria-roledescription\":this.labelCalendar||null,\"aria-labelledby\":s,\"aria-describedby\":l,\"aria-disabled\":f?\"true\":null,\"aria-activedescendant\":u},on:{keydown:this.onKeydownGrid,focus:this.setGridFocusFlag,blur:this.setGridFocusFlag},ref:\"grid\"},[X,Q,q,K]),le=this.normalizeSlot();le=le?e(\"footer\",{staticClass:\"b-calendar-footer\"},le):e();var be=e(\"div\",{staticClass:\"b-calendar-inner\",style:this.block?{}:{width:this.width},attrs:{id:i,dir:h?\"rtl\":\"ltr\",lang:this.computedLocale||null,role:\"group\",\"aria-disabled\":f?\"true\":null,\"aria-controls\":this.ariaControls||null,\"aria-roledescription\":this.roleDescription||null,\"aria-describedby\":[this.bvAttrs[\"aria-describedby\"],n,l].filter(pe).join(\" \")},on:{keydown:this.onKeydownWrapper}},[B,F,U,le]);return e(\"div\",{staticClass:\"b-calendar\",class:{\"d-block\":this.block}},[be])}}),PH=ae({components:{BCalendar:gA}}),Xu=z({bgVariant:c(g),borderVariant:c(g),tag:c(g,\"div\"),textVariant:c(g)},Db);I({props:Xu});var Vb=z({title:c(g),titleTag:c(g,\"h4\")},W$),bA=I({name:W$,functional:!0,props:Vb,render:function(e,r){var n=r.props,i=r.data,a=r.children;return e(n.titleTag,oe(i,{staticClass:\"card-title\"}),a||ce(n.title))}}),Hb=z({subTitle:c(g),subTitleTag:c(g,\"h6\"),subTitleTextVariant:c(g,\"muted\")},U$),yA=I({name:U$,functional:!0,props:Hb,render:function(e,r){var n=r.props,i=r.data,a=r.children;return e(n.subTitleTag,oe(i,{staticClass:\"card-subtitle\",class:[n.subTitleTextVariant?\"text-\".concat(n.subTitleTextVariant):null]}),a||ce(n.subTitle))}});function Vw(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Dc(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?Vw(Object(r),!0).forEach(function(n){hf(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):Vw(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function hf(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var zb=z(ie(Dc(Dc(Dc(Dc({},Vb),Hb),lp(Xu,sp.bind(null,\"body\"))),{},{bodyClass:c(de),overlay:c(_,!1)})),L$),OA=I({name:L$,functional:!0,props:zb,render:function(e,r){var n,i=r.props,a=r.data,o=r.children,s=i.bodyBgVariant,l=i.bodyBorderVariant,u=i.bodyTextVariant,f=e();i.title&&(f=e(bA,{props:at(Vb,i)}));var d=e();return i.subTitle&&(d=e(yA,{props:at(Hb,i),class:[\"mb-2\"]})),e(i.bodyTag,oe(a,{staticClass:\"card-body\",class:[(n={\"card-img-overlay\":i.overlay},hf(n,\"bg-\".concat(s),s),hf(n,\"border-\".concat(l),l),hf(n,\"text-\".concat(u),u),n),i.bodyClass]}),[f,d,o])}});function Hw(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function zw(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?Hw(Object(r),!0).forEach(function(n){vf(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):Hw(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function vf(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Ub=z(ie(zw(zw({},lp(Xu,sp.bind(null,\"header\"))),{},{header:c(g),headerClass:c(de),headerHtml:c(g)})),V$),_A=I({name:V$,functional:!0,props:Ub,render:function(e,r){var n,i=r.props,a=r.data,o=r.children,s=i.headerBgVariant,l=i.headerBorderVariant,u=i.headerTextVariant;return e(i.headerTag,oe(a,{staticClass:\"card-header\",class:[i.headerClass,(n={},vf(n,\"bg-\".concat(s),s),vf(n,\"border-\".concat(l),l),vf(n,\"text-\".concat(u),u),n)],domProps:o?{}:dt(i.headerHtml,i.header)}),o)}});function Uw(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Gw(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?Uw(Object(r),!0).forEach(function(n){mf(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):Uw(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function mf(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Gb=z(ie(Gw(Gw({},lp(Xu,sp.bind(null,\"footer\"))),{},{footer:c(g),footerClass:c(de),footerHtml:c(g)})),F$),wA=I({name:F$,functional:!0,props:Gb,render:function(e,r){var n,i=r.props,a=r.data,o=r.children,s=i.footerBgVariant,l=i.footerBorderVariant,u=i.footerTextVariant;return e(i.footerTag,oe(a,{staticClass:\"card-footer\",class:[i.footerClass,(n={},mf(n,\"bg-\".concat(s),s),mf(n,\"border-\".concat(l),l),mf(n,\"text-\".concat(u),u),n)],domProps:o?{}:dt(i.footerHtml,i.footer)}),o)}});function ov(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var EH='<svg width=\"%{w}\" height=\"%{h}\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 %{w} %{h}\" preserveAspectRatio=\"none\"><rect width=\"100%\" height=\"100%\" style=\"fill:%{f};\"></rect></svg>',$H=function(e,r,n){var i=encodeURIComponent(EH.replace(\"%{w}\",ce(e)).replace(\"%{h}\",ce(r)).replace(\"%{f}\",n));return\"data:image/svg+xml;charset=UTF-8,\".concat(i)},vp=z({alt:c(g),blank:c(_,!1),blankColor:c(g,\"transparent\"),block:c(_,!1),center:c(_,!1),fluid:c(_,!1),fluidGrow:c(_,!1),height:c(re),left:c(_,!1),right:c(_,!1),rounded:c(_r,!1),sizes:c(Or),src:c(g),srcset:c(Or),thumbnail:c(_,!1),width:c(re)},CC),Wb=I({name:CC,functional:!0,props:vp,render:function(e,r){var n,i=r.props,a=r.data,o=i.alt,s=i.src,l=i.block,u=i.fluidGrow,f=i.rounded,d=ee(i.width)||null,p=ee(i.height)||null,h=null,b=Me(i.srcset).filter(pe).join(\",\"),y=Me(i.sizes).filter(pe).join(\",\");return i.blank&&(!p&&d?p=d:!d&&p&&(d=p),!d&&!p&&(d=1,p=1),s=$H(d,p,i.blankColor||\"transparent\"),b=null,y=null),i.left?h=\"float-left\":i.right?h=\"float-right\":i.center&&(h=\"mx-auto\",l=!0),e(\"img\",oe(a,{attrs:{src:s,alt:o,width:d?ce(d):null,height:p?ce(p):null,srcset:b||null,sizes:y||null},class:(n={\"img-thumbnail\":i.thumbnail,\"img-fluid\":i.fluid||u,\"w-100\":u,rounded:f===\"\"||f===!0},ov(n,\"rounded-\".concat(f),Ae(f)&&f!==\"\"),ov(n,h,h),ov(n,\"d-block\",l),n)}))}});function Ww(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Kw(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?Ww(Object(r),!0).forEach(function(n){CH(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):Ww(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function CH(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Kb=z(ie(Kw(Kw({},Zn(vp,[\"src\",\"alt\",\"width\",\"height\",\"left\",\"right\"])),{},{bottom:c(_,!1),end:c(_,!1),start:c(_,!1),top:c(_,!1)})),H$),TA=I({name:H$,functional:!0,props:Kb,render:function(e,r){var n=r.props,i=r.data,a=n.src,o=n.alt,s=n.width,l=n.height,u=\"card-img\";return n.top?u+=\"-top\":n.right||n.end?u+=\"-right\":n.bottom?u+=\"-bottom\":(n.left||n.start)&&(u+=\"-left\"),e(\"img\",oe(i,{class:u,attrs:{src:a,alt:o,width:s,height:l}}))}});function Yw(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function es(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?Yw(Object(r),!0).forEach(function(n){Jl(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):Yw(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Jl(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Yb=lp(Kb,sp.bind(null,\"img\"));Yb.imgSrc.required=!1;var DH=z(ie(es(es(es(es(es(es({},zb),Ub),Gb),Yb),Xu),{},{align:c(g),noBody:c(_,!1)})),Db),AH=I({name:Db,functional:!0,props:DH,render:function(e,r){var n,i=r.props,a=r.data,o=r.slots,s=r.scopedSlots,l=i.imgSrc,u=i.imgLeft,f=i.imgRight,d=i.imgStart,p=i.imgEnd,h=i.imgBottom,b=i.header,y=i.headerHtml,P=i.footer,C=i.footerHtml,R=i.align,D=i.textVariant,B=i.bgVariant,A=i.borderVariant,V=s||{},N=o(),G={},H=e(),W=e();if(l){var j=e(TA,{props:at(Yb,i,VD.bind(null,\"img\"))});h?W=j:H=j}var E=e(),v=Ki(Ca,V,N);(v||b||y)&&(E=e(_A,{props:at(Ub,i),domProps:v?{}:dt(y,b)},rr(Ca,G,V,N)));var w=rr(kt,G,V,N);i.noBody||(w=e(OA,{props:at(zb,i)},w),i.overlay&&l&&(w=e(\"div\",{staticClass:\"position-relative\"},[H,w,W]),H=e(),W=e()));var $=e(),M=Ki(jm,V,N);return(M||P||C)&&($=e(wA,{props:at(Gb,i),domProps:v?{}:dt(C,P)},rr(jm,G,V,N))),e(i.tag,oe(a,{staticClass:\"card\",class:(n={\"flex-row\":u||d,\"flex-row-reverse\":(f||p)&&!(u||d)},Jl(n,\"text-\".concat(R),R),Jl(n,\"bg-\".concat(B),B),Jl(n,\"border-\".concat(A),A),Jl(n,\"text-\".concat(D),D),n)}),[H,E,w,$,W])}});function RH(t,e){if(!(t instanceof e))throw new TypeError(\"Cannot call a class as a function\")}function qw(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,\"value\"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}function xH(t,e,r){return e&&qw(t.prototype,e),r&&qw(t,r),Object.defineProperty(t,\"prototype\",{writable:!1}),t}var Is=\"__bv__visibility_observer\",MH=function(){function t(e,r){RH(this,t),this.el=e,this.callback=r.callback,this.margin=r.margin||0,this.once=r.once||!1,this.observer=null,this.visible=void 0,this.doneOnce=!1,this.createObserver()}return xH(t,[{key:\"createObserver\",value:function(){var r=this;if(this.observer&&this.stop(),!(this.doneOnce||!se(this.callback))){try{this.observer=new IntersectionObserver(this.handler.bind(this),{root:null,rootMargin:this.margin,threshold:0})}catch{this.doneOnce=!0,this.observer=void 0,this.callback(null);return}Eb(function(){We(function(){r.observer&&r.observer.observe(r.el)})})}}},{key:\"handler\",value:function(r){var n=r?r[0]:{},i=Boolean(n.isIntersecting||n.intersectionRatio>0);i!==this.visible&&(this.visible=i,this.callback(i),this.once&&this.visible&&(this.doneOnce=!0,this.stop()))}},{key:\"stop\",value:function(){this.observer&&this.observer.disconnect(),this.observer=null}}]),t}(),SA=function(e){var r=e[Is];r&&r.stop&&r.stop(),delete e[Is]},PA=function(e,r){var n=r.value,i=r.modifiers,a={margin:\"0px\",once:!1,callback:n};ge(i).forEach(function(o){g$.test(o)?a.margin=\"\".concat(o,\"px\"):o.toLowerCase()===\"once\"&&(a.once=!0)}),SA(e),e[Is]=new MH(e,a),e[Is]._prevModifiers=Na(i)},NH=function(e,r,n){var i=r.value,a=r.oldValue,o=r.modifiers;o=Na(o),e&&(i!==a||!e[Is]||!je(o,e[Is]._prevModifiers))&&PA(e,{value:i,modifiers:o})},IH=function(e){SA(e)},qb={bind:PA,componentUpdated:NH,unbind:IH},Ac;function Xw(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function hd(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?Xw(Object(r),!0).forEach(function(n){Ts(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):Xw(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Ts(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var hu=\"show\",BH=Ia+hu,EA=Pe(vp,[\"blank\"]),$A=z(hd(hd({},EA),{},Ts({blankHeight:c(re),blankSrc:c(g,null),blankWidth:c(re),offset:c(re,360)},hu,c(_,!1))),DC),CA=I({name:DC,directives:{\"b-visible\":qb},props:$A,data:function(){return{isShown:this[hu]}},computed:{computedSrc:function(){var e=this.blankSrc;return!e||this.isShown?this.src:e},computedBlank:function(){return!(this.isShown||this.blankSrc)},computedWidth:function(){var e=this.width;return this.isShown?e:this.blankWidth||e},computedHeight:function(){var e=this.height;return this.isShown?e:this.blankHeight||e},computedSrcset:function(){var e=Me(this.srcset).filter(pe).join(\",\");return e&&(!this.blankSrc||this.isShown)?e:null},computedSizes:function(){var e=Me(this.sizes).filter(pe).join(\",\");return e&&(!this.blankSrc||this.isShown)?e:null}},watch:(Ac={},Ts(Ac,hu,function(t,e){if(t!==e){var r=E_?t:!0;this.isShown=r,t!==r&&this.$nextTick(this.updateShowProp)}}),Ts(Ac,\"isShown\",function(e,r){e!==r&&this.updateShowProp()}),Ac),mounted:function(){var e=this;this.$nextTick(function(){e.isShown=E_?e[hu]:!0})},methods:{updateShowProp:function(){this.$emit(BH,this.isShown)},doShow:function(e){var r=this;(e||e===null)&&!this.isShown&&We(function(){r.isShown=!0})}},render:function(e){var r=[];if(!this.isShown){var n;r.push({name:\"b-visible\",value:this.doShow,modifiers:(n={},Ts(n,\"\".concat(ee(this.offset,0)),!0),Ts(n,\"once\",!0),n)})}return e(Wb,{directives:r,props:hd(hd({},at(EA,this.$props)),{},{src:this.computedSrc,blank:this.computedBlank,width:this.computedWidth,height:this.computedHeight,srcset:this.computedSrcset,sizes:this.computedSizes})})}});function Jw(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Zw(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?Jw(Object(r),!0).forEach(function(n){kH(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):Jw(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function kH(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var LH=z(ie(Zw(Zw({},Pe($A,ge(vp))),Pe(Kb,[\"src\",\"alt\",\"width\",\"height\"]))),z$),FH=I({name:z$,functional:!0,props:LH,render:function(e,r){var n=r.props,i=r.data,a=\"card-img\";return n.top?a+=\"-top\":n.right||n.end?a+=\"-right\":n.bottom?a+=\"-bottom\":(n.left||n.start)&&(a+=\"-left\"),e(CA,oe(i,{class:[a],props:Pe(n,[\"left\",\"right\"])}))}}),jH=z({textTag:c(g,\"p\")},G$),VH=I({name:G$,functional:!0,props:jH,render:function(e,r){var n=r.props,i=r.data,a=r.children;return e(n.textTag,oe(i,{staticClass:\"card-text\"}),a)}}),HH=z({columns:c(_,!1),deck:c(_,!1),tag:c(g,\"div\")},j$),zH=I({name:j$,functional:!0,props:HH,render:function(e,r){var n=r.props,i=r.data,a=r.children;return e(n.tag,oe(i,{class:n.deck?\"card-deck\":n.columns?\"card-columns\":\"card-group\"}),a)}}),UH=ae({components:{BCard:AH,BCardHeader:_A,BCardBody:OA,BCardTitle:bA,BCardSubTitle:yA,BCardFooter:wA,BCardImg:TA,BCardImgLazy:FH,BCardText:VH,BCardGroup:zH}}),Nu=function(){};function Qw(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function GH(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?Qw(Object(r),!0).forEach(function(n){WH(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):Qw(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function WH(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Iu=function(e,r,n){if(e=e?e.$el||e:null,!et(e)||kF(\"observeDom\"))return null;var i=new x2(function(a){for(var o=!1,s=0;s<a.length&&!o;s++){var l=a[s],u=l.type,f=l.target;(u===\"characterData\"&&f.nodeType===Node.TEXT_NODE||u===\"attributes\"||u===\"childList\"&&(l.addedNodes.length>0||l.removedNodes.length>0))&&(o=!0)}o&&r()});return i.observe(e,GH({childList:!0,subtree:!0},n)),i},ts;function eT(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function sv(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?eT(Object(r),!0).forEach(function(n){Zl(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):eT(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Zl(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var mp=Nt(\"value\",{type:mr,defaultValue:0}),KH=mp.mixin,YH=mp.props,lv=mp.prop,tT=mp.event,uv={next:{dirClass:\"carousel-item-left\",overlayClass:\"carousel-item-next\"},prev:{dirClass:\"carousel-item-right\",overlayClass:\"carousel-item-prev\"}},qH=600+50,XH=500,JH=40,rT={TOUCH:\"touch\",PEN:\"pen\"},nT={WebkitTransition:\"webkitTransitionEnd\",MozTransition:\"transitionend\",OTransition:\"otransitionend oTransitionEnd\",transition:\"transitionend\"},ZH=function(e){for(var r in nT)if(!Et(e.style[r]))return nT[r];return null},QH=z(ie(sv(sv(sv({},Ke),YH),{},{background:c(g),controls:c(_,!1),fade:c(_,!1),imgHeight:c(re),imgWidth:c(re),indicators:c(_,!1),interval:c(mr,5e3),labelGotoSlide:c(g,\"Goto slide\"),labelIndicators:c(g,\"Select a slide to display\"),labelNext:c(g,\"Next slide\"),labelPrev:c(g,\"Previous slide\"),noAnimation:c(_,!1),noHoverPause:c(_,!1),noTouch:c(_,!1),noWrap:c(_,!1)})),K$),e5=I({name:K$,mixins:[Ze,KH,ve],provide:function(){var e=this;return{getBvCarousel:function(){return e}}},props:QH,data:function(){return{index:this[lv]||0,isSliding:!1,transitionEndEvent:null,slides:[],direction:null,isPaused:!(ee(this.interval,0)>0),touchStartX:0,touchDeltaX:0}},computed:{numSlides:function(){return this.slides.length}},watch:(ts={},Zl(ts,lv,function(t,e){t!==e&&this.setSlide(ee(t,0))}),Zl(ts,\"interval\",function(e,r){e!==r&&(e?(this.pause(!0),this.start(!1)):this.pause(!1))}),Zl(ts,\"isPaused\",function(e,r){e!==r&&this.$emit(e?bj:Aj)}),Zl(ts,\"index\",function(e,r){e===r||this.isSliding||this.doSlide(e,r)}),ts),created:function(){this.$_interval=null,this.$_animationTimeout=null,this.$_touchTimeout=null,this.$_observer=null,this.isPaused=!(ee(this.interval,0)>0)},mounted:function(){this.transitionEndEvent=ZH(this.$el)||null,this.updateSlides(),this.setObserver(!0)},beforeDestroy:function(){this.clearInterval(),this.clearAnimationTimeout(),this.clearTouchTimeout(),this.setObserver(!1)},methods:{clearInterval:function(t){function e(){return t.apply(this,arguments)}return e.toString=function(){return t.toString()},e}(function(){clearInterval(this.$_interval),this.$_interval=null}),clearAnimationTimeout:function(){clearTimeout(this.$_animationTimeout),this.$_animationTimeout=null},clearTouchTimeout:function(){clearTimeout(this.$_touchTimeout),this.$_touchTimeout=null},setObserver:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:!1;this.$_observer&&this.$_observer.disconnect(),this.$_observer=null,e&&(this.$_observer=Iu(this.$refs.inner,this.updateSlides.bind(this),{subtree:!1,childList:!0,attributes:!0,attributeFilter:[\"id\"]}))},setSlide:function(e){var r=this,n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:null;if(!(Je&&document.visibilityState&&document.hidden)){var i=this.noWrap,a=this.numSlides;if(e=Mu(e),a!==0){if(this.isSliding){this.$once(Gh,function(){We(function(){return r.setSlide(e,n)})});return}this.direction=n,this.index=e>=a?i?a-1:0:e<0?i?0:a-1:e,i&&this.index!==e&&this.index!==this[lv]&&this.$emit(tT,this.index)}}},prev:function(){this.setSlide(this.index-1,\"prev\")},next:function(){this.setSlide(this.index+1,\"next\")},pause:function(e){e||(this.isPaused=!0),this.clearInterval()},start:function(e){e||(this.isPaused=!1),this.clearInterval(),this.interval&&this.numSlides>1&&(this.$_interval=setInterval(this.next,Fe(1e3,this.interval)))},restart:function(){this.$el.contains(Da())||this.start()},doSlide:function(e,r){var n=this,i=Boolean(this.interval),a=this.calcDirection(this.direction,r,e),o=a.overlayClass,s=a.dirClass,l=this.slides[r],u=this.slides[e];if(!(!l||!u)){if(this.isSliding=!0,i&&this.pause(!1),this.$emit($j,e),this.$emit(tT,this.index),this.noAnimation)$r(u,\"active\"),hr(l,\"active\"),this.isSliding=!1,this.$nextTick(function(){return n.$emit(Gh,e)});else{$r(u,o),kb(u),$r(l,s),$r(u,s);var f=!1,d=function h(){if(!f){if(f=!0,n.transitionEndEvent){var b=n.transitionEndEvent.split(/\\s+/);b.forEach(function(y){return ft(u,y,h,De)})}n.clearAnimationTimeout(),hr(u,s),hr(u,o),$r(u,\"active\"),hr(l,\"active\"),hr(l,s),hr(l,o),st(l,\"aria-current\",\"false\"),st(u,\"aria-current\",\"true\"),st(l,\"aria-hidden\",\"true\"),st(u,\"aria-hidden\",\"false\"),n.isSliding=!1,n.direction=null,n.$nextTick(function(){return n.$emit(Gh,e)})}};if(this.transitionEndEvent){var p=this.transitionEndEvent.split(/\\s+/);p.forEach(function(h){return it(u,h,d,De)})}this.$_animationTimeout=setTimeout(d,qH)}i&&this.start(!1)}},updateSlides:function(){this.pause(!0),this.slides=yn(\".carousel-item\",this.$refs.inner);var e=this.slides.length,r=Fe(0,Fi(Mu(this.index),e-1));this.slides.forEach(function(n,i){var a=i+1;i===r?($r(n,\"active\"),st(n,\"aria-current\",\"true\")):(hr(n,\"active\"),st(n,\"aria-current\",\"false\")),st(n,\"aria-posinset\",String(a)),st(n,\"aria-setsize\",String(e))}),this.setSlide(r),this.start(this.isPaused)},calcDirection:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:null,r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:0,n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:0;return e?uv[e]:n>r?uv.next:uv.prev},handleClick:function(e,r){var n=e.keyCode;(e.type===\"click\"||n===Ti||n===Ji)&&(_e(e),r())},handleSwipe:function(){var e=WD(this.touchDeltaX);if(!(e<=JH)){var r=e/this.touchDeltaX;this.touchDeltaX=0,r>0?this.prev():r<0&&this.next()}},touchStart:function(e){El&&rT[e.pointerType.toUpperCase()]?this.touchStartX=e.clientX:El||(this.touchStartX=e.touches[0].clientX)},touchMove:function(e){e.touches&&e.touches.length>1?this.touchDeltaX=0:this.touchDeltaX=e.touches[0].clientX-this.touchStartX},touchEnd:function(e){El&&rT[e.pointerType.toUpperCase()]&&(this.touchDeltaX=e.clientX-this.touchStartX),this.handleSwipe(),this.pause(!1),this.clearTouchTimeout(),this.$_touchTimeout=setTimeout(this.start,XH+Fe(1e3,this.interval))}},render:function(e){var r=this,n=this.indicators,i=this.background,a=this.noAnimation,o=this.noHoverPause,s=this.noTouch,l=this.index,u=this.isSliding,f=this.pause,d=this.restart,p=this.touchStart,h=this.touchEnd,b=this.safeId(\"__BV_inner_\"),y=e(\"div\",{staticClass:\"carousel-inner\",attrs:{id:b,role:\"list\"},ref:\"inner\"},[this.normalizeSlot()]),P=e();if(this.controls){var C=function(A,V,N){var G=function(W){u?_e(W,{propagation:!1}):r.handleClick(W,N)};return e(\"a\",{staticClass:\"carousel-control-\".concat(A),attrs:{href:\"#\",role:\"button\",\"aria-controls\":b,\"aria-disabled\":u?\"true\":null},on:{click:G,keydown:G}},[e(\"span\",{staticClass:\"carousel-control-\".concat(A,\"-icon\"),attrs:{\"aria-hidden\":\"true\"}}),e(\"span\",{class:\"sr-only\"},[V])])};P=[C(\"prev\",this.labelPrev,this.prev),C(\"next\",this.labelNext,this.next)]}var R=e(\"ol\",{staticClass:\"carousel-indicators\",directives:[{name:\"show\",value:n}],attrs:{id:this.safeId(\"__BV_indicators_\"),\"aria-hidden\":n?\"false\":\"true\",\"aria-label\":this.labelIndicators,\"aria-owns\":b}},this.slides.map(function(B,A){var V=function(G){r.handleClick(G,function(){r.setSlide(A)})};return e(\"li\",{class:{active:A===l},attrs:{role:\"button\",id:r.safeId(\"__BV_indicator_\".concat(A+1,\"_\")),tabindex:n?\"0\":\"-1\",\"aria-current\":A===l?\"true\":\"false\",\"aria-label\":\"\".concat(r.labelGotoSlide,\" \").concat(A+1),\"aria-describedby\":B.id||null,\"aria-controls\":b},on:{click:V,keydown:V},key:\"slide_\".concat(A)})})),D={mouseenter:o?Nu:f,mouseleave:o?Nu:d,focusin:f,focusout:d,keydown:function(A){if(!/input|textarea/i.test(A.target.tagName)){var V=A.keyCode;(V===Xn||V===Yi)&&(_e(A),r[V===Xn?\"prev\":\"next\"]())}}};return Qf&&!s&&(El?(D[\"&pointerdown\"]=p,D[\"&pointerup\"]=h):(D[\"&touchstart\"]=p,D[\"&touchmove\"]=this.touchMove,D[\"&touchend\"]=h)),e(\"div\",{staticClass:\"carousel\",class:{slide:!a,\"carousel-fade\":!a&&this.fade,\"pointer-event\":Qf&&El&&!s},style:{background:i},attrs:{role:\"region\",id:this.safeId(),\"aria-busy\":u?\"true\":\"false\"},on:D},[y,P,R])}});function iT(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function vu(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?iT(Object(r),!0).forEach(function(n){t5(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):iT(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function t5(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var DA={imgAlt:c(g),imgBlank:c(_,!1),imgBlankColor:c(g,\"transparent\"),imgHeight:c(re),imgSrc:c(g),imgWidth:c(re)},r5=z(ie(vu(vu(vu({},Ke),DA),{},{background:c(g),caption:c(g),captionHtml:c(g),captionTag:c(g,\"h3\"),contentTag:c(g,\"div\"),contentVisibleUp:c(g),text:c(g),textHtml:c(g),textTag:c(g,\"p\")})),Y$),n5=I({name:Y$,mixins:[Ze,ve],inject:{getBvCarousel:{default:function(){return function(){return{noTouch:!0}}}}},props:r5,computed:{bvCarousel:function(){return this.getBvCarousel()},contentClasses:function(){return[this.contentVisibleUp?\"d-none\":\"\",this.contentVisibleUp?\"d-\".concat(this.contentVisibleUp,\"-block\"):\"\"]},computedWidth:function(){return this.imgWidth||this.bvCarousel.imgWidth||null},computedHeight:function(){return this.imgHeight||this.bvCarousel.imgHeight||null}},render:function(e){var r=this.normalizeSlot(Qj);if(!r&&(this.imgSrc||this.imgBlank)){var n={};!this.bvCarousel.noTouch&&Qf&&(n.dragstart=function(o){return _e(o,{propagation:!1})}),r=e(Wb,{props:vu(vu({},at(DA,this.$props,VD.bind(null,\"img\"))),{},{width:this.computedWidth,height:this.computedHeight,fluidGrow:!0,block:!0}),on:n})}var i=[this.caption||this.captionHtml?e(this.captionTag,{domProps:dt(this.captionHtml,this.caption)}):!1,this.text||this.textHtml?e(this.textTag,{domProps:dt(this.textHtml,this.text)}):!1,this.normalizeSlot()||!1],a=e();return i.some(pe)&&(a=e(this.contentTag,{staticClass:\"carousel-caption\",class:this.contentClasses},i.map(function(o){return o||e()}))),e(\"div\",{staticClass:\"carousel-item\",style:{background:this.background||this.bvCarousel.background||null},attrs:{id:this.safeId(),role:\"listitem\"}},[r,a])}}),i5=ae({components:{BCarousel:e5,BCarouselSlide:n5}}),cv=\"show\",a5=function(e){lr(e,\"height\",0),We(function(){kb(e),lr(e,\"height\",\"\".concat(e.scrollHeight,\"px\"))})},o5=function(e){op(e,\"height\")},s5=function(e){lr(e,\"height\",\"auto\"),lr(e,\"display\",\"block\"),lr(e,\"height\",\"\".concat(Ro(e).height,\"px\")),kb(e),lr(e,\"height\",0)},l5=function(e){op(e,\"height\")},u5={css:!0,enterClass:\"\",enterActiveClass:\"collapsing\",enterToClass:\"collapse show\",leaveClass:\"collapse show\",leaveActiveClass:\"collapsing\",leaveToClass:\"collapse\"},c5={enter:a5,afterEnter:o5,leave:s5,afterLeave:l5},f5={appear:c(_,!1)},d5=I({name:ZF,functional:!0,props:f5,render:function(e,r){var n=r.props,i=r.data,a=r.children;return e(\"transition\",oe(i,{props:u5,on:c5},{props:n}),a)}}),Rc;function aT(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function fv(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?aT(Object(r),!0).forEach(function(n){Jm(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):aT(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Jm(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var p5=xt(fr,\"toggle\"),h5=xt(fr,\"request-state\"),oT=bt(fr,\"accordion\"),v5=bt(fr,\"state\"),m5=bt(fr,\"sync-state\"),gp=Nt(\"visible\",{type:_,defaultValue:!1}),g5=gp.mixin,b5=gp.props,xc=gp.prop,y5=gp.event,O5=z(ie(fv(fv(fv({},Ke),b5),{},{accordion:c(g),appear:c(_,!1),isNav:c(_,!1),tag:c(g,\"div\")})),fr),_5=I({name:fr,mixins:[Ze,g5,ve,Qn],props:O5,data:function(){return{show:this[xc],transitioning:!1}},computed:{classObject:function(){var e=this.transitioning;return{\"navbar-collapse\":this.isNav,collapse:!e,show:this.show&&!e}},slotScope:function(){var e=this;return{visible:this.show,close:function(){e.show=!1}}}},watch:(Rc={},Jm(Rc,xc,function(t){t!==this.show&&(this.show=t)}),Jm(Rc,\"show\",function(e,r){e!==r&&this.emitState()}),Rc),created:function(){this.show=this[xc]},mounted:function(){var e=this;this.show=this[xc],this.listenOnRoot(p5,this.handleToggleEvent),this.listenOnRoot(oT,this.handleAccordionEvent),this.isNav&&(this.setWindowEvents(!0),this.handleResize()),this.$nextTick(function(){e.emitState()}),this.listenOnRoot(h5,function(r){r===e.safeId()&&e.$nextTick(e.emitSync)})},updated:function(){this.emitSync()},deactivated:function(){this.isNav&&this.setWindowEvents(!1)},activated:function(){this.isNav&&this.setWindowEvents(!0),this.emitSync()},beforeDestroy:function(){this.show=!1,this.isNav&&Je&&this.setWindowEvents(!1)},methods:{setWindowEvents:function(e){qn(e,window,\"resize\",this.handleResize,De),qn(e,window,\"orientationchange\",this.handleResize,De)},toggle:function(){this.show=!this.show},onEnter:function(){this.transitioning=!0,this.$emit(tr)},onAfterEnter:function(){this.transitioning=!1,this.$emit(Dr)},onLeave:function(){this.transitioning=!0,this.$emit(Xr)},onAfterLeave:function(){this.transitioning=!1,this.$emit(Pt)},emitState:function(){var e=this.show,r=this.accordion,n=this.safeId();this.$emit(y5,e),this.emitOnRoot(v5,n,e),r&&e&&this.emitOnRoot(oT,n,r)},emitSync:function(){this.emitOnRoot(m5,this.safeId(),this.show)},checkDisplayBlock:function(){var e=this.$el,r=Ru(e,cv);hr(e,cv);var n=hn(e).display===\"block\";return r&&$r(e,cv),n},clickHandler:function(e){var r=e.target;!this.isNav||!r||hn(this.$el).display!==\"block\"||(Vi(r,\".nav-link,.dropdown-item\")||Jr(\".nav-link,.dropdown-item\",r))&&!this.checkDisplayBlock()&&(this.show=!1)},handleToggleEvent:function(e){e===this.safeId()&&this.toggle()},handleAccordionEvent:function(e,r){var n=this.accordion,i=this.show;if(!(!n||n!==r)){var a=e===this.safeId();(a&&!i||!a&&i)&&this.toggle()}},handleResize:function(){this.show=hn(this.$el).display===\"block\"}},render:function(e){var r=this.appear,n=e(this.tag,{class:this.classObject,directives:[{name:\"show\",value:this.show}],attrs:{id:this.safeId()},on:{click:this.clickHandler}},this.normalizeSlot(kt,this.slotScope));return e(d5,{props:{appear:r},on:{enter:this.onEnter,afterEnter:this.onAfterEnter,leave:this.onLeave,afterLeave:this.onAfterLeave}},[n])}}),gi=function(e,r){return Nr?r.instance:e.context},Zm=\"collapsed\",Qm=\"not-collapsed\",bp=\"__BV_toggle\",mu=\"\".concat(bp,\"_HANDLER__\"),vd=\"\".concat(bp,\"_CLICK__\"),md=\"\".concat(bp,\"_STATE__\"),Bs=\"\".concat(bp,\"_TARGETS__\"),w5=\"false\",T5=\"true\",eg=\"aria-controls\",tg=\"aria-expanded\",rg=\"role\",sT=\"tabindex\",ng=\"overflow-anchor\",S5=xt(fr,\"toggle\"),AA=bt(fr,\"state\"),RA=bt(fr,\"sync-state\"),P5=xt(fr,\"request-state\"),E5=[Ji,Ti],xA=function(e){return!he([\"button\",\"a\"],e.tagName.toLowerCase())},$5=function(e,r){var n=e.modifiers,i=e.arg,a=e.value,o=ge(n||{});if(a=Ae(a)?a.split(sf):a,wi(r.tagName,\"a\")){var s=bn(r,\"href\")||\"\";eF.test(s)&&o.push(s.replace(QL,\"\"))}return Me(i,a).forEach(function(l){return Ae(l)&&o.push(l)}),o.filter(function(l,u,f){return l&&f.indexOf(l)===u})},MA=function(e){var r=e[vd];r&&(ft(e,\"click\",r,Yr),ft(e,\"keydown\",r,Yr)),e[vd]=null},C5=function(e,r){if(MA(e),r){var n=function(a){if(!(a.type===\"keydown\"&&!he(E5,a.keyCode))&&!lo(e)){var o=e[Bs]||[];o.forEach(function(s){Oi(r).$emit(S5,s)})}};e[vd]=n,it(e,\"click\",n,Yr),xA(e)&&it(e,\"keydown\",n,Yr)}},NA=function(e,r){e[mu]&&r&&Oi(r).$off([AA,RA],e[mu]),e[mu]=null},D5=function(e,r){if(NA(e,r),r){var n=function(a,o){he(e[Bs]||[],a)&&(e[md]=o,IA(e,o))};e[mu]=n,Oi(r).$on([AA,RA],n)}},IA=function(e,r){r?(hr(e,Zm),$r(e,Qm),st(e,tg,T5)):(hr(e,Qm),$r(e,Zm),st(e,tg,w5))},Mc=function(e,r){e[r]=null,delete e[r]},dv=function(e,r,n){if(!(!Je||!gi(n,r))){xA(e)&&(mi(e,rg)||st(e,rg,\"button\"),mi(e,sT)||st(e,sT,\"0\")),IA(e,e[md]);var i=$5(r,e);i.length>0?(st(e,eg,i.join(\" \")),lr(e,ng,\"none\")):(vi(e,eg),op(e,ng)),We(function(){C5(e,gi(n,r))}),je(i,e[Bs])||(e[Bs]=i,i.forEach(function(a){Oi(gi(n,r)).$emit(P5,a)}))}},BA={bind:function(e,r,n){e[md]=!1,e[Bs]=[],D5(e,gi(n,r)),dv(e,r,n)},componentUpdated:dv,updated:dv,unbind:function(e,r,n){MA(e),NA(e,gi(n,r)),Mc(e,mu),Mc(e,vd),Mc(e,md),Mc(e,Bs),hr(e,Zm),hr(e,Qm),vi(e,tg),vi(e,eg),vi(e,rg),op(e,ng)}},Xb=ae({directives:{VBToggle:BA}}),kA=ae({components:{BCollapse:_5},plugins:{VBTogglePlugin:Xb}});/**!\n * @fileOverview Kickass library to create and place poppers near their reference elements.\n * @version 1.16.1\n * @license\n * Copyright (c) 2016 Federico Zivolo and contributors\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */var Ju=typeof window<\"u\"&&typeof document<\"u\"&&typeof navigator<\"u\",A5=function(){for(var t=[\"Edge\",\"Trident\",\"Firefox\"],e=0;e<t.length;e+=1)if(Ju&&navigator.userAgent.indexOf(t[e])>=0)return 1;return 0}();function R5(t){var e=!1;return function(){e||(e=!0,window.Promise.resolve().then(function(){e=!1,t()}))}}function x5(t){var e=!1;return function(){e||(e=!0,setTimeout(function(){e=!1,t()},A5))}}var M5=Ju&&window.Promise,N5=M5?R5:x5;function LA(t){var e={};return t&&e.toString.call(t)===\"[object Function]\"}function Bo(t,e){if(t.nodeType!==1)return[];var r=t.ownerDocument.defaultView,n=r.getComputedStyle(t,null);return e?n[e]:n}function Jb(t){return t.nodeName===\"HTML\"?t:t.parentNode||t.host}function Zu(t){if(!t)return document.body;switch(t.nodeName){case\"HTML\":case\"BODY\":return t.ownerDocument.body;case\"#document\":return t.body}var e=Bo(t),r=e.overflow,n=e.overflowX,i=e.overflowY;return/(auto|scroll|overlay)/.test(r+i+n)?t:Zu(Jb(t))}function FA(t){return t&&t.referenceNode?t.referenceNode:t}var lT=Ju&&!!(window.MSInputMethodContext&&document.documentMode),uT=Ju&&/MSIE 10/.test(navigator.userAgent);function rl(t){return t===11?lT:t===10?uT:lT||uT}function ks(t){if(!t)return document.documentElement;for(var e=rl(10)?document.body:null,r=t.offsetParent||null;r===e&&t.nextElementSibling;)r=(t=t.nextElementSibling).offsetParent;var n=r&&r.nodeName;return!n||n===\"BODY\"||n===\"HTML\"?t?t.ownerDocument.documentElement:document.documentElement:[\"TH\",\"TD\",\"TABLE\"].indexOf(r.nodeName)!==-1&&Bo(r,\"position\")===\"static\"?ks(r):r}function I5(t){var e=t.nodeName;return e===\"BODY\"?!1:e===\"HTML\"||ks(t.firstElementChild)===t}function ig(t){return t.parentNode!==null?ig(t.parentNode):t}function gd(t,e){if(!t||!t.nodeType||!e||!e.nodeType)return document.documentElement;var r=t.compareDocumentPosition(e)&Node.DOCUMENT_POSITION_FOLLOWING,n=r?t:e,i=r?e:t,a=document.createRange();a.setStart(n,0),a.setEnd(i,0);var o=a.commonAncestorContainer;if(t!==o&&e!==o||n.contains(i))return I5(o)?o:ks(o);var s=ig(t);return s.host?gd(s.host,e):gd(t,ig(e).host)}function Ls(t){var e=arguments.length>1&&arguments[1]!==void 0?arguments[1]:\"top\",r=e===\"top\"?\"scrollTop\":\"scrollLeft\",n=t.nodeName;if(n===\"BODY\"||n===\"HTML\"){var i=t.ownerDocument.documentElement,a=t.ownerDocument.scrollingElement||i;return a[r]}return t[r]}function B5(t,e){var r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:!1,n=Ls(e,\"top\"),i=Ls(e,\"left\"),a=r?-1:1;return t.top+=n*a,t.bottom+=n*a,t.left+=i*a,t.right+=i*a,t}function cT(t,e){var r=e===\"x\"?\"Left\":\"Top\",n=r===\"Left\"?\"Right\":\"Bottom\";return parseFloat(t[\"border\"+r+\"Width\"])+parseFloat(t[\"border\"+n+\"Width\"])}function fT(t,e,r,n){return Math.max(e[\"offset\"+t],e[\"scroll\"+t],r[\"client\"+t],r[\"offset\"+t],r[\"scroll\"+t],rl(10)?parseInt(r[\"offset\"+t])+parseInt(n[\"margin\"+(t===\"Height\"?\"Top\":\"Left\")])+parseInt(n[\"margin\"+(t===\"Height\"?\"Bottom\":\"Right\")]):0)}function jA(t){var e=t.body,r=t.documentElement,n=rl(10)&&getComputedStyle(r);return{height:fT(\"Height\",e,r,n),width:fT(\"Width\",e,r,n)}}var k5=function(t,e){if(!(t instanceof e))throw new TypeError(\"Cannot call a class as a function\")},L5=function(){function t(e,r){for(var n=0;n<r.length;n++){var i=r[n];i.enumerable=i.enumerable||!1,i.configurable=!0,\"value\"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),Fs=function(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t},In=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(t[n]=r[n])}return t};function xa(t){return In({},t,{right:t.left+t.width,bottom:t.top+t.height})}function ag(t){var e={};try{if(rl(10)){e=t.getBoundingClientRect();var r=Ls(t,\"top\"),n=Ls(t,\"left\");e.top+=r,e.left+=n,e.bottom+=r,e.right+=n}else e=t.getBoundingClientRect()}catch{}var i={left:e.left,top:e.top,width:e.right-e.left,height:e.bottom-e.top},a=t.nodeName===\"HTML\"?jA(t.ownerDocument):{},o=a.width||t.clientWidth||i.width,s=a.height||t.clientHeight||i.height,l=t.offsetWidth-o,u=t.offsetHeight-s;if(l||u){var f=Bo(t);l-=cT(f,\"x\"),u-=cT(f,\"y\"),i.width-=l,i.height-=u}return xa(i)}function Zb(t,e){var r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:!1,n=rl(10),i=e.nodeName===\"HTML\",a=ag(t),o=ag(e),s=Zu(t),l=Bo(e),u=parseFloat(l.borderTopWidth),f=parseFloat(l.borderLeftWidth);r&&i&&(o.top=Math.max(o.top,0),o.left=Math.max(o.left,0));var d=xa({top:a.top-o.top-u,left:a.left-o.left-f,width:a.width,height:a.height});if(d.marginTop=0,d.marginLeft=0,!n&&i){var p=parseFloat(l.marginTop),h=parseFloat(l.marginLeft);d.top-=u-p,d.bottom-=u-p,d.left-=f-h,d.right-=f-h,d.marginTop=p,d.marginLeft=h}return(n&&!r?e.contains(s):e===s&&s.nodeName!==\"BODY\")&&(d=B5(d,e)),d}function F5(t){var e=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,r=t.ownerDocument.documentElement,n=Zb(t,r),i=Math.max(r.clientWidth,window.innerWidth||0),a=Math.max(r.clientHeight,window.innerHeight||0),o=e?0:Ls(r),s=e?0:Ls(r,\"left\"),l={top:o-n.top+n.marginTop,left:s-n.left+n.marginLeft,width:i,height:a};return xa(l)}function VA(t){var e=t.nodeName;if(e===\"BODY\"||e===\"HTML\")return!1;if(Bo(t,\"position\")===\"fixed\")return!0;var r=Jb(t);return r?VA(r):!1}function HA(t){if(!t||!t.parentElement||rl())return document.documentElement;for(var e=t.parentElement;e&&Bo(e,\"transform\")===\"none\";)e=e.parentElement;return e||document.documentElement}function Qb(t,e,r,n){var i=arguments.length>4&&arguments[4]!==void 0?arguments[4]:!1,a={top:0,left:0},o=i?HA(t):gd(t,FA(e));if(n===\"viewport\")a=F5(o,i);else{var s=void 0;n===\"scrollParent\"?(s=Zu(Jb(e)),s.nodeName===\"BODY\"&&(s=t.ownerDocument.documentElement)):n===\"window\"?s=t.ownerDocument.documentElement:s=n;var l=Zb(s,o,i);if(s.nodeName===\"HTML\"&&!VA(o)){var u=jA(t.ownerDocument),f=u.height,d=u.width;a.top+=l.top-l.marginTop,a.bottom=f+l.top,a.left+=l.left-l.marginLeft,a.right=d+l.left}else a=l}r=r||0;var p=typeof r==\"number\";return a.left+=p?r:r.left||0,a.top+=p?r:r.top||0,a.right-=p?r:r.right||0,a.bottom-=p?r:r.bottom||0,a}function j5(t){var e=t.width,r=t.height;return e*r}function zA(t,e,r,n,i){var a=arguments.length>5&&arguments[5]!==void 0?arguments[5]:0;if(t.indexOf(\"auto\")===-1)return t;var o=Qb(r,n,a,i),s={top:{width:o.width,height:e.top-o.top},right:{width:o.right-e.right,height:o.height},bottom:{width:o.width,height:o.bottom-e.bottom},left:{width:e.left-o.left,height:o.height}},l=Object.keys(s).map(function(p){return In({key:p},s[p],{area:j5(s[p])})}).sort(function(p,h){return h.area-p.area}),u=l.filter(function(p){var h=p.width,b=p.height;return h>=r.clientWidth&&b>=r.clientHeight}),f=u.length>0?u[0].key:l[0].key,d=t.split(\"-\")[1];return f+(d?\"-\"+d:\"\")}function UA(t,e,r){var n=arguments.length>3&&arguments[3]!==void 0?arguments[3]:null,i=n?HA(e):gd(e,FA(r));return Zb(r,i,n)}function GA(t){var e=t.ownerDocument.defaultView,r=e.getComputedStyle(t),n=parseFloat(r.marginTop||0)+parseFloat(r.marginBottom||0),i=parseFloat(r.marginLeft||0)+parseFloat(r.marginRight||0),a={width:t.offsetWidth+i,height:t.offsetHeight+n};return a}function bd(t){var e={left:\"right\",right:\"left\",bottom:\"top\",top:\"bottom\"};return t.replace(/left|right|bottom|top/g,function(r){return e[r]})}function WA(t,e,r){r=r.split(\"-\")[0];var n=GA(t),i={width:n.width,height:n.height},a=[\"right\",\"left\"].indexOf(r)!==-1,o=a?\"top\":\"left\",s=a?\"left\":\"top\",l=a?\"height\":\"width\",u=a?\"width\":\"height\";return i[o]=e[o]+e[l]/2-n[l]/2,r===s?i[s]=e[s]-n[u]:i[s]=e[bd(s)],i}function Qu(t,e){return Array.prototype.find?t.find(e):t.filter(e)[0]}function V5(t,e,r){if(Array.prototype.findIndex)return t.findIndex(function(i){return i[e]===r});var n=Qu(t,function(i){return i[e]===r});return t.indexOf(n)}function KA(t,e,r){var n=r===void 0?t:t.slice(0,V5(t,\"name\",r));return n.forEach(function(i){i.function&&console.warn(\"`modifier.function` is deprecated, use `modifier.fn`!\");var a=i.function||i.fn;i.enabled&&LA(a)&&(e.offsets.popper=xa(e.offsets.popper),e.offsets.reference=xa(e.offsets.reference),e=a(e,i))}),e}function H5(){if(!this.state.isDestroyed){var t={instance:this,styles:{},arrowStyles:{},attributes:{},flipped:!1,offsets:{}};t.offsets.reference=UA(this.state,this.popper,this.reference,this.options.positionFixed),t.placement=zA(this.options.placement,t.offsets.reference,this.popper,this.reference,this.options.modifiers.flip.boundariesElement,this.options.modifiers.flip.padding),t.originalPlacement=t.placement,t.positionFixed=this.options.positionFixed,t.offsets.popper=WA(this.popper,t.offsets.reference,t.placement),t.offsets.popper.position=this.options.positionFixed?\"fixed\":\"absolute\",t=KA(this.modifiers,t),this.state.isCreated?this.options.onUpdate(t):(this.state.isCreated=!0,this.options.onCreate(t))}}function YA(t,e){return t.some(function(r){var n=r.name,i=r.enabled;return i&&n===e})}function ey(t){for(var e=[!1,\"ms\",\"Webkit\",\"Moz\",\"O\"],r=t.charAt(0).toUpperCase()+t.slice(1),n=0;n<e.length;n++){var i=e[n],a=i?\"\"+i+r:t;if(typeof document.body.style[a]<\"u\")return a}return null}function z5(){return this.state.isDestroyed=!0,YA(this.modifiers,\"applyStyle\")&&(this.popper.removeAttribute(\"x-placement\"),this.popper.style.position=\"\",this.popper.style.top=\"\",this.popper.style.left=\"\",this.popper.style.right=\"\",this.popper.style.bottom=\"\",this.popper.style.willChange=\"\",this.popper.style[ey(\"transform\")]=\"\"),this.disableEventListeners(),this.options.removeOnDestroy&&this.popper.parentNode.removeChild(this.popper),this}function qA(t){var e=t.ownerDocument;return e?e.defaultView:window}function XA(t,e,r,n){var i=t.nodeName===\"BODY\",a=i?t.ownerDocument.defaultView:t;a.addEventListener(e,r,{passive:!0}),i||XA(Zu(a.parentNode),e,r,n),n.push(a)}function U5(t,e,r,n){r.updateBound=n,qA(t).addEventListener(\"resize\",r.updateBound,{passive:!0});var i=Zu(t);return XA(i,\"scroll\",r.updateBound,r.scrollParents),r.scrollElement=i,r.eventsEnabled=!0,r}function G5(){this.state.eventsEnabled||(this.state=U5(this.reference,this.options,this.state,this.scheduleUpdate))}function W5(t,e){return qA(t).removeEventListener(\"resize\",e.updateBound),e.scrollParents.forEach(function(r){r.removeEventListener(\"scroll\",e.updateBound)}),e.updateBound=null,e.scrollParents=[],e.scrollElement=null,e.eventsEnabled=!1,e}function K5(){this.state.eventsEnabled&&(cancelAnimationFrame(this.scheduleUpdate),this.state=W5(this.reference,this.state))}function ty(t){return t!==\"\"&&!isNaN(parseFloat(t))&&isFinite(t)}function og(t,e){Object.keys(e).forEach(function(r){var n=\"\";[\"width\",\"height\",\"top\",\"right\",\"bottom\",\"left\"].indexOf(r)!==-1&&ty(e[r])&&(n=\"px\"),t.style[r]=e[r]+n})}function Y5(t,e){Object.keys(e).forEach(function(r){var n=e[r];n!==!1?t.setAttribute(r,e[r]):t.removeAttribute(r)})}function q5(t){return og(t.instance.popper,t.styles),Y5(t.instance.popper,t.attributes),t.arrowElement&&Object.keys(t.arrowStyles).length&&og(t.arrowElement,t.arrowStyles),t}function X5(t,e,r,n,i){var a=UA(i,e,t,r.positionFixed),o=zA(r.placement,a,e,t,r.modifiers.flip.boundariesElement,r.modifiers.flip.padding);return e.setAttribute(\"x-placement\",o),og(e,{position:r.positionFixed?\"fixed\":\"absolute\"}),r}function J5(t,e){var r=t.offsets,n=r.popper,i=r.reference,a=Math.round,o=Math.floor,s=function(C){return C},l=a(i.width),u=a(n.width),f=[\"left\",\"right\"].indexOf(t.placement)!==-1,d=t.placement.indexOf(\"-\")!==-1,p=l%2===u%2,h=l%2===1&&u%2===1,b=e?f||d||p?a:o:s,y=e?a:s;return{left:b(h&&!d&&e?n.left-1:n.left),top:y(n.top),bottom:y(n.bottom),right:b(n.right)}}var Z5=Ju&&/Firefox/i.test(navigator.userAgent);function Q5(t,e){var r=e.x,n=e.y,i=t.offsets.popper,a=Qu(t.instance.modifiers,function(D){return D.name===\"applyStyle\"}).gpuAcceleration;a!==void 0&&console.warn(\"WARNING: `gpuAcceleration` option moved to `computeStyle` modifier and will not be supported in future versions of Popper.js!\");var o=a!==void 0?a:e.gpuAcceleration,s=ks(t.instance.popper),l=ag(s),u={position:i.position},f=J5(t,window.devicePixelRatio<2||!Z5),d=r===\"bottom\"?\"top\":\"bottom\",p=n===\"right\"?\"left\":\"right\",h=ey(\"transform\"),b=void 0,y=void 0;if(d===\"bottom\"?s.nodeName===\"HTML\"?y=-s.clientHeight+f.bottom:y=-l.height+f.bottom:y=f.top,p===\"right\"?s.nodeName===\"HTML\"?b=-s.clientWidth+f.right:b=-l.width+f.right:b=f.left,o&&h)u[h]=\"translate3d(\"+b+\"px, \"+y+\"px, 0)\",u[d]=0,u[p]=0,u.willChange=\"transform\";else{var P=d===\"bottom\"?-1:1,C=p===\"right\"?-1:1;u[d]=y*P,u[p]=b*C,u.willChange=d+\", \"+p}var R={\"x-placement\":t.placement};return t.attributes=In({},R,t.attributes),t.styles=In({},u,t.styles),t.arrowStyles=In({},t.offsets.arrow,t.arrowStyles),t}function JA(t,e,r){var n=Qu(t,function(s){var l=s.name;return l===e}),i=!!n&&t.some(function(s){return s.name===r&&s.enabled&&s.order<n.order});if(!i){var a=\"`\"+e+\"`\",o=\"`\"+r+\"`\";console.warn(o+\" modifier is required by \"+a+\" modifier in order to work, be sure to include it before \"+a+\"!\")}return i}function ez(t,e){var r;if(!JA(t.instance.modifiers,\"arrow\",\"keepTogether\"))return t;var n=e.element;if(typeof n==\"string\"){if(n=t.instance.popper.querySelector(n),!n)return t}else if(!t.instance.popper.contains(n))return console.warn(\"WARNING: `arrow.element` must be child of its popper element!\"),t;var i=t.placement.split(\"-\")[0],a=t.offsets,o=a.popper,s=a.reference,l=[\"left\",\"right\"].indexOf(i)!==-1,u=l?\"height\":\"width\",f=l?\"Top\":\"Left\",d=f.toLowerCase(),p=l?\"left\":\"top\",h=l?\"bottom\":\"right\",b=GA(n)[u];s[h]-b<o[d]&&(t.offsets.popper[d]-=o[d]-(s[h]-b)),s[d]+b>o[h]&&(t.offsets.popper[d]+=s[d]+b-o[h]),t.offsets.popper=xa(t.offsets.popper);var y=s[d]+s[u]/2-b/2,P=Bo(t.instance.popper),C=parseFloat(P[\"margin\"+f]),R=parseFloat(P[\"border\"+f+\"Width\"]),D=y-t.offsets.popper[d]-C-R;return D=Math.max(Math.min(o[u]-b,D),0),t.arrowElement=n,t.offsets.arrow=(r={},Fs(r,d,Math.round(D)),Fs(r,p,\"\"),r),t}function tz(t){return t===\"end\"?\"start\":t===\"start\"?\"end\":t}var ZA=[\"auto-start\",\"auto\",\"auto-end\",\"top-start\",\"top\",\"top-end\",\"right-start\",\"right\",\"right-end\",\"bottom-end\",\"bottom\",\"bottom-start\",\"left-end\",\"left\",\"left-start\"],pv=ZA.slice(3);function dT(t){var e=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,r=pv.indexOf(t),n=pv.slice(r+1).concat(pv.slice(0,r));return e?n.reverse():n}var hv={FLIP:\"flip\",CLOCKWISE:\"clockwise\",COUNTERCLOCKWISE:\"counterclockwise\"};function rz(t,e){if(YA(t.instance.modifiers,\"inner\")||t.flipped&&t.placement===t.originalPlacement)return t;var r=Qb(t.instance.popper,t.instance.reference,e.padding,e.boundariesElement,t.positionFixed),n=t.placement.split(\"-\")[0],i=bd(n),a=t.placement.split(\"-\")[1]||\"\",o=[];switch(e.behavior){case hv.FLIP:o=[n,i];break;case hv.CLOCKWISE:o=dT(n);break;case hv.COUNTERCLOCKWISE:o=dT(n,!0);break;default:o=e.behavior}return o.forEach(function(s,l){if(n!==s||o.length===l+1)return t;n=t.placement.split(\"-\")[0],i=bd(n);var u=t.offsets.popper,f=t.offsets.reference,d=Math.floor,p=n===\"left\"&&d(u.right)>d(f.left)||n===\"right\"&&d(u.left)<d(f.right)||n===\"top\"&&d(u.bottom)>d(f.top)||n===\"bottom\"&&d(u.top)<d(f.bottom),h=d(u.left)<d(r.left),b=d(u.right)>d(r.right),y=d(u.top)<d(r.top),P=d(u.bottom)>d(r.bottom),C=n===\"left\"&&h||n===\"right\"&&b||n===\"top\"&&y||n===\"bottom\"&&P,R=[\"top\",\"bottom\"].indexOf(n)!==-1,D=!!e.flipVariations&&(R&&a===\"start\"&&h||R&&a===\"end\"&&b||!R&&a===\"start\"&&y||!R&&a===\"end\"&&P),B=!!e.flipVariationsByContent&&(R&&a===\"start\"&&b||R&&a===\"end\"&&h||!R&&a===\"start\"&&P||!R&&a===\"end\"&&y),A=D||B;(p||C||A)&&(t.flipped=!0,(p||C)&&(n=o[l+1]),A&&(a=tz(a)),t.placement=n+(a?\"-\"+a:\"\"),t.offsets.popper=In({},t.offsets.popper,WA(t.instance.popper,t.offsets.reference,t.placement)),t=KA(t.instance.modifiers,t,\"flip\"))}),t}function nz(t){var e=t.offsets,r=e.popper,n=e.reference,i=t.placement.split(\"-\")[0],a=Math.floor,o=[\"top\",\"bottom\"].indexOf(i)!==-1,s=o?\"right\":\"bottom\",l=o?\"left\":\"top\",u=o?\"width\":\"height\";return r[s]<a(n[l])&&(t.offsets.popper[l]=a(n[l])-r[u]),r[l]>a(n[s])&&(t.offsets.popper[l]=a(n[s])),t}function iz(t,e,r,n){var i=t.match(/((?:\\-|\\+)?\\d*\\.?\\d*)(.*)/),a=+i[1],o=i[2];if(!a)return t;if(o.indexOf(\"%\")===0){var s=void 0;switch(o){case\"%p\":s=r;break;case\"%\":case\"%r\":default:s=n}var l=xa(s);return l[e]/100*a}else if(o===\"vh\"||o===\"vw\"){var u=void 0;return o===\"vh\"?u=Math.max(document.documentElement.clientHeight,window.innerHeight||0):u=Math.max(document.documentElement.clientWidth,window.innerWidth||0),u/100*a}else return a}function az(t,e,r,n){var i=[0,0],a=[\"right\",\"left\"].indexOf(n)!==-1,o=t.split(/(\\+|\\-)/).map(function(f){return f.trim()}),s=o.indexOf(Qu(o,function(f){return f.search(/,|\\s/)!==-1}));o[s]&&o[s].indexOf(\",\")===-1&&console.warn(\"Offsets separated by white space(s) are deprecated, use a comma (,) instead.\");var l=/\\s*,\\s*|\\s+/,u=s!==-1?[o.slice(0,s).concat([o[s].split(l)[0]]),[o[s].split(l)[1]].concat(o.slice(s+1))]:[o];return u=u.map(function(f,d){var p=(d===1?!a:a)?\"height\":\"width\",h=!1;return f.reduce(function(b,y){return b[b.length-1]===\"\"&&[\"+\",\"-\"].indexOf(y)!==-1?(b[b.length-1]=y,h=!0,b):h?(b[b.length-1]+=y,h=!1,b):b.concat(y)},[]).map(function(b){return iz(b,p,e,r)})}),u.forEach(function(f,d){f.forEach(function(p,h){ty(p)&&(i[d]+=p*(f[h-1]===\"-\"?-1:1))})}),i}function oz(t,e){var r=e.offset,n=t.placement,i=t.offsets,a=i.popper,o=i.reference,s=n.split(\"-\")[0],l=void 0;return ty(+r)?l=[+r,0]:l=az(r,a,o,s),s===\"left\"?(a.top+=l[0],a.left-=l[1]):s===\"right\"?(a.top+=l[0],a.left+=l[1]):s===\"top\"?(a.left+=l[0],a.top-=l[1]):s===\"bottom\"&&(a.left+=l[0],a.top+=l[1]),t.popper=a,t}function sz(t,e){var r=e.boundariesElement||ks(t.instance.popper);t.instance.reference===r&&(r=ks(r));var n=ey(\"transform\"),i=t.instance.popper.style,a=i.top,o=i.left,s=i[n];i.top=\"\",i.left=\"\",i[n]=\"\";var l=Qb(t.instance.popper,t.instance.reference,e.padding,r,t.positionFixed);i.top=a,i.left=o,i[n]=s,e.boundaries=l;var u=e.priority,f=t.offsets.popper,d={primary:function(h){var b=f[h];return f[h]<l[h]&&!e.escapeWithReference&&(b=Math.max(f[h],l[h])),Fs({},h,b)},secondary:function(h){var b=h===\"right\"?\"left\":\"top\",y=f[b];return f[h]>l[h]&&!e.escapeWithReference&&(y=Math.min(f[b],l[h]-(h===\"right\"?f.width:f.height))),Fs({},b,y)}};return u.forEach(function(p){var h=[\"left\",\"top\"].indexOf(p)!==-1?\"primary\":\"secondary\";f=In({},f,d[h](p))}),t.offsets.popper=f,t}function lz(t){var e=t.placement,r=e.split(\"-\")[0],n=e.split(\"-\")[1];if(n){var i=t.offsets,a=i.reference,o=i.popper,s=[\"bottom\",\"top\"].indexOf(r)!==-1,l=s?\"left\":\"top\",u=s?\"width\":\"height\",f={start:Fs({},l,a[l]),end:Fs({},l,a[l]+a[u]-o[u])};t.offsets.popper=In({},o,f[n])}return t}function uz(t){if(!JA(t.instance.modifiers,\"hide\",\"preventOverflow\"))return t;var e=t.offsets.reference,r=Qu(t.instance.modifiers,function(n){return n.name===\"preventOverflow\"}).boundaries;if(e.bottom<r.top||e.left>r.right||e.top>r.bottom||e.right<r.left){if(t.hide===!0)return t;t.hide=!0,t.attributes[\"x-out-of-boundaries\"]=\"\"}else{if(t.hide===!1)return t;t.hide=!1,t.attributes[\"x-out-of-boundaries\"]=!1}return t}function cz(t){var e=t.placement,r=e.split(\"-\")[0],n=t.offsets,i=n.popper,a=n.reference,o=[\"left\",\"right\"].indexOf(r)!==-1,s=[\"top\",\"left\"].indexOf(r)===-1;return i[o?\"left\":\"top\"]=a[r]-(s?i[o?\"width\":\"height\"]:0),t.placement=bd(e),t.offsets.popper=xa(i),t}var fz={shift:{order:100,enabled:!0,fn:lz},offset:{order:200,enabled:!0,fn:oz,offset:0},preventOverflow:{order:300,enabled:!0,fn:sz,priority:[\"left\",\"right\",\"top\",\"bottom\"],padding:5,boundariesElement:\"scrollParent\"},keepTogether:{order:400,enabled:!0,fn:nz},arrow:{order:500,enabled:!0,fn:ez,element:\"[x-arrow]\"},flip:{order:600,enabled:!0,fn:rz,behavior:\"flip\",padding:5,boundariesElement:\"viewport\",flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:cz},hide:{order:800,enabled:!0,fn:uz},computeStyle:{order:850,enabled:!0,fn:Q5,gpuAcceleration:!0,x:\"bottom\",y:\"right\"},applyStyle:{order:900,enabled:!0,fn:q5,onLoad:X5,gpuAcceleration:void 0}},dz={placement:\"bottom\",positionFixed:!1,eventsEnabled:!0,removeOnDestroy:!1,onCreate:function(){},onUpdate:function(){},modifiers:fz},yp=function(){function t(e,r){var n=this,i=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};k5(this,t),this.scheduleUpdate=function(){return requestAnimationFrame(n.update)},this.update=N5(this.update.bind(this)),this.options=In({},t.Defaults,i),this.state={isDestroyed:!1,isCreated:!1,scrollParents:[]},this.reference=e&&e.jquery?e[0]:e,this.popper=r&&r.jquery?r[0]:r,this.options.modifiers={},Object.keys(In({},t.Defaults.modifiers,i.modifiers)).forEach(function(o){n.options.modifiers[o]=In({},t.Defaults.modifiers[o]||{},i.modifiers?i.modifiers[o]:{})}),this.modifiers=Object.keys(this.options.modifiers).map(function(o){return In({name:o},n.options.modifiers[o])}).sort(function(o,s){return o.order-s.order}),this.modifiers.forEach(function(o){o.enabled&&LA(o.onLoad)&&o.onLoad(n.reference,n.popper,n.options,o,n.state)}),this.update();var a=this.options.eventsEnabled;a&&this.enableEventListeners(),this.state.eventsEnabled=a}return L5(t,[{key:\"update\",value:function(){return H5.call(this)}},{key:\"destroy\",value:function(){return z5.call(this)}},{key:\"enableEventListeners\",value:function(){return G5.call(this)}},{key:\"disableEventListeners\",value:function(){return K5.call(this)}}]),t}();yp.Utils=(typeof window<\"u\"?window:global).PopperUtils;yp.placements=ZA;yp.Defaults=dz;const sg=yp;var pz=\"top-start\",hz=\"top-end\",vz=\"bottom-start\",mz=\"bottom-end\",gz=\"right-start\",bz=\"left-start\";function yz(t,e){if(!(t instanceof e))throw new TypeError(\"Cannot call a class as a function\")}function pT(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,\"value\"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}function Oz(t,e,r){return e&&pT(t.prototype,e),r&&pT(t,r),Object.defineProperty(t,\"prototype\",{writable:!1}),t}var ko=function(){function t(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};if(yz(this,t),!e)throw new TypeError(\"Failed to construct '\".concat(this.constructor.name,\"'. 1 argument required, \").concat(arguments.length,\" given.\"));Gu(this,t.Defaults,this.constructor.Defaults,r,{type:e}),ip(this,{type:xn(),cancelable:xn(),nativeEvent:xn(),target:xn(),relatedTarget:xn(),vueTarget:xn(),componentId:xn()});var n=!1;this.preventDefault=function(){this.cancelable&&(n=!0)},Cb(this,\"defaultPrevented\",{enumerable:!0,get:function(){return n}})}return Oz(t,null,[{key:\"Defaults\",get:function(){return{type:\"\",cancelable:!0,nativeEvent:null,target:null,relatedTarget:null,vueTarget:null,componentId:null}}}]),t}(),_z=I({data:function(){return{listenForClickOut:!1}},watch:{listenForClickOut:function(e,r){e!==r&&(ft(this.clickOutElement,this.clickOutEventName,this._clickOutHandler,De),e&&it(this.clickOutElement,this.clickOutEventName,this._clickOutHandler,De))}},beforeCreate:function(){this.clickOutElement=null,this.clickOutEventName=null},mounted:function(){this.clickOutElement||(this.clickOutElement=document),this.clickOutEventName||(this.clickOutEventName=\"click\"),this.listenForClickOut&&it(this.clickOutElement,this.clickOutEventName,this._clickOutHandler,De)},beforeDestroy:function(){ft(this.clickOutElement,this.clickOutEventName,this._clickOutHandler,De)},methods:{isClickOut:function(e){return!Rt(this.$el,e.target)},_clickOutHandler:function(e){this.clickOutHandler&&this.isClickOut(e)&&this.clickOutHandler(e)}}}),wz=I({data:function(){return{listenForFocusIn:!1}},watch:{listenForFocusIn:function(e,r){e!==r&&(ft(this.focusInElement,\"focusin\",this._focusInHandler,De),e&&it(this.focusInElement,\"focusin\",this._focusInHandler,De))}},beforeCreate:function(){this.focusInElement=null},mounted:function(){this.focusInElement||(this.focusInElement=document),this.listenForFocusIn&&it(this.focusInElement,\"focusin\",this._focusInHandler,De)},beforeDestroy:function(){ft(this.focusInElement,\"focusin\",this._focusInHandler,De)},methods:{_focusInHandler:function(e){this.focusInHandler&&this.focusInHandler(e)}}}),Bu=null;Nr&&(Bu=new WeakMap);var Tz=function(e,r){!Nr||Bu.set(e,r)},Sz=function(e){!Nr||Bu.delete(e)},Pz=function(e){if(!Nr)return e.__vue__;for(var r=e;r;){if(Bu.has(r))return Bu.get(r);r=r.parentNode}return null};function hT(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function vT(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?hT(Object(r),!0).forEach(function(n){Ez(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):hT(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Ez(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var mT=bt(Co,Dr),$z=bt(Co,Pt),Cz=\".dropdown form\",Dz=[\".dropdown-item\",\".b-dropdown-form\"].map(function(t){return\"\".concat(t,\":not(.disabled):not([disabled])\")}).join(\", \"),Az=function(e){return(e||[]).filter(Yn)},Op=z(ie(vT(vT({},Ke),{},{boundary:c([ba,g],\"scrollParent\"),disabled:c(_,!1),dropleft:c(_,!1),dropright:c(_,!1),dropup:c(_,!1),noFlip:c(_,!1),offset:c(re,0),popperOpts:c(Mt,{}),right:c(_,!1)})),Co),ry=I({mixins:[Ze,Qn,_z,wz],provide:function(){var e=this;return{getBvDropdown:function(){return e}}},inject:{getBvNavbar:{default:function(){return function(){return null}}}},props:Op,data:function(){return{visible:!1,visibleChangePrevented:!1}},computed:{bvNavbar:function(){return this.getBvNavbar()},inNavbar:function(){return!nt(this.bvNavbar)},toggler:function(){var e=this.$refs.toggle;return e?e.$el||e:null},directionClass:function(){return this.dropup?\"dropup\":this.dropright?\"dropright\":this.dropleft?\"dropleft\":\"\"},boundaryClass:function(){return this.boundary!==\"scrollParent\"&&!this.inNavbar?\"position-static\":\"\"},hideDelay:function(){return this.inNavbar?Qf?300:50:0}},watch:{visible:function(e,r){if(this.visibleChangePrevented){this.visibleChangePrevented=!1;return}if(e!==r){var n=e?tr:Xr,i=new ko(n,{cancelable:!0,vueTarget:this,target:this.$refs.menu,relatedTarget:null,componentId:this.safeId?this.safeId():this.id||null});if(this.emitEvent(i),i.defaultPrevented){this.visibleChangePrevented=!0,this.visible=r,this.$off(Pt,this.focusToggler);return}e?this.showMenu():this.hideMenu()}},disabled:function(e,r){e!==r&&e&&this.visible&&(this.visible=!1)}},created:function(){this.$_popper=null,this.$_hideTimeout=null},deactivated:function(){this.visible=!1,this.whileOpenListen(!1),this.destroyPopper()},mounted:function(){Tz(this.$el,this)},beforeDestroy:function(){this.visible=!1,this.whileOpenListen(!1),this.destroyPopper(),this.clearHideTimeout(),Sz(this.$el)},methods:{emitEvent:function(e){var r=e.type;this.emitOnRoot(bt(Co,r),e),this.$emit(r,e)},showMenu:function(){var e=this;if(!this.disabled){if(!this.inNavbar)if(typeof sg>\"u\")jt(\"Popper.js not found. Falling back to CSS positioning\",Co);else{var r=this.dropup&&this.right||this.split?this.$el:this.$refs.toggle;r=r.$el||r,this.createPopper(r)}this.emitOnRoot(mT,this),this.whileOpenListen(!0),this.$nextTick(function(){e.focusMenu(),e.$emit(Dr)})}},hideMenu:function(){this.whileOpenListen(!1),this.emitOnRoot($z,this),this.$emit(Pt),this.destroyPopper()},createPopper:function(e){this.destroyPopper(),this.$_popper=new sg(e,this.$refs.menu,this.getPopperConfig())},destroyPopper:function(){this.$_popper&&this.$_popper.destroy(),this.$_popper=null},updatePopper:function(){try{this.$_popper.scheduleUpdate()}catch{}},clearHideTimeout:function(){clearTimeout(this.$_hideTimeout),this.$_hideTimeout=null},getPopperConfig:function(){var e=vz;this.dropup?e=this.right?hz:pz:this.dropright?e=gz:this.dropleft?e=bz:this.right&&(e=mz);var r={placement:e,modifiers:{offset:{offset:this.offset||0},flip:{enabled:!this.noFlip}}},n=this.boundary;return n&&(r.modifiers.preventOverflow={boundariesElement:n}),AF(r,this.popperOpts||{})},whileOpenListen:function(e){this.listenForClickOut=e,this.listenForFocusIn=e;var r=e?\"listenOnRoot\":\"listenOffRoot\";this[r](mT,this.rootCloseListener)},rootCloseListener:function(e){e!==this&&(this.visible=!1)},show:function(){var e=this;this.disabled||We(function(){e.visible=!0})},hide:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:!1;this.disabled||(this.visible=!1,e&&this.$once(Pt,this.focusToggler))},toggle:function(e){e=e||{};var r=e,n=r.type,i=r.keyCode;if(!(n!==\"click\"&&!(n===\"keydown\"&&[Ji,Ti,Rr].indexOf(i)!==-1))){if(this.disabled){this.visible=!1;return}this.$emit(DD,e),_e(e),this.visible?this.hide(!0):this.show()}},onMousedown:function(e){_e(e,{propagation:!1})},onKeydown:function(e){var r=e.keyCode;r===Fb?this.onEsc(e):r===Rr?this.focusNext(e,!1):r===Zr&&this.focusNext(e,!0)},onEsc:function(e){this.visible&&(this.visible=!1,_e(e),this.$once(Pt,this.focusToggler))},onSplitClick:function(e){if(this.disabled){this.visible=!1;return}this.$emit(Ln,e)},hideHandler:function(e){var r=this,n=e.target;this.visible&&!Rt(this.$refs.menu,n)&&!Rt(this.toggler,n)&&(this.clearHideTimeout(),this.$_hideTimeout=setTimeout(function(){return r.hide()},this.hideDelay))},clickOutHandler:function(e){this.hideHandler(e)},focusInHandler:function(e){this.hideHandler(e)},focusNext:function(e,r){var n=this,i=e.target;!this.visible||e&&Jr(Cz,i)||(_e(e),this.$nextTick(function(){var a=n.getItems();if(!(a.length<1)){var o=a.indexOf(i);r&&o>0?o--:!r&&o<a.length-1&&o++,o<0&&(o=0),n.focusItem(o,a)}}))},focusItem:function(e,r){var n=r.find(function(i,a){return a===e});we(n)},getItems:function(){return Az(yn(Dz,this.$refs.menu))},focusMenu:function(){we(this.$refs.menu)},focusToggler:function(){var e=this;this.$nextTick(function(){we(e.toggler)})}}});function gT(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Mi(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?gT(Object(r),!0).forEach(function(n){Rz(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):gT(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Rz(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var QA=z(ie(Mi(Mi(Mi({},Ke),Op),{},{block:c(_,!1),html:c(g),lazy:c(_,!1),menuClass:c(de),noCaret:c(_,!1),role:c(g,\"menu\"),size:c(g),split:c(_,!1),splitButtonType:c(g,\"button\",function(t){return he([\"button\",\"submit\",\"reset\"],t)}),splitClass:c(de),splitHref:c(g),splitTo:c(ND),splitVariant:c(g),text:c(g),toggleAttrs:c(Mt,{}),toggleClass:c(de),toggleTag:c(g,\"button\"),toggleText:c(g,\"Toggle dropdown\"),variant:c(g,\"secondary\")})),Co),bT=I({name:Co,mixins:[Ze,ry,ve],props:QA,computed:{dropdownClasses:function(){var e=this.block,r=this.split;return[this.directionClass,this.boundaryClass,{show:this.visible,\"btn-group\":r||!e,\"d-flex\":e&&r}]},menuClasses:function(){return[this.menuClass,{\"dropdown-menu-right\":this.right,show:this.visible}]},toggleClasses:function(){var e=this.split;return[this.toggleClass,{\"dropdown-toggle-split\":e,\"dropdown-toggle-no-caret\":this.noCaret&&!e}]}},render:function(e){var r=this.visible,n=this.variant,i=this.size,a=this.block,o=this.disabled,s=this.split,l=this.role,u=this.hide,f=this.toggle,d={variant:n,size:i,block:a,disabled:o},p=this.normalizeSlot(Wi),h=this.hasNormalizedSlot(Wi)?{}:dt(this.html,this.text),b=e();if(s){var y=this.splitTo,P=this.splitHref,C=this.splitButtonType,R=Mi(Mi({},d),{},{variant:this.splitVariant||n});y?R.to=y:P?R.href=P:C&&(R.type=C),b=e(Qr,{class:this.splitClass,attrs:{id:this.safeId(\"_BV_button_\")},props:R,domProps:h,on:{click:this.onSplitClick},ref:\"button\"},p),p=[e(\"span\",{class:[\"sr-only\"]},[this.toggleText])],h={}}var D=[\"menu\",\"listbox\",\"tree\",\"grid\",\"dialog\"],B=e(Qr,{staticClass:\"dropdown-toggle\",class:this.toggleClasses,attrs:Mi(Mi({},this.toggleAttrs),{},{id:this.safeId(\"_BV_toggle_\"),\"aria-haspopup\":D.includes(l)?l:\"false\",\"aria-expanded\":ce(r)}),props:Mi(Mi({},d),{},{tag:this.toggleTag,block:a&&!s}),domProps:h,on:{mousedown:this.onMousedown,click:f,keydown:f},ref:\"toggle\"},p),A=e(\"ul\",{staticClass:\"dropdown-menu\",class:this.menuClasses,attrs:{role:l,tabindex:\"-1\",\"aria-labelledby\":this.safeId(s?\"_BV_button_\":\"_BV_toggle_\")},on:{keydown:this.onKeydown},ref:\"menu\"},[!this.lazy||r?this.normalizeSlot(kt,{hide:u}):e()]);return e(\"div\",{staticClass:\"dropdown b-dropdown\",class:this.dropdownClasses,attrs:{id:this.safeId()}},[b,B,A])}});function yT(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function yd(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?yT(Object(r),!0).forEach(function(n){eR(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):yT(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function eR(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var tR=Pe(ei,[\"event\",\"routerTag\"]),xz=z(ie(yd(yd({},tR),{},{linkClass:c(de),variant:c(g)})),tC),OT=I({name:tC,mixins:[Vt,ve],inject:{getBvDropdown:{default:function(){return function(){return null}}}},inheritAttrs:!1,props:xz,computed:{bvDropdown:function(){return this.getBvDropdown()},computedAttrs:function(){return yd(yd({},this.bvAttrs),{},{role:\"menuitem\"})}},methods:{closeDropdown:function(){var e=this;We(function(){e.bvDropdown&&e.bvDropdown.hide(!0)})},onClick:function(e){this.$emit(Ln,e),this.closeDropdown()}},render:function(e){var r=this.linkClass,n=this.variant,i=this.active,a=this.disabled,o=this.onClick,s=this.bvAttrs;return e(\"li\",{class:s.class,style:s.style,attrs:{role:\"presentation\"}},[e(tn,{staticClass:\"dropdown-item\",class:[r,eR({},\"text-\".concat(n),n&&!(i||a))],props:at(tR,this.$props),attrs:this.computedAttrs,on:{click:o},ref:\"item\"},this.normalizeSlot())])}});function _T(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function wT(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?_T(Object(r),!0).forEach(function(n){lg(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):_T(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function lg(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Mz=z({active:c(_,!1),activeClass:c(g,\"active\"),buttonClass:c(de),disabled:c(_,!1),variant:c(g)},rC),Nc=I({name:rC,mixins:[Vt,ve],inject:{getBvDropdown:{default:function(){return function(){return null}}}},inheritAttrs:!1,props:Mz,computed:{bvDropdown:function(){return this.getBvDropdown()},computedAttrs:function(){return wT(wT({},this.bvAttrs),{},{role:\"menuitem\",type:\"button\",disabled:this.disabled})}},methods:{closeDropdown:function(){this.bvDropdown&&this.bvDropdown.hide(!0)},onClick:function(e){this.$emit(Ln,e),this.closeDropdown()}},render:function(e){var r,n=this.active,i=this.variant,a=this.bvAttrs;return e(\"li\",{class:a.class,style:a.style,attrs:{role:\"presentation\"}},[e(\"button\",{staticClass:\"dropdown-item\",class:[this.buttonClass,(r={},lg(r,this.activeClass,n),lg(r,\"text-\".concat(i),i&&!(n||this.disabled)),r)],attrs:this.computedAttrs,on:{click:this.onClick},ref:\"button\"},this.normalizeSlot())])}});function TT(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function ST(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?TT(Object(r),!0).forEach(function(n){rR(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):TT(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function rR(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Nz=z({id:c(g),tag:c(g,\"header\"),variant:c(g)},eC),PT=I({name:eC,functional:!0,props:Nz,render:function(e,r){var n=r.props,i=r.data,a=r.children,o=n.tag,s=n.variant;return e(\"li\",oe(Pe(i,[\"attrs\"]),{attrs:{role:\"presentation\"}}),[e(o,{staticClass:\"dropdown-header\",class:rR({},\"text-\".concat(s),s),attrs:ST(ST({},i.attrs||{}),{},{id:n.id||null,role:wi(o,\"header\")?null:\"heading\"}),ref:\"header\"},a)])}});function ET(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function $T(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?ET(Object(r),!0).forEach(function(n){Iz(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):ET(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Iz(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Bz=z({tag:c(g,\"hr\")},J$),CT=I({name:J$,functional:!0,props:Bz,render:function(e,r){var n=r.props,i=r.data;return e(\"li\",oe(Pe(i,[\"attrs\"]),{attrs:{role:\"presentation\"}}),[e(n.tag,{staticClass:\"dropdown-divider\",attrs:$T($T({},i.attrs||{}),{},{role:\"separator\",\"aria-orientation\":\"horizontal\"}),ref:\"divider\"})])}}),ny=z({id:c(g),inline:c(_,!1),novalidate:c(_,!1),validated:c(_,!1)},aC),iy=I({name:aC,functional:!0,props:ny,render:function(e,r){var n=r.props,i=r.data,a=r.children;return e(\"form\",oe(i,{class:{\"form-inline\":n.inline,\"was-validated\":n.validated},attrs:{id:n.id,novalidate:n.novalidate}}),a)}});function DT(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Od(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?DT(Object(r),!0).forEach(function(n){kz(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):DT(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function kz(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Lz=z(ie(Od(Od({},ny),{},{disabled:c(_,!1),formClass:c(de)})),Z$),AT=I({name:Z$,functional:!0,props:Lz,render:function(e,r){var n=r.props,i=r.data,a=r.listeners,o=r.children;return e(\"li\",oe(Pe(i,[\"attrs\",\"on\"]),{attrs:{role:\"presentation\"}}),[e(iy,{staticClass:\"b-dropdown-form\",class:[n.formClass,{disabled:n.disabled}],props:n,attrs:Od(Od({},i.attrs||{}),{},{disabled:n.disabled,tabindex:n.disabled?null:\"-1\"}),on:a,ref:\"form\"},o)])}});function Fz(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var jz=z({tag:c(g,\"p\"),textClass:c(de),variant:c(g)},nC),RT=I({name:nC,functional:!0,props:jz,render:function(e,r){var n=r.props,i=r.data,a=r.children,o=n.tag,s=n.textClass,l=n.variant;return e(\"li\",oe(Pe(i,[\"attrs\"]),{attrs:{role:\"presentation\"}}),[e(o,{staticClass:\"b-dropdown-text\",class:[s,Fz({},\"text-\".concat(l),l)],props:n,attrs:i.attrs||{},ref:\"text\"},a)])}});function xT(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function MT(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?xT(Object(r),!0).forEach(function(n){nR(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):xT(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function nR(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Vz=z({ariaDescribedby:c(g),header:c(g),headerClasses:c(de),headerTag:c(g,\"header\"),headerVariant:c(g),id:c(g)},Q$),NT=I({name:Q$,functional:!0,props:Vz,render:function(e,r){var n=r.props,i=r.data,a=r.slots,o=r.scopedSlots,s=n.id,l=n.variant,u=n.header,f=n.headerTag,d=a(),p=o||{},h={},b=s?\"_bv_\".concat(s,\"_group_dd_header\"):null,y=e();return(Ki(Ca,p,d)||u)&&(y=e(f,{staticClass:\"dropdown-header\",class:[n.headerClasses,nR({},\"text-\".concat(l),l)],attrs:{id:b,role:wi(f,\"header\")?null:\"heading\"}},rr(Ca,h,p,d)||u)),e(\"li\",oe(Pe(i,[\"attrs\"]),{attrs:{role:\"presentation\"}}),[y,e(\"ul\",{staticClass:\"list-unstyled\",attrs:MT(MT({},i.attrs||{}),{},{id:s,role:\"group\",\"aria-describedby\":[b,n.ariaDescribedBy].filter(pe).join(\" \").trim()||null})},rr(kt,h,p,d))])}}),ay=ae({components:{BDropdown:bT,BDd:bT,BDropdownItem:OT,BDdItem:OT,BDropdownItemButton:Nc,BDropdownItemBtn:Nc,BDdItemButton:Nc,BDdItemBtn:Nc,BDropdownHeader:PT,BDdHeader:PT,BDropdownDivider:CT,BDdDivider:CT,BDropdownForm:AT,BDdForm:AT,BDropdownText:RT,BDdText:RT,BDropdownGroup:NT,BDdGroup:NT}});function Hz(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var zz=[\"iframe\",\"embed\",\"video\",\"object\",\"img\",\"b-img\",\"b-img-lazy\"],Uz=z({aspect:c(g,\"16by9\"),tag:c(g,\"div\"),type:c(g,\"iframe\",function(t){return he(zz,t)})},iC),Gz=I({name:iC,functional:!0,props:Uz,render:function(e,r){var n=r.props,i=r.data,a=r.children,o=n.aspect;return e(n.tag,{staticClass:\"embed-responsive\",class:Hz({},\"embed-responsive-\".concat(o),o),ref:i.ref},[e(n.type,oe(Pe(i,[\"ref\"]),{staticClass:\"embed-responsive-item\"}),a)])}}),Wz=ae({components:{BEmbed:Gz}}),Kz='Setting prop \"options\" to an object is deprecated. Use the array format instead.',ec=z({disabledField:c(g,\"disabled\"),htmlField:c(g,\"html\"),options:c(Nj,[]),textField:c(g,\"text\"),valueField:c(g,\"value\")},\"formOptionControls\"),_p=I({props:ec,computed:{formOptions:function(){return this.normalizeOptions(this.options)}},methods:{normalizeOption:function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:null;if(yr(e)){var n=ur(e,this.valueField),i=ur(e,this.textField);return{value:Et(n)?r||i:n,text:Cw(String(Et(i)?r:i)),html:ur(e,this.htmlField),disabled:Boolean(ur(e,this.disabledField))}}return{value:r||e,text:Cw(String(e)),disabled:!1}},normalizeOptions:function(e){var r=this;return He(e)?e.map(function(n){return r.normalizeOption(n)}):yr(e)?(jt(Kz,this.$options.name),ge(e).map(function(n){return r.normalizeOption(e[n]||{},n)})):[]}}});function IT(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function BT(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?IT(Object(r),!0).forEach(function(n){Yz(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):IT(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Yz(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var qz=z(ie(BT(BT({},ec),{},{id:c(g,void 0,!0)})),lC),kT=I({name:lC,mixins:[_p,ve],props:qz,render:function(e){var r=this.id,n=this.formOptions.map(function(i,a){var o=i.value,s=i.text,l=i.html,u=i.disabled;return e(\"option\",{attrs:{value:o,disabled:u},domProps:dt(l,s),key:\"option_\".concat(a)})});return e(\"datalist\",{attrs:{id:r}},[n,this.normalizeSlot()])}});function Xz(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Jz=z({id:c(g),inline:c(_,!1),tag:c(g,\"small\"),textVariant:c(g,\"muted\")},TC),_d=I({name:TC,functional:!0,props:Jz,render:function(e,r){var n=r.props,i=r.data,a=r.children;return e(n.tag,oe(i,{class:Xz({\"form-text\":!n.inline},\"text-\".concat(n.textVariant),n.textVariant),attrs:{id:n.id}}),a)}}),Zz=z({ariaLive:c(g),forceShow:c(_,!1),id:c(g),role:c(g),state:c(_,null),tag:c(g,\"div\"),tooltip:c(_,!1)},dC),wd=I({name:dC,functional:!0,props:Zz,render:function(e,r){var n=r.props,i=r.data,a=r.children,o=n.tooltip,s=n.ariaLive,l=n.forceShow===!0||n.state===!1;return e(n.tag,oe(i,{class:{\"d-block\":l,\"invalid-feedback\":!o,\"invalid-tooltip\":o},attrs:{id:n.id||null,role:n.role||null,\"aria-live\":s||null,\"aria-atomic\":s?\"true\":null}}),a)}}),Qz=z({ariaLive:c(g),forceShow:c(_,!1),id:c(g),role:c(g),state:c(_,null),tag:c(g,\"div\"),tooltip:c(_,!1)},EC),iR=I({name:EC,functional:!0,props:Qz,render:function(e,r){var n=r.props,i=r.data,a=r.children,o=n.tooltip,s=n.ariaLive,l=n.forceShow===!0||n.state===!0;return e(n.tag,oe(i,{class:{\"d-block\":l,\"valid-feedback\":!o,\"valid-tooltip\":o},attrs:{id:n.id||null,role:n.role||null,\"aria-live\":s||null,\"aria-atomic\":s?\"true\":null}}),a)}}),e3=z({tag:c(g,\"div\")},mC),Td=I({name:mC,functional:!0,props:e3,render:function(e,r){var n=r.props,i=r.data,a=r.children;return e(n.tag,oe(i,{staticClass:\"form-row\"}),a)}}),t3=ae({components:{BForm:iy,BFormDatalist:kT,BDatalist:kT,BFormText:_d,BFormInvalidFeedback:wd,BFormFeedback:wd,BFormValidFeedback:iR,BFormRow:Td}}),LT=function(e,r){for(var n=0;n<e.length;n++)if(je(e[n],r))return n;return-1},FT=\"input, textarea, select\",ti=z({autofocus:c(_,!1),disabled:c(_,!1),form:c(g),id:c(g),name:c(g),required:c(_,!1)},\"formControls\"),Lo=I({props:ti,mounted:function(){this.handleAutofocus()},activated:function(){this.handleAutofocus()},methods:{handleAutofocus:function(){var e=this;this.$nextTick(function(){We(function(){var r=e.$el;e.autofocus&&Yn(r)&&(Vi(r,FT)||(r=gn(FT,r)),we(r))})})}}}),tc=z({plain:c(_,!1)},\"formControls\"),wp=I({props:tc,computed:{custom:function(){return!this.plain}}}),ri=z({size:c(g)},\"formControls\"),Qi=I({props:ri,computed:{sizeFormClass:function(){return[this.size?\"form-control-\".concat(this.size):null]}}}),ni=z({state:c(_,null)},\"formState\"),Si=I({props:ni,computed:{computedState:function(){return Mn(this.state)?this.state:null},stateClass:function(){var e=this.computedState;return e===!0?\"is-valid\":e===!1?\"is-invalid\":null},computedAriaInvalid:function(){var e=Tt(this).ariaInvalid;return e===!0||e===\"true\"||e===\"\"||this.computedState===!1?\"true\":e}}}),Ic,na;function jT(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function ci(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?jT(Object(r),!0).forEach(function(n){Hr(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):jT(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Hr(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Tp=Nt(\"checked\",{defaultValue:null}),r3=Tp.mixin,n3=Tp.props,Rl=Tp.prop,aR=Tp.event,oy=z(ie(ci(ci(ci(ci(ci(ci(ci({},Ke),n3),ti),ri),ni),tc),{},{ariaLabel:c(g),ariaLabelledby:c(g),button:c(_,!1),buttonVariant:c(g),inline:c(_,!1),value:c(Ns)})),\"formRadioCheckControls\"),oR=I({mixins:[Vt,Ze,r3,ve,Lo,Qi,Si,wp],inheritAttrs:!1,props:oy,data:function(){return{localChecked:this.isGroup?this.bvGroup[Rl]:this[Rl],hasFocus:!1}},computed:{computedLocalChecked:{get:function(){return this.isGroup?this.bvGroup.localChecked:this.localChecked},set:function(e){this.isGroup?this.bvGroup.localChecked=e:this.localChecked=e}},isChecked:function(){return je(this.value,this.computedLocalChecked)},isRadio:function(){return!0},isGroup:function(){return!!this.bvGroup},isBtnMode:function(){return this.isGroup?this.bvGroup.buttons:this.button},isPlain:function(){return this.isBtnMode?!1:this.isGroup?this.bvGroup.plain:this.plain},isCustom:function(){return this.isBtnMode?!1:!this.isPlain},isSwitch:function(){return this.isBtnMode||this.isRadio||this.isPlain?!1:this.isGroup?this.bvGroup.switches:this.switch},isInline:function(){return this.isGroup?this.bvGroup.inline:this.inline},isDisabled:function(){return this.isGroup?this.bvGroup.disabled||this.disabled:this.disabled},isRequired:function(){return this.computedName&&(this.isGroup?this.bvGroup.required:this.required)},computedName:function(){return(this.isGroup?this.bvGroup.groupName:this.name)||null},computedForm:function(){return(this.isGroup?this.bvGroup.form:this.form)||null},computedSize:function(){return(this.isGroup?this.bvGroup.size:this.size)||\"\"},computedState:function(){return this.isGroup?this.bvGroup.computedState:Mn(this.state)?this.state:null},computedButtonVariant:function(){var e=this.buttonVariant;return e||(this.isGroup&&this.bvGroup.buttonVariant?this.bvGroup.buttonVariant:\"secondary\")},buttonClasses:function(){var e,r=this.computedSize;return[\"btn\",\"btn-\".concat(this.computedButtonVariant),(e={},Hr(e,\"btn-\".concat(r),r),Hr(e,\"disabled\",this.isDisabled),Hr(e,\"active\",this.isChecked),Hr(e,\"focus\",this.hasFocus),e)]},computedAttrs:function(){var e=this.isDisabled,r=this.isRequired;return ci(ci({},this.bvAttrs),{},{id:this.safeId(),type:this.isRadio?\"radio\":\"checkbox\",name:this.computedName,form:this.computedForm,disabled:e,required:r,\"aria-required\":r||null,\"aria-label\":this.ariaLabel||null,\"aria-labelledby\":this.ariaLabelledby||null})}},watch:(Ic={},Hr(Ic,Rl,function(){this[\"\".concat(Rl,\"Watcher\")].apply(this,arguments)}),Hr(Ic,\"computedLocalChecked\",function(){this.computedLocalCheckedWatcher.apply(this,arguments)}),Ic),methods:(na={},Hr(na,\"\".concat(Rl,\"Watcher\"),function(e){je(e,this.computedLocalChecked)||(this.computedLocalChecked=e)}),Hr(na,\"computedLocalCheckedWatcher\",function(e,r){je(e,r)||this.$emit(aR,e)}),Hr(na,\"handleChange\",function(e){var r=this,n=e.target.checked,i=this.value,a=n?i:null;this.computedLocalChecked=i,this.$nextTick(function(){r.$emit(en,a),r.isGroup&&r.bvGroup.$emit(en,a)})}),Hr(na,\"handleFocus\",function(e){e.target&&(e.type===\"focus\"?this.hasFocus=!0:e.type===\"blur\"&&(this.hasFocus=!1))}),Hr(na,\"focus\",function(){this.isDisabled||we(this.$refs.input)}),Hr(na,\"blur\",function(){this.isDisabled||rn(this.$refs.input)}),na),render:function(e){var r=this.isRadio,n=this.isBtnMode,i=this.isPlain,a=this.isCustom,o=this.isInline,s=this.isSwitch,l=this.computedSize,u=this.bvAttrs,f=this.normalizeSlot(),d=e(\"input\",{class:[{\"form-check-input\":i,\"custom-control-input\":a,\"position-static\":i&&!f},n?\"\":this.stateClass],directives:[{name:\"model\",value:this.computedLocalChecked}],attrs:this.computedAttrs,domProps:{value:this.value,checked:this.isChecked},on:ci({change:this.handleChange},n?{focus:this.handleFocus,blur:this.handleFocus}:{}),key:\"input\",ref:\"input\"});if(n){var p=e(\"label\",{class:this.buttonClasses},[d,f]);return this.isGroup||(p=e(\"div\",{class:[\"btn-group-toggle\",\"d-inline-block\"]},[p])),p}var h=e();return i&&!f||(h=e(\"label\",{class:{\"form-check-label\":i,\"custom-control-label\":a},attrs:{for:this.safeId()}},f)),e(\"div\",{class:[Hr({\"form-check\":i,\"form-check-inline\":i&&o,\"custom-control\":a,\"custom-control-inline\":a&&o,\"custom-checkbox\":a&&!r&&!s,\"custom-switch\":s,\"custom-radio\":a&&r},\"b-custom-control-\".concat(l),l&&!n),u.class],style:u.style},[d,h])}}),rs;function VT(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function HT(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?VT(Object(r),!0).forEach(function(n){Ss(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):VT(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Ss(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Sd=\"indeterminate\",vv=Ia+Sd,i3=z(ie(HT(HT({},oy),{},(rs={},Ss(rs,Sd,c(_,!1)),Ss(rs,\"switch\",c(_,!1)),Ss(rs,\"uncheckedValue\",c(Ns,!1)),Ss(rs,\"value\",c(Ns,!0)),rs))),oC),gf=I({name:oC,mixins:[oR],inject:{getBvGroup:{from:\"getBvCheckGroup\",default:function(){return function(){return null}}}},props:i3,computed:{bvGroup:function(){return this.getBvGroup()},isChecked:function(){var e=this.value,r=this.computedLocalChecked;return He(r)?LT(r,e)>-1:je(r,e)},isRadio:function(){return!1}},watch:Ss({},Sd,function(t,e){je(t,e)||this.setIndeterminate(t)}),mounted:function(){this.setIndeterminate(this[Sd])},methods:{computedLocalCheckedWatcher:function(e,r){if(!je(e,r)){this.$emit(aR,e);var n=this.$refs.input;n&&this.$emit(vv,n.indeterminate)}},handleChange:function(e){var r=this,n=e.target,i=n.checked,a=n.indeterminate,o=this.value,s=this.uncheckedValue,l=this.computedLocalChecked;if(He(l)){var u=LT(l,o);i&&u<0?l=l.concat(o):!i&&u>-1&&(l=l.slice(0,u).concat(l.slice(u+1)))}else l=i?o:s;this.computedLocalChecked=l,this.$nextTick(function(){r.$emit(en,l),r.isGroup&&r.bvGroup.$emit(en,l),r.$emit(vv,a)})},setIndeterminate:function(e){He(this.computedLocalChecked)&&(e=!1);var r=this.$refs.input;r&&(r.indeterminate=e,this.$emit(vv,e))}}}),a3=z(oy,pC),ug=I({name:pC,mixins:[oR],inject:{getBvGroup:{from:\"getBvRadioGroup\",default:function(){return function(){return null}}}},props:a3,computed:{bvGroup:function(){return this.getBvGroup()}}}),Bc;function zT(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function li(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?zT(Object(r),!0).forEach(function(n){bf(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):zT(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function bf(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var UT=[\"aria-describedby\",\"aria-labelledby\"],Sp=Nt(\"checked\"),o3=Sp.mixin,s3=Sp.props,cg=Sp.prop,l3=Sp.event,sy=z(ie(li(li(li(li(li(li(li(li({},Ke),s3),ti),ec),ri),ni),tc),{},{ariaInvalid:c(_r,!1),buttonVariant:c(g),buttons:c(_,!1),stacked:c(_,!1),validated:c(_,!1)})),\"formRadioCheckGroups\"),sR=I({mixins:[Ze,o3,ve,Lo,_p,Qi,Si,wp],inheritAttrs:!1,props:sy,data:function(){return{localChecked:this[cg]}},computed:{inline:function(){return!this.stacked},groupName:function(){return this.name||this.safeId()},groupClasses:function(){var e=this.inline,r=this.size,n=this.validated,i={\"was-validated\":n};return this.buttons&&(i=[i,\"btn-group-toggle\",bf({\"btn-group\":e,\"btn-group-vertical\":!e},\"btn-group-\".concat(r),r)]),i}},watch:(Bc={},bf(Bc,cg,function(t){je(t,this.localChecked)||(this.localChecked=t)}),bf(Bc,\"localChecked\",function(e,r){je(e,r)||this.$emit(l3,e)}),Bc),render:function(e){var r=this,n=this.isRadioGroup,i=Zn(this.$attrs,UT),a=n?ug:gf,o=this.formOptions.map(function(s,l){var u=\"BV_option_\".concat(l);return e(a,{props:{disabled:s.disabled||!1,id:r.safeId(u),value:s.value},attrs:i,key:u},[e(\"span\",{domProps:dt(s.html,s.text)})])});return e(\"div\",{class:[this.groupClasses,\"bv-no-focus-ring\"],attrs:li(li({},Pe(this.$attrs,UT)),{},{\"aria-invalid\":this.computedAriaInvalid,\"aria-required\":this.required?\"true\":null,id:this.safeId(),role:n?\"radiogroup\":\"group\",tabindex:\"-1\"})},[this.normalizeSlot(Mb),o,this.normalizeSlot()])}}),kc;function GT(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function WT(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?GT(Object(r),!0).forEach(function(n){fg(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):GT(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function fg(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var u3=z(ie(WT(WT({},sy),{},(kc={},fg(kc,cg,c(Ar,[])),fg(kc,\"switches\",c(_,!1)),kc))),sC),mv=I({name:sC,mixins:[sR],provide:function(){var e=this;return{getBvCheckGroup:function(){return e}}},props:u3,computed:{isRadioGroup:function(){return!1}}}),c3=ae({components:{BFormCheckbox:gf,BCheckbox:gf,BCheck:gf,BFormCheckboxGroup:mv,BCheckboxGroup:mv,BCheckGroup:mv}}),Lc=\"__BV_hover_handler__\",lR=\"mouseenter\",f3=\"mouseleave\",d3=function(e){var r=function(i){e(i.type===lR,i)};return r.fn=e,r},KT=function(e,r,n){qn(e,r,lR,n,De),qn(e,r,f3,n,De)},gv=function(e,r){var n=r.value,i=n===void 0?null:n;if(Je){var a=e[Lc],o=se(a),s=!(o&&a.fn===i);o&&s&&(KT(!1,e,a),delete e[Lc]),se(i)&&s&&(e[Lc]=d3(i),KT(!0,e,e[Lc]))}},uR={bind:gv,componentUpdated:gv,unbind:function(e){gv(e,{value:null})}};function YT(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function ns(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?YT(Object(r),!0).forEach(function(n){ms(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):YT(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function ms(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var ly=ie(ns(ns(ns(ns(ns(ns({},Ke),ri),ni),Pe(Op,[\"disabled\"])),Pe(ti,[\"autofocus\"])),{},{buttonOnly:c(_,!1),buttonVariant:c(g,\"secondary\"),formattedValue:c(g),labelSelected:c(g),lang:c(g),menuClass:c(de),placeholder:c(g),readonly:c(_,!1),rtl:c(_,null),value:c(g,\"\")})),cR=I({name:QF,directives:{\"b-hover\":uR},mixins:[Ze,Qi,Si,ry,ve],props:ly,data:function(){return{isHovered:!1,hasFocus:!1}},computed:{idButton:function(){return this.safeId()},idLabel:function(){return this.safeId(\"_value_\")},idMenu:function(){return this.safeId(\"_dialog_\")},idWrapper:function(){return this.safeId(\"_outer_\")},computedDir:function(){return this.rtl===!0?\"rtl\":this.rtl===!1?\"ltr\":null}},methods:{focus:function(){this.disabled||we(this.$refs.toggle)},blur:function(){this.disabled||rn(this.$refs.toggle)},setFocus:function(e){this.hasFocus=e.type===\"focus\"},handleHover:function(e){this.isHovered=e}},render:function(e){var r,n=this.idButton,i=this.idLabel,a=this.idMenu,o=this.idWrapper,s=this.disabled,l=this.readonly,u=this.required,f=this.name,d=this.state,p=this.visible,h=this.size,b=this.isHovered,y=this.hasFocus,P=this.labelSelected,C=this.buttonVariant,R=this.buttonOnly,D=ce(this.value)||\"\",B=d===!1||u&&!D,A={isHovered:b,hasFocus:y,state:d,opened:p},V=e(\"button\",{staticClass:\"btn\",class:(r={},ms(r,\"btn-\".concat(C),R),ms(r,\"btn-\".concat(h),h),ms(r,\"h-auto\",!R),ms(r,\"dropdown-toggle\",R),ms(r,\"dropdown-toggle-no-caret\",R),r),attrs:{id:n,type:\"button\",disabled:s,\"aria-haspopup\":\"dialog\",\"aria-expanded\":p?\"true\":\"false\",\"aria-invalid\":B?\"true\":null,\"aria-required\":u?\"true\":null},directives:[{name:\"b-hover\",value:this.handleHover}],on:{mousedown:this.onMousedown,click:this.toggle,keydown:this.toggle,\"!focus\":this.setFocus,\"!blur\":this.setFocus},ref:\"toggle\"},[this.hasNormalizedSlot(Wi)?this.normalizeSlot(Wi,A):e(vV,{props:{scale:1.25}})]),N=e();f&&!s&&(N=e(\"input\",{attrs:{type:\"hidden\",name:f||null,form:this.form||null,value:D}}));var G=e(\"div\",{staticClass:\"dropdown-menu\",class:[this.menuClass,{show:p,\"dropdown-menu-right\":this.right}],attrs:{id:a,role:\"dialog\",tabindex:\"-1\",\"aria-modal\":\"false\",\"aria-labelledby\":i},on:{keydown:this.onKeydown},ref:\"menu\"},[this.normalizeSlot(kt,{opened:p})]),H=e(\"label\",{class:R?\"sr-only\":[\"form-control\",{\"text-muted\":!D},this.stateClass,this.sizeFormClass],attrs:{id:i,for:n,\"aria-invalid\":B?\"true\":null,\"aria-required\":u?\"true\":null},directives:[{name:\"b-hover\",value:this.handleHover}],on:{\"!click\":function(j){_e(j,{preventDefault:!1})}}},[D?this.formattedValue||D:this.placeholder||\"\",D&&P?e(\"bdi\",{staticClass:\"sr-only\"},P):\"\"]);return e(\"div\",{staticClass:\"b-form-btn-label-control dropdown\",class:[this.directionClass,this.boundaryClass,[{\"btn-group\":R,\"form-control\":!R,focus:y&&!R,show:p,\"is-valid\":d===!0,\"is-invalid\":d===!1},R?null:this.sizeFormClass]],attrs:{id:o,role:R?null:\"group\",lang:this.lang||null,dir:this.computedDir,\"aria-disabled\":s,\"aria-readonly\":l&&!s,\"aria-labelledby\":i,\"aria-invalid\":d===!1||u&&!D?\"true\":null,\"aria-required\":u?\"true\":null}},[V,N,G,H])}}),xl;function qT(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Ni(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?qT(Object(r),!0).forEach(function(n){Ql(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):qT(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Ql(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Pp=Nt(\"value\",{type:ho}),p3=Pp.mixin,h3=Pp.props,XT=Pp.prop,v3=Pp.event,fR=Pe(mA,[\"block\",\"hidden\",\"id\",\"noKeyNav\",\"roleDescription\",\"value\",\"width\"]),dR=Pe(ly,[\"formattedValue\",\"id\",\"lang\",\"rtl\",\"value\"]),m3=z(ie(Ni(Ni(Ni(Ni(Ni({},Ke),h3),fR),dR),{},{calendarWidth:c(g,\"270px\"),closeButton:c(_,!1),closeButtonVariant:c(g,\"outline-secondary\"),dark:c(_,!1),labelCloseButton:c(g,\"Close\"),labelResetButton:c(g,\"Reset\"),labelTodayButton:c(g,\"Select today\"),noCloseOnSelect:c(_,!1),resetButton:c(_,!1),resetButtonVariant:c(g,\"outline-danger\"),resetValue:c(ho),todayButton:c(_,!1),todayButtonVariant:c(g,\"outline-primary\")})),uC),JT=I({name:uC,mixins:[Ze,p3],props:m3,data:function(){return{localYMD:rt(this[XT])||\"\",isVisible:!1,localLocale:null,isRTL:!1,formattedValue:\"\",activeYMD:\"\"}},computed:{calendarYM:function(){return this.activeYMD.slice(0,-3)},computedLang:function(){return(this.localLocale||\"\").replace(/-u-.*$/i,\"\")||null},computedResetValue:function(){return rt(pd(this.resetValue))||\"\"}},watch:(xl={},Ql(xl,XT,function(t){this.localYMD=rt(t)||\"\"}),Ql(xl,\"localYMD\",function(e){this.isVisible&&this.$emit(v3,this.valueAsDate?At(e)||null:e||\"\")}),Ql(xl,\"calendarYM\",function(e,r){if(e!==r&&r)try{this.$refs.control.updatePopper()}catch{}}),xl),methods:{focus:function(){this.disabled||we(this.$refs.control)},blur:function(){this.disabled||rn(this.$refs.control)},setAndClose:function(e){var r=this;this.localYMD=e,this.noCloseOnSelect||this.$nextTick(function(){r.$refs.control.hide(!0)})},onSelected:function(e){var r=this;this.$nextTick(function(){r.setAndClose(e)})},onInput:function(e){this.localYMD!==e&&(this.localYMD=e)},onContext:function(e){var r=e.activeYMD,n=e.isRTL,i=e.locale,a=e.selectedYMD,o=e.selectedFormatted;this.isRTL=n,this.localLocale=i,this.formattedValue=o,this.localYMD=a,this.activeYMD=r,this.$emit(Ms,e)},onTodayButton:function(){this.setAndClose(rt(pd(Jt(),this.min,this.max)))},onResetButton:function(){this.setAndClose(this.computedResetValue)},onCloseButton:function(){this.$refs.control.hide(!0)},onShow:function(){this.isVisible=!0},onShown:function(){var e=this;this.$nextTick(function(){we(e.$refs.calendar),e.$emit(Dr)})},onHidden:function(){this.isVisible=!1,this.$emit(Pt)},defaultButtonFn:function(e){var r=e.isHovered,n=e.hasFocus;return this.$createElement(r||n?hV:pV,{attrs:{\"aria-hidden\":\"true\"}})}},render:function(e){var r=this.localYMD,n=this.disabled,i=this.readonly,a=this.dark,o=this.$props,s=this.$scopedSlots,l=Ge(this.placeholder)?this.labelNoDateSelected:this.placeholder,u=[];if(this.todayButton){var f=this.labelTodayButton;u.push(e(Qr,{props:{disabled:n||i,size:\"sm\",variant:this.todayButtonVariant},attrs:{\"aria-label\":f||null},on:{click:this.onTodayButton}},f))}if(this.resetButton){var d=this.labelResetButton;u.push(e(Qr,{props:{disabled:n||i,size:\"sm\",variant:this.resetButtonVariant},attrs:{\"aria-label\":d||null},on:{click:this.onResetButton}},d))}if(this.closeButton){var p=this.labelCloseButton;u.push(e(Qr,{props:{disabled:n,size:\"sm\",variant:this.closeButtonVariant},attrs:{\"aria-label\":p||null},on:{click:this.onCloseButton}},p))}u.length>0&&(u=[e(\"div\",{staticClass:\"b-form-date-controls d-flex flex-wrap\",class:{\"justify-content-between\":u.length>1,\"justify-content-end\":u.length<2}},u)]);var h=e(gA,{staticClass:\"b-form-date-calendar w-100\",props:Ni(Ni({},at(fR,o)),{},{hidden:!this.isVisible,value:r,valueAsDate:!1,width:this.calendarWidth}),on:{selected:this.onSelected,input:this.onInput,context:this.onContext},scopedSlots:Zn(s,[\"nav-prev-decade\",\"nav-prev-year\",\"nav-prev-month\",\"nav-this-month\",\"nav-next-month\",\"nav-next-year\",\"nav-next-decade\"]),key:\"calendar\",ref:\"calendar\"},u);return e(cR,{staticClass:\"b-form-datepicker\",props:Ni(Ni({},at(dR,o)),{},{formattedValue:r?this.formattedValue:\"\",id:this.safeId(),lang:this.computedLang,menuClass:[{\"bg-dark\":a,\"text-light\":a},this.menuClass],placeholder:l,rtl:this.isRTL,value:r}),on:{show:this.onShow,shown:this.onShown,hidden:this.onHidden},scopedSlots:Ql({},Wi,s[Wi]||this.defaultButtonFn),ref:\"control\"},[h])}}),g3=ae({components:{BFormDatepicker:JT,BDatepicker:JT}}),Fc;function ZT(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Ri(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?ZT(Object(r),!0).forEach(function(n){yf(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):ZT(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function yf(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Ep=Nt(\"value\",{type:[Ar,_$],defaultValue:null,validator:function(e){return e===\"\"?(jt(w3,Ab),!0):Ge(e)||T3(e)}}),b3=Ep.mixin,y3=Ep.props,O3=Ep.prop,_3=Ep.event,w3='Setting \"value\"/\"v-model\" to an empty string for reset is deprecated. Set to \"null\" instead.',T3=function t(e){return $F(e)||He(e)&&e.every(function(r){return t(r)})},pR=function(e){return se(e.getAsEntry)?e.getAsEntry():se(e.webkitGetAsEntry)?e.webkitGetAsEntry():null},S3=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0;return Promise.all(Ao(e).filter(function(n){return n.kind===\"file\"}).map(function(n){var i=pR(n);if(i){if(i.isDirectory&&r)return P3(i.createReader(),\"\".concat(i.name,\"/\"));if(i.isFile)return new Promise(function(a){i.file(function(o){o.$path=\"\",a(o)})})}return null}).filter(pe))},P3=function t(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:\"\";return new Promise(function(n){var i=[],a=function o(){e.readEntries(function(s){s.length===0?n(Promise.all(i).then(function(l){return E2(l)})):(i.push(Promise.all(s.map(function(l){if(l){if(l.isDirectory)return t(l.createReader(),\"\".concat(r).concat(l.name,\"/\"));if(l.isFile)return new Promise(function(u){l.file(function(f){f.$path=\"\".concat(r).concat(f.name),u(f)})})}return null}).filter(pe))),o())})};a()})},E3=z(ie(Ri(Ri(Ri(Ri(Ri(Ri(Ri({},Ke),y3),ti),tc),ni),ri),{},{accept:c(g,\"\"),browseText:c(g,\"Browse\"),capture:c(_,!1),directory:c(_,!1),dropPlaceholder:c(g,\"Drop files here\"),fileNameFormatter:c(xr),multiple:c(_,!1),noDrop:c(_,!1),noDropPlaceholder:c(g,\"Not allowed\"),noTraverse:c(_,!1),placeholder:c(g,\"No file chosen\")})),Ab),QT=I({name:Ab,mixins:[Vt,Ze,b3,ve,Lo,Si,wp,ve],inheritAttrs:!1,props:E3,data:function(){return{files:[],dragging:!1,dropAllowed:!this.noDrop,hasFocus:!1}},computed:{computedAccept:function(){var e=this.accept;return e=(e||\"\").trim().split(/[,\\s]+/).filter(pe),e.length===0?null:e.map(function(r){var n=\"name\",i=\"^\",a=\"$\";ZL.test(r)?i=\"\":(n=\"type\",sF.test(r)&&(a=\".+$\",r=r.slice(0,-1))),r=Ib(r);var o=new RegExp(\"\".concat(i).concat(r).concat(a));return{rx:o,prop:n}})},computedCapture:function(){var e=this.capture;return e===!0||e===\"\"?!0:e||null},computedAttrs:function(){var e=this.name,r=this.disabled,n=this.required,i=this.form,a=this.computedCapture,o=this.accept,s=this.multiple,l=this.directory;return Ri(Ri({},this.bvAttrs),{},{type:\"file\",id:this.safeId(),name:e,disabled:r,required:n,form:i||null,capture:a,accept:o||null,multiple:s,directory:l,webkitdirectory:l,\"aria-required\":n?\"true\":null})},computedFileNameFormatter:function(){var e=this.fileNameFormatter;return yi(e)?e:this.defaultFileNameFormatter},clonedFiles:function(){return Nn(this.files)},flattenedFiles:function(){return Cl(this.files)},fileNames:function(){return this.flattenedFiles.map(function(e){return e.name})},labelContent:function(){if(this.dragging&&!this.noDrop)return this.normalizeSlot(Uj,{allowed:this.dropAllowed})||(this.dropAllowed?this.dropPlaceholder:this.$createElement(\"span\",{staticClass:\"text-danger\"},this.noDropPlaceholder));if(this.files.length===0)return this.normalizeSlot(b2)||this.placeholder;var e=this.flattenedFiles,r=this.clonedFiles,n=this.fileNames,i=this.computedFileNameFormatter;return this.hasNormalizedSlot(z_)?this.normalizeSlot(z_,{files:e,filesTraversed:r,names:n}):i(e,r,n)}},watch:(Fc={},yf(Fc,O3,function(t){(!t||He(t)&&t.length===0)&&this.reset()}),yf(Fc,\"files\",function(e,r){if(!je(e,r)){var n=this.multiple,i=this.noTraverse,a=!n||i?Cl(e):e;this.$emit(_3,n?a:a[0]||null)}}),Fc),created:function(){this.$_form=null},mounted:function(){var e=Jr(\"form\",this.$el);e&&(it(e,\"reset\",this.reset,Yr),this.$_form=e)},beforeDestroy:function(){var e=this.$_form;e&&ft(e,\"reset\",this.reset,Yr)},methods:{isFileValid:function(e){if(!e)return!1;var r=this.computedAccept;return r?r.some(function(n){return n.rx.test(e[n.prop])}):!0},isFilesArrayValid:function(e){var r=this;return He(e)?e.every(function(n){return r.isFileValid(n)}):this.isFileValid(e)},defaultFileNameFormatter:function(e,r,n){return n.join(\", \")},setFiles:function(e){this.dropAllowed=!this.noDrop,this.dragging=!1,this.files=this.multiple?this.directory?e:Cl(e):Cl(e).slice(0,1)},setInputFiles:function(e){try{var r=new ClipboardEvent(\"\").clipboardData||new DataTransfer;Cl(Nn(e)).forEach(function(n){delete n.$path,r.items.add(n)}),this.$refs.input.files=r.files}catch{}},reset:function(){try{var e=this.$refs.input;e.value=\"\",e.type=\"\",e.type=\"file\"}catch{}this.files=[]},handleFiles:function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;if(r){var n=e.filter(this.isFilesArrayValid);n.length>0&&(this.setFiles(n),this.setInputFiles(n))}else this.setFiles(e)},focusHandler:function(e){this.plain||e.type===\"focusout\"?this.hasFocus=!1:this.hasFocus=!0},onChange:function(e){var r=this,n=e.type,i=e.target,a=e.dataTransfer,o=a===void 0?{}:a,s=n===\"drop\";this.$emit(en,e);var l=Ao(o.items||[]);if(h$&&l.length>0&&!nt(pR(l[0])))S3(l,this.directory).then(function(f){return r.handleFiles(f,s)});else{var u=Ao(i.files||o.files||[]).map(function(f){return f.$path=f.webkitRelativePath||\"\",f});this.handleFiles(u,s)}},onDragenter:function(e){_e(e),this.dragging=!0;var r=e.dataTransfer,n=r===void 0?{}:r;if(this.noDrop||this.disabled||!this.dropAllowed){n.dropEffect=\"none\",this.dropAllowed=!1;return}n.dropEffect=\"copy\"},onDragover:function(e){_e(e),this.dragging=!0;var r=e.dataTransfer,n=r===void 0?{}:r;if(this.noDrop||this.disabled||!this.dropAllowed){n.dropEffect=\"none\",this.dropAllowed=!1;return}n.dropEffect=\"copy\"},onDragleave:function(e){var r=this;_e(e),this.$nextTick(function(){r.dragging=!1,r.dropAllowed=!r.noDrop})},onDrop:function(e){var r=this;if(_e(e),this.dragging=!1,this.noDrop||this.disabled||!this.dropAllowed){this.$nextTick(function(){r.dropAllowed=!r.noDrop});return}this.onChange(e)}},render:function(e){var r=this.custom,n=this.plain,i=this.size,a=this.dragging,o=this.stateClass,s=this.bvAttrs,l=e(\"input\",{class:[{\"form-control-file\":n,\"custom-file-input\":r,focus:r&&this.hasFocus},o],style:r?{zIndex:-5}:{},attrs:this.computedAttrs,on:{change:this.onChange,focusin:this.focusHandler,focusout:this.focusHandler,reset:this.reset},ref:\"input\"});if(n)return l;var u=e(\"label\",{staticClass:\"custom-file-label\",class:{dragging:a},attrs:{for:this.safeId(),\"data-browse\":this.browseText||null}},[e(\"span\",{staticClass:\"d-block form-file-text\",style:{pointerEvents:\"none\"}},[this.labelContent])]);return e(\"div\",{staticClass:\"custom-file b-form-file\",class:[yf({},\"b-custom-control-\".concat(i),i),o,s.class],style:s.style,attrs:{id:this.safeId(\"_BV_file_outer_\")},on:{dragenter:this.onDragenter,dragover:this.onDragover,dragleave:this.onDragleave,drop:this.onDrop}},[l,u])}}),$3=ae({components:{BFormFile:QT,BFile:QT}}),bv=function(e){return\"\\\\\"+e},hR=function(e){e=ce(e);var r=e.length,n=e.charCodeAt(0);return e.split(\"\").reduce(function(i,a,o){var s=e.charCodeAt(o);return s===0?i+\"\\uFFFD\":s===127||s>=1&&s<=31||o===0&&s>=48&&s<=57||o===1&&s>=48&&s<=57&&n===45?i+bv(\"\".concat(s.toString(16),\" \")):o===0&&s===45&&r===1?i+bv(a):s>=128||s===45||s===95||s>=48&&s<=57||s>=65&&s<=90||s>=97&&s<=122?i+a:i+bv(a)},\"\")};function eS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function jc(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?eS(Object(r),!0).forEach(function(n){eu(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):eS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function eu(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var C3=[\"auto\",\"start\",\"end\",\"center\",\"baseline\",\"stretch\"],D3=function(e,r,n){var i=e;if(!(Ge(n)||n===!1))return r&&(i+=\"-\".concat(r)),e===\"col\"&&(n===\"\"||n===!0)||(i+=\"-\".concat(n)),od(i)},A3=Ku(D3),dg=va(null),R3=function(){var e=xu().filter(pe),r=e.reduce(function(a,o){return a[o]=c(Au),a},va(null)),n=e.reduce(function(a,o){return a[Oa(o,\"offset\")]=c(re),a},va(null)),i=e.reduce(function(a,o){return a[Oa(o,\"order\")]=c(re),a},va(null));return dg=Gu(va(null),{col:ge(r),offset:ge(n),order:ge(i)}),z(ie(jc(jc(jc(jc({},r),n),i),{},{alignSelf:c(g,null,function(a){return he(C3,a)}),col:c(_,!1),cols:c(re),offset:c(re),order:c(re),tag:c(g,\"div\")})),q$)},Of={name:q$,functional:!0,get props(){return delete this.props,this.props=R3()},render:function(e,r){var n,i=r.props,a=r.data,o=r.children,s=i.cols,l=i.offset,u=i.order,f=i.alignSelf,d=[];for(var p in dg)for(var h=dg[p],b=0;b<h.length;b++){var y=A3(p,h[b].replace(p,\"\"),i[h[b]]);y&&d.push(y)}var P=d.some(function(C){return OF.test(C)});return d.push((n={col:i.col||!P&&!s},eu(n,\"col-\".concat(s),s),eu(n,\"offset-\".concat(l),l),eu(n,\"order-\".concat(u),u),eu(n,\"align-self-\".concat(f),f),n)),e(i.tag,oe(a,{class:d}),o)}};function tS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Ps(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?tS(Object(r),!0).forEach(function(n){x3(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):tS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function x3(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var vR=[\"input\",\"select\",\"textarea\"],M3=vR.map(function(t){return\"\".concat(t,\":not([disabled])\")}).join(),N3=[].concat(vR,[\"a\",\"button\",\"label\"]),I3=function(){return z(ie(Ps(Ps(Ps(Ps({},Ke),ni),xu().reduce(function(e,r){return e[Oa(r,\"contentCols\")]=c(Au),e[Oa(r,\"labelAlign\")]=c(g),e[Oa(r,\"labelCols\")]=c(Au),e},va(null))),{},{description:c(g),disabled:c(_,!1),feedbackAriaLive:c(g,\"assertive\"),invalidFeedback:c(g),label:c(g),labelClass:c(de),labelFor:c(g),labelSize:c(g),labelSrOnly:c(_,!1),tooltip:c(_,!1),validFeedback:c(g),validated:c(_,!1)})),cC)},rS={name:cC,mixins:[Ze,Si,ve],get props(){return delete this.props,this.props=I3()},data:function(){return{ariaDescribedby:null}},computed:{contentColProps:function(){return this.getColProps(this.$props,\"content\")},labelAlignClasses:function(){return this.getAlignClasses(this.$props,\"label\")},labelColProps:function(){return this.getColProps(this.$props,\"label\")},isHorizontal:function(){return ge(this.contentColProps).length>0||ge(this.labelColProps).length>0}},watch:{ariaDescribedby:function(e,r){e!==r&&this.updateAriaDescribedby(e,r)}},mounted:function(){var e=this;this.$nextTick(function(){e.updateAriaDescribedby(e.ariaDescribedby)})},methods:{getAlignClasses:function(e,r){return xu().reduce(function(n,i){var a=e[Oa(i,\"\".concat(r,\"Align\"))]||null;return a&&n.push([\"text\",i,a].filter(pe).join(\"-\")),n},[])},getColProps:function(e,r){return xu().reduce(function(n,i){var a=e[Oa(i,\"\".concat(r,\"Cols\"))];return a=a===\"\"?!0:a||!1,!Mn(a)&&a!==\"auto\"&&(a=ee(a,0),a=a>0?a:!1),a&&(n[i||(Mn(a)?\"col\":\"cols\")]=a),n},{})},updateAriaDescribedby:function(e,r){var n=this.labelFor;if(Je&&n){var i=gn(\"#\".concat(hR(n)),this.$refs.content);if(i){var a=\"aria-describedby\",o=(e||\"\").split(sf),s=(r||\"\").split(sf),l=(bn(i,a)||\"\").split(sf).filter(function(u){return!he(s,u)}).concat(o).filter(function(u,f,d){return d.indexOf(u)===f}).filter(pe).join(\" \").trim();l?st(i,a,l):vi(i,a)}}},onLegendClick:function(e){if(!this.labelFor){var r=e.target,n=r?r.tagName:\"\";if(N3.indexOf(n)===-1){var i=yn(M3,this.$refs.content).filter(Yn);i.length===1&&we(i[0])}}}},render:function(e){var r=this.computedState,n=this.feedbackAriaLive,i=this.isHorizontal,a=this.labelFor,o=this.normalizeSlot,s=this.safeId,l=this.tooltip,u=s(),f=!a,d=e(),p=o(BD)||this.label,h=p?s(\"_BV_label_\"):null;if(p||i){var b=this.labelSize,y=this.labelColProps,P=f?\"legend\":\"label\";this.labelSrOnly?(p&&(d=e(P,{class:\"sr-only\",attrs:{id:h,for:a||null}},[p])),d=e(i?Of:\"div\",{props:i?y:{}},[d])):d=e(i?Of:P,{on:f?{click:this.onLegendClick}:{},props:i?Ps(Ps({},y),{},{tag:P}):{},attrs:{id:h,for:a||null,tabindex:f?\"-1\":null},class:[f?\"bv-no-focus-ring\":\"\",i||f?\"col-form-label\":\"\",!i&&f?\"pt-0\":\"\",!i&&!f?\"d-block\":\"\",b?\"col-form-label-\".concat(b):\"\",this.labelAlignClasses,this.labelClass]},[p])}var C=e(),R=o(t2)||this.invalidFeedback,D=R?s(\"_BV_feedback_invalid_\"):null;R&&(C=e(wd,{props:{ariaLive:n,id:D,state:r,tooltip:l},attrs:{tabindex:R?\"-1\":null}},[R]));var B=e(),A=o(P2)||this.validFeedback,V=A?s(\"_BV_feedback_valid_\"):null;A&&(B=e(iR,{props:{ariaLive:n,id:V,state:r,tooltip:l},attrs:{tabindex:A?\"-1\":null}},[A]));var N=e(),G=o(Hj)||this.description,H=G?s(\"_BV_description_\"):null;G&&(N=e(_d,{attrs:{id:H,tabindex:\"-1\"}},[G]));var W=this.ariaDescribedby=[H,r===!1?D:null,r===!0?V:null].filter(pe).join(\" \")||null,j=e(i?Of:\"div\",{props:i?this.contentColProps:{},ref:\"content\"},[o(kt,{ariaDescribedby:W,descriptionId:H,id:u,labelId:h})||e(),C,B,N]);return e(f?\"fieldset\":i?Td:\"div\",{staticClass:\"form-group\",class:[{\"was-validated\":this.validated},this.stateClass],attrs:{id:u,disabled:f?this.disabled:null,role:f?null:\"group\",\"aria-invalid\":this.computedAriaInvalid,\"aria-labelledby\":f&&i?h:null}},i&&f?[e(Td,[d,j])]:[d,j])}},B3=ae({components:{BFormGroup:rS,BFormFieldset:rS}}),mR=I({computed:{selectionStart:{cache:!1,get:function(){return this.$refs.input.selectionStart},set:function(e){this.$refs.input.selectionStart=e}},selectionEnd:{cache:!1,get:function(){return this.$refs.input.selectionEnd},set:function(e){this.$refs.input.selectionEnd=e}},selectionDirection:{cache:!1,get:function(){return this.$refs.input.selectionDirection},set:function(e){this.$refs.input.selectionDirection=e}}},methods:{select:function(){var e;(e=this.$refs.input).select.apply(e,arguments)},setSelectionRange:function(){var e;(e=this.$refs.input).setSelectionRange.apply(e,arguments)},setRangeText:function(){var e;(e=this.$refs.input).setRangeText.apply(e,arguments)}}});function nS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function iS(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?nS(Object(r),!0).forEach(function(n){gR(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):nS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function gR(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var $p=Nt(\"value\",{type:re,defaultValue:\"\",event:Rj}),k3=$p.mixin,L3=$p.props,aS=$p.prop,F3=$p.event,uy=z(ie(iS(iS({},L3),{},{ariaInvalid:c(_r,!1),autocomplete:c(g),debounce:c(re,0),formatter:c(xr),lazy:c(_,!1),lazyFormatter:c(_,!1),number:c(_,!1),placeholder:c(g),plaintext:c(_,!1),readonly:c(_,!1),trim:c(_,!1)})),\"formTextControls\"),bR=I({mixins:[k3],props:uy,data:function(){var e=this[aS];return{localValue:ce(e),vModelValue:this.modifyValue(e)}},computed:{computedClass:function(){var e=this.plaintext,r=this.type,n=r===\"range\",i=r===\"color\";return[{\"custom-range\":n,\"form-control-plaintext\":e&&!n&&!i,\"form-control\":i||!e&&!n},this.sizeFormClass,this.stateClass]},computedDebounce:function(){return Fe(ee(this.debounce,0),0)},hasFormatter:function(){return yi(this.formatter)}},watch:gR({},aS,function(t){var e=ce(t),r=this.modifyValue(t);(e!==this.localValue||r!==this.vModelValue)&&(this.clearDebounce(),this.localValue=e,this.vModelValue=r)}),created:function(){this.$_inputDebounceTimer=null},beforeDestroy:function(){this.clearDebounce()},methods:{clearDebounce:function(){clearTimeout(this.$_inputDebounceTimer),this.$_inputDebounceTimer=null},formatValue:function(e,r){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:!1;return e=ce(e),this.hasFormatter&&(!this.lazyFormatter||n)&&(e=this.formatter(e,r)),e},modifyValue:function(e){return e=ce(e),this.trim&&(e=e.trim()),this.number&&(e=Ee(e,e)),e},updateValue:function(e){var r=this,n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,i=this.lazy;if(!(i&&!n)){this.clearDebounce();var a=function(){if(e=r.modifyValue(e),e!==r.vModelValue)r.vModelValue=e,r.$emit(F3,e);else if(r.hasFormatter){var l=r.$refs.input;l&&e!==l.value&&(l.value=e)}},o=this.computedDebounce;o>0&&!i&&!n?this.$_inputDebounceTimer=setTimeout(a,o):a()}},onInput:function(e){if(!e.target.composing){var r=e.target.value,n=this.formatValue(r,e);if(n===!1||e.defaultPrevented){_e(e,{propagation:!1});return}this.localValue=n,this.updateValue(n),this.$emit(_D,n)}},onChange:function(e){var r=e.target.value,n=this.formatValue(r,e);if(n===!1||e.defaultPrevented){_e(e,{propagation:!1});return}this.localValue=n,this.updateValue(n,!0),this.$emit(en,n)},onBlur:function(e){var r=e.target.value,n=this.formatValue(r,e,!0);n!==!1&&(this.localValue=ce(this.modifyValue(n)),this.updateValue(n,!0)),this.$emit(bD,e)},focus:function(){this.disabled||we(this.$el)},blur:function(){this.disabled||rn(this.$el)}}}),yR=I({computed:{validity:{cache:!1,get:function(){return this.$refs.input.validity}},validationMessage:{cache:!1,get:function(){return this.$refs.input.validationMessage}},willValidate:{cache:!1,get:function(){return this.$refs.input.willValidate}}},methods:{setCustomValidity:function(){var e;return(e=this.$refs.input).setCustomValidity.apply(e,arguments)},checkValidity:function(){var e;return(e=this.$refs.input).checkValidity.apply(e,arguments)},reportValidity:function(){var e;return(e=this.$refs.input).reportValidity.apply(e,arguments)}}});function oS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function la(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?oS(Object(r),!0).forEach(function(n){j3(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):oS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function j3(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var OR=[\"text\",\"password\",\"email\",\"number\",\"url\",\"tel\",\"search\",\"range\",\"color\",\"date\",\"time\",\"datetime\",\"datetime-local\",\"month\",\"week\"],V3=z(ie(la(la(la(la(la(la({},Ke),ti),ri),ni),uy),{},{list:c(g),max:c(re),min:c(re),noWheel:c(_,!1),step:c(re),type:c(g,\"text\",function(t){return he(OR,t)})})),fC),sS=I({name:fC,mixins:[Zi,Ze,Lo,Qi,Si,bR,mR,yR],props:V3,computed:{localType:function(){var e=this.type;return he(OR,e)?e:\"text\"},computedAttrs:function(){var e=this.localType,r=this.name,n=this.form,i=this.disabled,a=this.placeholder,o=this.required,s=this.min,l=this.max,u=this.step;return{id:this.safeId(),name:r,form:n,type:e,disabled:i,placeholder:a,required:o,autocomplete:this.autocomplete||null,readonly:this.readonly||this.plaintext,min:s,max:l,step:u,list:e!==\"password\"?this.list:null,\"aria-required\":o?\"true\":null,\"aria-invalid\":this.computedAriaInvalid}},computedListeners:function(){return la(la({},this.bvListeners),{},{input:this.onInput,change:this.onChange,blur:this.onBlur})}},watch:{noWheel:function(e){this.setWheelStopper(e)}},mounted:function(){this.setWheelStopper(this.noWheel)},deactivated:function(){this.setWheelStopper(!1)},activated:function(){this.setWheelStopper(this.noWheel)},beforeDestroy:function(){this.setWheelStopper(!1)},methods:{setWheelStopper:function(e){var r=this.$el;qn(e,r,\"focus\",this.onWheelFocus),qn(e,r,\"blur\",this.onWheelBlur),e||ft(document,\"wheel\",this.stopWheel)},onWheelFocus:function(){it(document,\"wheel\",this.stopWheel)},onWheelBlur:function(){ft(document,\"wheel\",this.stopWheel)},stopWheel:function(e){_e(e,{propagation:!1}),rn(this.$el)}},render:function(e){return e(\"input\",{class:this.computedClass,attrs:this.computedAttrs,domProps:{value:this.localValue},on:this.computedListeners,ref:\"input\"})}}),H3=ae({components:{BFormInput:sS,BInput:sS}}),z3=z(sy,hC),lS=I({name:hC,mixins:[sR],provide:function(){var e=this;return{getBvRadioGroup:function(){return e}}},props:z3,computed:{isRadioGroup:function(){return!0}}}),U3=ae({components:{BFormRadio:ug,BRadio:ug,BFormRadioGroup:lS,BRadioGroup:lS}}),Ml;function uS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Nl(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?uS(Object(r),!0).forEach(function(n){_f(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):uS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function _f(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Cp=Nt(\"value\",{type:re,event:en}),G3=Cp.mixin,W3=Cp.props,cS=Cp.prop,K3=Cp.event,_R=3,wR=5,fS=function(e){return Fe(_R,ee(e,wR))},Ka=function(e,r,n){return Fe(Fi(e,n),r)},Y3=I({name:ej,mixins:[ve],props:{disabled:c(_,!1),focused:c(_,!1),hasClear:c(_,!1),rating:c(mr,0),readonly:c(_,!1),star:c(mr,0),variant:c(g)},methods:{onClick:function(e){!this.disabled&&!this.readonly&&(_e(e,{propagation:!1}),this.$emit(CD,this.star))}},render:function(e){var r=this.rating,n=this.star,i=this.focused,a=this.hasClear,o=this.variant,s=this.disabled,l=this.readonly,u=a?0:1,f=r>=n?\"full\":r>=n-.5?\"half\":\"empty\",d={variant:o,disabled:s,readonly:l};return e(\"span\",{staticClass:\"b-rating-star\",class:{focused:i&&r===n||!ee(r)&&n===u,\"b-rating-star-empty\":f===\"empty\",\"b-rating-star-half\":f===\"half\",\"b-rating-star-full\":f===\"full\"},attrs:{tabindex:!s&&!l?\"-1\":null},on:{click:this.onClick}},[e(\"span\",{staticClass:\"b-rating-icon\"},[this.normalizeSlot(f,d)])])}}),q3=z(ie(Nl(Nl(Nl(Nl(Nl({},Ke),W3),Pe(ti,[\"required\",\"autofocus\"])),ri),{},{color:c(g),iconClear:c(g,\"x\"),iconEmpty:c(g,\"star\"),iconFull:c(g,\"star-fill\"),iconHalf:c(g,\"star-half\"),inline:c(_,!1),locale:c(Or),noBorder:c(_,!1),precision:c(re),readonly:c(_,!1),showClear:c(_,!1),showValue:c(_,!1),showValueMax:c(_,!1),stars:c(re,wR,function(t){return ee(t)>=_R}),variant:c(g)})),vC),dS=I({name:vC,components:{BIconStar:wV,BIconStarHalf:SV,BIconStarFill:TV,BIconX:QD},mixins:[Ze,G3,Qi],props:q3,data:function(){var e=Ee(this[cS],null),r=fS(this.stars);return{localValue:nt(e)?null:Ka(e,0,r),hasFocus:!1}},computed:{computedStars:function(){return fS(this.stars)},computedRating:function(){var e=Ee(this.localValue,0),r=ee(this.precision,3);return Ka(Ee(e.toFixed(r)),0,this.computedStars)},computedLocale:function(){var e=Me(this.locale).filter(pe),r=new Intl.NumberFormat(e);return r.resolvedOptions().locale},isInteractive:function(){return!this.disabled&&!this.readonly},isRTL:function(){return pp(this.computedLocale)},formattedRating:function(){var e=ee(this.precision),r=this.showValueMax,n=this.computedLocale,i={notation:\"standard\",minimumFractionDigits:isNaN(e)?0:e,maximumFractionDigits:isNaN(e)?3:e},a=this.computedStars.toLocaleString(n),o=this.localValue;return o=nt(o)?r?\"-\":\"\":o.toLocaleString(n,i),r?\"\".concat(o,\"/\").concat(a):o}},watch:(Ml={},_f(Ml,cS,function(t,e){if(t!==e){var r=Ee(t,null);this.localValue=nt(r)?null:Ka(r,0,this.computedStars)}}),_f(Ml,\"localValue\",function(e,r){e!==r&&e!==(this.value||0)&&this.$emit(K3,e||null)}),_f(Ml,\"disabled\",function(e){e&&(this.hasFocus=!1,this.blur())}),Ml),methods:{focus:function(){this.disabled||we(this.$el)},blur:function(){this.disabled||rn(this.$el)},onKeydown:function(e){var r=e.keyCode;if(this.isInteractive&&he([Xn,Rr,Yi,Zr],r)){_e(e,{propagation:!1});var n=ee(this.localValue,0),i=this.showClear?0:1,a=this.computedStars,o=this.isRTL?-1:1;r===Xn?this.localValue=Ka(n-o,i,a)||null:r===Yi?this.localValue=Ka(n+o,i,a):r===Rr?this.localValue=Ka(n-1,i,a)||null:r===Zr&&(this.localValue=Ka(n+1,i,a))}},onSelected:function(e){this.isInteractive&&(this.localValue=e)},onFocus:function(e){this.hasFocus=this.isInteractive?e.type===\"focus\":!1},renderIcon:function(e){return this.$createElement(sd,{props:{icon:e,variant:this.disabled||this.color?null:this.variant||null}})},iconEmptyFn:function(){return this.renderIcon(this.iconEmpty)},iconHalfFn:function(){return this.renderIcon(this.iconHalf)},iconFullFn:function(){return this.renderIcon(this.iconFull)},iconClearFn:function(){return this.$createElement(sd,{props:{icon:this.iconClear}})}},render:function(e){var r=this,n=this.disabled,i=this.readonly,a=this.name,o=this.form,s=this.inline,l=this.variant,u=this.color,f=this.noBorder,d=this.hasFocus,p=this.computedRating,h=this.computedStars,b=this.formattedRating,y=this.showClear,P=this.isRTL,C=this.isInteractive,R=this.$scopedSlots,D=[];if(y&&!n&&!i){var B=e(\"span\",{staticClass:\"b-rating-icon\"},[(R[qj]||this.iconClearFn)()]);D.push(e(\"span\",{staticClass:\"b-rating-star b-rating-star-clear flex-grow-1\",class:{focused:d&&p===0},attrs:{tabindex:C?\"-1\":null},on:{click:function(){return r.onSelected(null)}},key:\"clear\"},[B]))}for(var A=0;A<h;A++){var V=A+1;D.push(e(Y3,{staticClass:\"flex-grow-1\",style:u&&!n?{color:u}:{},props:{rating:p,star:V,variant:n?null:l||null,disabled:n,readonly:i,focused:d,hasClear:y},on:{selected:this.onSelected},scopedSlots:{empty:R[Xj]||this.iconEmptyFn,half:R[Zj]||this.iconHalfFn,full:R[Jj]||this.iconFullFn},key:A}))}return a&&D.push(e(\"input\",{attrs:{type:\"hidden\",value:nt(this.localValue)?\"\":p,name:a,form:o||null},key:\"hidden\"})),this.showValue&&D.push(e(\"b\",{staticClass:\"b-rating-value flex-grow-1\",attrs:{\"aria-hidden\":\"true\"},key:\"value\"},ce(b))),e(\"output\",{staticClass:\"b-rating form-control align-items-center\",class:[{\"d-inline-flex\":s,\"d-flex\":!s,\"border-0\":f,disabled:n,readonly:!n&&i},this.sizeFormClass],attrs:{id:this.safeId(),dir:P?\"rtl\":\"ltr\",tabindex:n?null:\"0\",disabled:n,role:\"slider\",\"aria-disabled\":n?\"true\":null,\"aria-readonly\":!n&&i?\"true\":null,\"aria-live\":\"off\",\"aria-valuemin\":y?\"0\":\"1\",\"aria-valuemax\":ce(h),\"aria-valuenow\":p?ce(p):null},on:{keydown:this.onKeydown,focus:this.onFocus,blur:this.onFocus}},D)}}),X3=ae({components:{BFormRating:dS,BRating:dS}}),Dp=Nt(\"value\"),J3=Dp.mixin,Z3=Dp.props,Q3=Dp.prop,e8=Dp.event;function pS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function hS(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?pS(Object(r),!0).forEach(function(n){t8(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):pS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function t8(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var r8=z(ie(hS(hS({},ec),{},{labelField:c(g,\"label\"),optionsField:c(g,\"options\")})),\"formOptions\"),n8=I({mixins:[_p],props:r8,methods:{normalizeOption:function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:null;if(yr(e)){var n=ur(e,this.valueField),i=ur(e,this.textField),a=ur(e,this.optionsField,null);return nt(a)?{value:Et(n)?r||i:n,text:String(Et(i)?r:i),html:ur(e,this.htmlField),disabled:Boolean(ur(e,this.disabledField))}:{label:String(ur(e,this.labelField)||i),options:this.normalizeOptions(a)}}return{value:r||e,text:String(e),disabled:!1}}}}),i8=z({disabled:c(_,!1),value:c(Ns,void 0,!0)},bC),Pd=I({name:bC,functional:!0,props:i8,render:function(e,r){var n=r.props,i=r.data,a=r.children,o=n.value,s=n.disabled;return e(\"option\",oe(i,{attrs:{disabled:s},domProps:{value:o}}),a)}});function vS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function mS(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?vS(Object(r),!0).forEach(function(n){a8(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):vS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function a8(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var o8=z(ie(mS(mS({},ec),{},{label:c(g,void 0,!0)})),yC),pg=I({name:yC,mixins:[ve,_p],props:o8,render:function(e){var r=this.label,n=this.formOptions.map(function(i,a){var o=i.value,s=i.text,l=i.html,u=i.disabled;return e(Pd,{attrs:{value:o,disabled:u},domProps:dt(l,s),key:\"option_\".concat(a)})});return e(\"optgroup\",{attrs:{label:r}},[this.normalizeSlot(Mb),n,this.normalizeSlot()])}});function gS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Ya(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?gS(Object(r),!0).forEach(function(n){s8(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):gS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function s8(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var l8=z(ie(Ya(Ya(Ya(Ya(Ya(Ya(Ya({},Ke),Z3),ti),tc),ri),ni),{},{ariaInvalid:c(_r,!1),multiple:c(_,!1),selectSize:c(mr,0)})),gC),bS=I({name:gC,mixins:[Ze,J3,Lo,Qi,Si,wp,n8,ve],props:l8,data:function(){return{localValue:this[Q3]}},computed:{computedSelectSize:function(){return!this.plain&&this.selectSize===0?null:this.selectSize},inputClass:function(){return[this.plain?\"form-control\":\"custom-select\",this.size&&this.plain?\"form-control-\".concat(this.size):null,this.size&&!this.plain?\"custom-select-\".concat(this.size):null,this.stateClass]}},watch:{value:function(e){this.localValue=e},localValue:function(){this.$emit(e8,this.localValue)}},methods:{focus:function(){we(this.$refs.input)},blur:function(){rn(this.$refs.input)},onChange:function(e){var r=this,n=e.target,i=Ao(n.options).filter(function(a){return a.selected}).map(function(a){return\"_value\"in a?a._value:a.value});this.localValue=n.multiple?i:i[0],this.$nextTick(function(){r.$emit(en,r.localValue)})}},render:function(e){var r=this.name,n=this.disabled,i=this.required,a=this.computedSelectSize,o=this.localValue,s=this.formOptions.map(function(l,u){var f=l.value,d=l.label,p=l.options,h=l.disabled,b=\"option_\".concat(u);return He(p)?e(pg,{props:{label:d,options:p},key:b}):e(Pd,{props:{value:f,disabled:h},domProps:dt(l.html,l.text),key:b})});return e(\"select\",{class:this.inputClass,attrs:{id:this.safeId(),name:r,form:this.form||null,multiple:this.multiple||null,size:a,disabled:n,required:i,\"aria-required\":i?\"true\":null,\"aria-invalid\":this.computedAriaInvalid},on:{change:this.onChange},directives:[{name:\"model\",value:o}],ref:\"input\"},[this.normalizeSlot(Mb),s,this.normalizeSlot()])}}),u8=ae({components:{BFormSelect:bS,BFormSelectOption:Pd,BFormSelectOptionGroup:pg,BSelect:bS,BSelectOption:Pd,BSelectOptionGroup:pg}}),is;function yS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function fi(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?yS(Object(r),!0).forEach(function(n){tu(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):yS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function tu(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Ap=Nt(\"value\",{type:Ij}),c8=Ap.mixin,f8=Ap.props,OS=Ap.prop,d8=Ap.event,TR=1,SR=100,PR=1,ER=500,$R=100,CR=10,DR=4,_S=[Zr,Rr,Ra,Aa,ud,ld],AR=z(ie(fi(fi(fi(fi(fi(fi({},Ke),f8),Pe(ti,[\"required\",\"autofocus\"])),ri),ni),{},{ariaControls:c(g),ariaLabel:c(g),formatterFn:c(xr),inline:c(_,!1),labelDecrement:c(g,\"Decrement\"),labelIncrement:c(g,\"Increment\"),locale:c(Or),max:c(re,SR),min:c(re,TR),placeholder:c(g),readonly:c(_,!1),repeatDelay:c(re,ER),repeatInterval:c(re,$R),repeatStepMultiplier:c(re,DR),repeatThreshold:c(re,CR),step:c(re,PR),vertical:c(_,!1),wrap:c(_,!1)})),OC),hg=I({name:OC,mixins:[Vt,Ze,c8,Qi,Si,ve],inheritAttrs:!1,props:AR,data:function(){return{localValue:Ee(this[OS],null),hasFocus:!1}},computed:{required:function(){return!1},spinId:function(){return this.safeId()},computedInline:function(){return this.inline&&!this.vertical},computedReadonly:function(){return this.readonly&&!this.disabled},computedRequired:function(){return this.required&&!this.computedReadonly&&!this.disabled},computedStep:function(){return Ee(this.step,PR)},computedMin:function(){return Ee(this.min,TR)},computedMax:function(){var e=Ee(this.max,SR),r=this.computedStep,n=this.computedMin;return Mu((e-n)/r)*r+n},computedDelay:function(){var e=ee(this.repeatDelay,0);return e>0?e:ER},computedInterval:function(){var e=ee(this.repeatInterval,0);return e>0?e:$R},computedThreshold:function(){return Fe(ee(this.repeatThreshold,CR),1)},computedStepMultiplier:function(){return Fe(ee(this.repeatStepMultiplier,DR),1)},computedPrecision:function(){var e=this.computedStep;return Mu(e)===e?0:(e.toString().split(\".\")[1]||\"\").length},computedMultiplier:function(){return YD(10,this.computedPrecision||0)},valueAsFixed:function(){var e=this.localValue;return nt(e)?\"\":e.toFixed(this.computedPrecision)},computedLocale:function(){var e=Me(this.locale).filter(pe),r=new Intl.NumberFormat(e);return r.resolvedOptions().locale},computedRTL:function(){return pp(this.computedLocale)},defaultFormatter:function(){var e=this.computedPrecision,r=new Intl.NumberFormat(this.computedLocale,{style:\"decimal\",useGrouping:!1,minimumIntegerDigits:1,minimumFractionDigits:e,maximumFractionDigits:e,notation:\"standard\"});return r.format},computedFormatter:function(){var e=this.formatterFn;return yi(e)?e:this.defaultFormatter},computedAttrs:function(){return fi(fi({},this.bvAttrs),{},{role:\"group\",lang:this.computedLocale,tabindex:this.disabled?null:\"-1\",title:this.ariaLabel})},computedSpinAttrs:function(){var e=this.spinId,r=this.localValue,n=this.computedRequired,i=this.disabled,a=this.state,o=this.computedFormatter,s=!nt(r);return fi(fi({dir:this.computedRTL?\"rtl\":\"ltr\"},this.bvAttrs),{},{id:e,role:\"spinbutton\",tabindex:i?null:\"0\",\"aria-live\":\"off\",\"aria-label\":this.ariaLabel||null,\"aria-controls\":this.ariaControls||null,\"aria-invalid\":a===!1||!s&&n?\"true\":null,\"aria-required\":n?\"true\":null,\"aria-valuemin\":ce(this.computedMin),\"aria-valuemax\":ce(this.computedMax),\"aria-valuenow\":s?r:null,\"aria-valuetext\":s?o(r):null})}},watch:(is={},tu(is,OS,function(t){this.localValue=Ee(t,null)}),tu(is,\"localValue\",function(e){this.$emit(d8,e)}),tu(is,\"disabled\",function(e){e&&this.clearRepeat()}),tu(is,\"readonly\",function(e){e&&this.clearRepeat()}),is),created:function(){this.$_autoDelayTimer=null,this.$_autoRepeatTimer=null,this.$_keyIsDown=!1},beforeDestroy:function(){this.clearRepeat()},deactivated:function(){this.clearRepeat()},methods:{focus:function(){this.disabled||we(this.$refs.spinner)},blur:function(){this.disabled||rn(this.$refs.spinner)},emitChange:function(){this.$emit(en,this.localValue)},stepValue:function(e){var r=this.localValue;if(!this.disabled&&!nt(r)){var n=this.computedStep*e,i=this.computedMin,a=this.computedMax,o=this.computedMultiplier,s=this.wrap;r=Gm((r-i)/n)*n+i+n,r=Gm(r*o)/o,this.localValue=r>a?s?i:a:r<i?s?a:i:r}},onFocusBlur:function(e){this.hasFocus=this.disabled?!1:e.type===\"focus\"},stepUp:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:1,r=this.localValue;nt(r)?this.localValue=this.computedMin:this.stepValue(1*e)},stepDown:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:1,r=this.localValue;nt(r)?this.localValue=this.wrap?this.computedMax:this.computedMin:this.stepValue(-1*e)},onKeydown:function(e){var r=e.keyCode,n=e.altKey,i=e.ctrlKey,a=e.metaKey;if(!(this.disabled||this.readonly||n||i||a)&&he(_S,r)){if(_e(e,{propagation:!1}),this.$_keyIsDown)return;this.resetTimers(),he([Zr,Rr],r)?(this.$_keyIsDown=!0,r===Zr?this.handleStepRepeat(e,this.stepUp):r===Rr&&this.handleStepRepeat(e,this.stepDown)):r===ud?this.stepUp(this.computedStepMultiplier):r===ld?this.stepDown(this.computedStepMultiplier):r===Ra?this.localValue=this.computedMin:r===Aa&&(this.localValue=this.computedMax)}},onKeyup:function(e){var r=e.keyCode,n=e.altKey,i=e.ctrlKey,a=e.metaKey;this.disabled||this.readonly||n||i||a||he(_S,r)&&(_e(e,{propagation:!1}),this.resetTimers(),this.$_keyIsDown=!1,this.emitChange())},handleStepRepeat:function(e,r){var n=this,i=e||{},a=i.type,o=i.button;if(!this.disabled&&!this.readonly){if(a===\"mousedown\"&&o)return;this.resetTimers(),r(1);var s=this.computedThreshold,l=this.computedStepMultiplier,u=this.computedDelay,f=this.computedInterval;this.$_autoDelayTimer=setTimeout(function(){var d=0;n.$_autoRepeatTimer=setInterval(function(){r(d<s?1:l),d++},f)},u)}},onMouseup:function(e){var r=e||{},n=r.type,i=r.button;n===\"mouseup\"&&i||(_e(e,{propagation:!1}),this.resetTimers(),this.setMouseup(!1),this.emitChange())},setMouseup:function(e){try{qn(e,document.body,\"mouseup\",this.onMouseup,!1),qn(e,document.body,\"touchend\",this.onMouseup,!1)}catch{}},resetTimers:function(){clearTimeout(this.$_autoDelayTimer),clearInterval(this.$_autoRepeatTimer),this.$_autoDelayTimer=null,this.$_autoRepeatTimer=null},clearRepeat:function(){this.resetTimers(),this.setMouseup(!1),this.$_keyIsDown=!1}},render:function(e){var r=this,n=this.spinId,i=this.localValue,a=this.computedInline,o=this.computedReadonly,s=this.vertical,l=this.disabled,u=this.computedFormatter,f=!nt(i),d=function(C,R,D,B,A,V,N){var G=e(D,{props:{scale:r.hasFocus?1.5:1.25},attrs:{\"aria-hidden\":\"true\"}}),H={hasFocus:r.hasFocus},W=function(E){!l&&!o&&(_e(E,{propagation:!1}),r.setMouseup(!0),we(E.currentTarget),r.handleStepRepeat(E,C))};return e(\"button\",{staticClass:\"btn btn-sm border-0 rounded-0\",class:{\"py-0\":!s},attrs:{tabindex:\"-1\",type:\"button\",disabled:l||o||V,\"aria-disabled\":l||o||V?\"true\":null,\"aria-controls\":n,\"aria-label\":R||null,\"aria-keyshortcuts\":A||null},on:{mousedown:W,touchstart:W},key:B||null,ref:B},[r.normalizeSlot(N,H)||G])},p=d(this.stepUp,this.labelIncrement,_V,\"inc\",\"ArrowUp\",!1,e2),h=d(this.stepDown,this.labelDecrement,bV,\"dec\",\"ArrowDown\",!1,Vj),b=e();this.name&&!l&&(b=e(\"input\",{attrs:{type:\"hidden\",name:this.name,form:this.form||null,value:this.valueAsFixed},key:\"hidden\"}));var y=e(\"output\",{staticClass:\"flex-grow-1\",class:{\"d-flex\":s,\"align-self-center\":!s,\"align-items-center\":s,\"border-top\":s,\"border-bottom\":s,\"border-left\":!s,\"border-right\":!s},attrs:this.computedSpinAttrs,key:\"output\",ref:\"spinner\"},[e(\"bdi\",f?u(i):this.placeholder||\"\")]);return e(\"div\",{staticClass:\"b-form-spinbutton form-control\",class:[{disabled:l,readonly:o,focus:this.hasFocus,\"d-inline-flex\":a||s,\"d-flex\":!a&&!s,\"align-items-stretch\":!s,\"flex-column\":s},this.sizeFormClass,this.stateClass],attrs:this.computedAttrs,on:{keydown:this.onKeydown,keyup:this.onKeyup,\"!focus\":this.onFocusBlur,\"!blur\":this.onFocusBlur}},s?[p,b,y,h]:[h,b,y,p])}}),p8=ae({components:{BFormSpinbutton:hg,BSpinbutton:hg}});function wS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function TS(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?wS(Object(r),!0).forEach(function(n){h8(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):wS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function h8(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var v8=z(ie(TS(TS({},Ke),{},{disabled:c(_,!1),noRemove:c(_,!1),pill:c(_,!1),removeLabel:c(g,\"Remove tag\"),tag:c(g,\"span\"),title:c(g),variant:c(g,\"secondary\")})),_C),vg=I({name:_C,mixins:[Ze,ve],props:v8,methods:{onRemove:function(e){var r=e.type,n=e.keyCode;!this.disabled&&(r===\"click\"||r===\"keydown\"&&n===tA)&&this.$emit(Oj)}},render:function(e){var r=this.title,n=this.tag,i=this.variant,a=this.pill,o=this.disabled,s=this.safeId(),l=this.safeId(\"_taglabel_\"),u=e();!this.noRemove&&!o&&(u=e(xo,{staticClass:\"b-form-tag-remove\",props:{ariaLabel:this.removeLabel},attrs:{\"aria-controls\":s,\"aria-describedby\":l,\"aria-keyshortcuts\":\"Delete\"},on:{click:this.onRemove,keydown:this.onRemove}}));var f=e(\"span\",{staticClass:\"b-form-tag-content flex-grow-1 text-truncate\",attrs:{id:l}},this.normalizeSlot()||r);return e(jb,{staticClass:\"b-form-tag d-inline-flex align-items-baseline mw-100\",class:{disabled:o},props:{tag:n,variant:i,pill:a},attrs:{id:s,title:r||null,\"aria-labelledby\":l}},[f,u])}}),Il;function SS(t){return y8(t)||b8(t)||g8(t)||m8()}function m8(){throw new TypeError(`Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function g8(t,e){if(!!t){if(typeof t==\"string\")return mg(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);if(r===\"Object\"&&t.constructor&&(r=t.constructor.name),r===\"Map\"||r===\"Set\")return Array.from(t);if(r===\"Arguments\"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return mg(t,e)}}function b8(t){if(typeof Symbol<\"u\"&&t[Symbol.iterator]!=null||t[\"@@iterator\"]!=null)return Array.from(t)}function y8(t){if(Array.isArray(t))return mg(t)}function mg(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}function PS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function dn(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?PS(Object(r),!0).forEach(function(n){wf(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):PS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function wf(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Rp=Nt(\"value\",{type:Ar,defaultValue:[]}),O8=Rp.mixin,_8=Rp.props,yv=Rp.prop,w8=Rp.event,RR=[\"text\",\"email\",\"tel\",\"url\",\"number\"],T8=[\".b-form-tag\",\"button\",\"input\",\"select\"].join(\" \"),S8=function(e){return Ib(e).replace(b$,\"\\\\s\")},ES=function(e){return Me(e).map(function(r){return ya(ce(r))}).filter(function(r,n,i){return r.length>0&&i.indexOf(r)===n})},$S=function(e){return Ae(e)?e:Po(e)&&e.target.value||\"\"},Ov=function(){return{all:[],valid:[],invalid:[],duplicate:[]}},P8=z(ie(dn(dn(dn(dn(dn(dn({},Ke),_8),ti),ri),ni),{},{addButtonText:c(g,\"Add\"),addButtonVariant:c(g,\"outline-secondary\"),addOnChange:c(_,!1),duplicateTagText:c(g,\"Duplicate tag(s)\"),feedbackAriaLive:c(g,\"assertive\"),ignoreInputFocusSelector:c(Or,T8),inputAttrs:c(Mt,{}),inputClass:c(de),inputId:c(g),inputType:c(g,\"text\",function(t){return he(RR,t)}),invalidTagText:c(g,\"Invalid tag(s)\"),limit:c(mr),limitTagsText:c(g,\"Tag limit reached\"),noAddOnEnter:c(_,!1),noOuterFocus:c(_,!1),noTagRemove:c(_,!1),placeholder:c(g,\"Add tag...\"),removeOnDelete:c(_,!1),separator:c(Or),tagClass:c(de),tagPills:c(_,!1),tagRemoveLabel:c(g,\"Remove tag\"),tagRemovedLabel:c(g,\"Tag removed\"),tagValidator:c(xr),tagVariant:c(g,\"secondary\")})),wC),CS=I({name:wC,mixins:[Zi,Ze,O8,Lo,Qi,Si,ve],props:P8,data:function(){return{hasFocus:!1,newTag:\"\",tags:[],removedTags:[],tagsState:Ov(),focusState:null}},computed:{computedInputId:function(){return this.inputId||this.safeId(\"__input__\")},computedInputType:function(){return he(RR,this.inputType)?this.inputType:\"text\"},computedInputAttrs:function(){var e=this.disabled,r=this.form;return dn(dn({},this.inputAttrs),{},{id:this.computedInputId,value:this.newTag,disabled:e,form:r})},computedInputHandlers:function(){return dn(dn({},Pe(this.bvListeners,[nd,id])),{},{blur:this.onInputBlur,change:this.onInputChange,focus:this.onInputFocus,input:this.onInputInput,keydown:this.onInputKeydown,reset:this.reset})},computedSeparator:function(){return Me(this.separator).filter(Ae).filter(pe).join(\"\")},computedSeparatorRegExp:function(){var e=this.computedSeparator;return e?new RegExp(\"[\".concat(S8(e),\"]+\")):null},computedJoiner:function(){var e=this.computedSeparator.charAt(0);return e!==\" \"?\"\".concat(e,\" \"):e},computeIgnoreInputFocusSelector:function(){return Me(this.ignoreInputFocusSelector).filter(pe).join(\",\").trim()},disableAddButton:function(){var e=this,r=ya(this.newTag);return r===\"\"||!this.splitTags(r).some(function(n){return!he(e.tags,n)&&e.validateTag(n)})},duplicateTags:function(){return this.tagsState.duplicate},hasDuplicateTags:function(){return this.duplicateTags.length>0},invalidTags:function(){return this.tagsState.invalid},hasInvalidTags:function(){return this.invalidTags.length>0},isLimitReached:function(){var e=this.limit;return Kn(e)&&e>=0&&this.tags.length>=e}},watch:(Il={},wf(Il,yv,function(t){this.tags=ES(t)}),wf(Il,\"tags\",function(e,r){je(e,this[yv])||this.$emit(w8,e),je(e,r)||(e=Me(e).filter(pe),r=Me(r).filter(pe),this.removedTags=r.filter(function(n){return!he(e,n)}))}),wf(Il,\"tagsState\",function(e,r){je(e,r)||this.$emit(Dj,e.valid,e.invalid,e.duplicate)}),Il),created:function(){this.tags=ES(this[yv])},mounted:function(){var e=Jr(\"form\",this.$el);e&&it(e,\"reset\",this.reset,Yr)},beforeDestroy:function(){var e=Jr(\"form\",this.$el);e&&ft(e,\"reset\",this.reset,Yr)},methods:{addTag:function(e){if(e=Ae(e)?e:this.newTag,!(this.disabled||ya(e)===\"\"||this.isLimitReached)){var r=this.parseTags(e);if(r.valid.length>0||r.all.length===0)if(Vi(this.getInput(),\"select\"))this.newTag=\"\";else{var n=[].concat(SS(r.invalid),SS(r.duplicate));this.newTag=r.all.filter(function(i){return he(n,i)}).join(this.computedJoiner).concat(n.length>0?this.computedJoiner.charAt(0):\"\")}r.valid.length>0&&(this.tags=Me(this.tags,r.valid)),this.tagsState=r,this.focus()}},removeTag:function(e){this.disabled||(this.tags=this.tags.filter(function(r){return r!==e}))},reset:function(){var e=this;this.newTag=\"\",this.tags=[],this.$nextTick(function(){e.removedTags=[],e.tagsState=Ov()})},onInputInput:function(e){if(!(this.disabled||Po(e)&&e.target.composing)){var r=$S(e),n=this.computedSeparatorRegExp;this.newTag!==r&&(this.newTag=r),r=C2(r),n&&n.test(r.slice(-1))?this.addTag():this.tagsState=r===\"\"?Ov():this.parseTags(r)}},onInputChange:function(e){if(!this.disabled&&this.addOnChange){var r=$S(e);this.newTag!==r&&(this.newTag=r),this.addTag()}},onInputKeydown:function(e){if(!(this.disabled||!Po(e))){var r=e.keyCode,n=e.target.value||\"\";!this.noAddOnEnter&&r===Ji?(_e(e,{propagation:!1}),this.addTag()):this.removeOnDelete&&(r===CV||r===tA)&&n===\"\"&&(_e(e,{propagation:!1}),this.tags=this.tags.slice(0,-1))}},onClick:function(e){var r=this,n=this.computeIgnoreInputFocusSelector;(!n||!Jr(n,e.target,!0))&&this.$nextTick(function(){r.focus()})},onInputFocus:function(e){var r=this;this.focusState!==\"out\"&&(this.focusState=\"in\",this.$nextTick(function(){We(function(){r.hasFocus&&(r.$emit(vj,e),r.focusState=null)})}))},onInputBlur:function(e){var r=this;this.focusState!==\"in\"&&(this.focusState=\"out\",this.$nextTick(function(){We(function(){r.hasFocus||(r.$emit(bD,e),r.focusState=null)})}))},onFocusin:function(e){this.hasFocus=!0,this.$emit(nd,e)},onFocusout:function(e){this.hasFocus=!1,this.$emit(id,e)},handleAutofocus:function(){var e=this;this.$nextTick(function(){We(function(){e.autofocus&&e.focus()})})},focus:function(){this.disabled||we(this.getInput())},blur:function(){this.disabled||rn(this.getInput())},splitTags:function(e){e=ce(e);var r=this.computedSeparatorRegExp;return(r?e.split(r):[e]).map(ya).filter(pe)},parseTags:function(e){var r=this,n=this.splitTags(e),i={all:n,valid:[],invalid:[],duplicate:[]};return n.forEach(function(a){he(r.tags,a)||he(i.valid,a)?he(i.duplicate,a)||i.duplicate.push(a):r.validateTag(a)?i.valid.push(a):he(i.invalid,a)||i.invalid.push(a)}),i},validateTag:function(e){var r=this.tagValidator;return yi(r)?r(e):!0},getInput:function(){return gn(\"#\".concat(hR(this.computedInputId)),this.$el)},defaultRender:function(e){var r=e.addButtonText,n=e.addButtonVariant,i=e.addTag,a=e.disableAddButton,o=e.disabled,s=e.duplicateTagText,l=e.inputAttrs,u=e.inputClass,f=e.inputHandlers,d=e.inputType,p=e.invalidTagText,h=e.isDuplicate,b=e.isInvalid,y=e.isLimitReached,P=e.limitTagsText,C=e.noTagRemove,R=e.placeholder,D=e.removeTag,B=e.tagClass,A=e.tagPills,V=e.tagRemoveLabel,N=e.tagVariant,G=e.tags,H=this.$createElement,W=G.map(function(Ie){return Ie=ce(Ie),H(vg,{class:B,props:{disabled:o,noRemove:C,pill:A,removeLabel:V,tag:\"li\",title:Ie,variant:N},on:{remove:function(){return D(Ie)}},key:\"tags_\".concat(Ie)},Ie)}),j=p&&b?this.safeId(\"__invalid_feedback__\"):null,E=s&&h?this.safeId(\"__duplicate_feedback__\"):null,v=P&&y?this.safeId(\"__limit_feedback__\"):null,w=[l[\"aria-describedby\"],j,E,v].filter(pe).join(\" \"),$=H(\"input\",{staticClass:\"b-form-tags-input w-100 flex-grow-1 p-0 m-0 bg-transparent border-0\",class:u,style:{outline:0,minWidth:\"5rem\"},attrs:dn(dn({},l),{},{\"aria-describedby\":w||null,type:d,placeholder:R||null}),domProps:{value:l.value},on:f,directives:[{name:\"model\",value:l.value}],ref:\"input\"}),M=H(Qr,{staticClass:\"b-form-tags-button py-0\",class:{invisible:a},style:{fontSize:\"90%\"},props:{disabled:a||y,variant:n},on:{click:function(){return i()}},ref:\"button\"},[this.normalizeSlot(Fj)||r]),F=this.safeId(\"__tag_list__\"),X=H(\"li\",{staticClass:\"b-form-tags-field flex-grow-1\",attrs:{role:\"none\",\"aria-live\":\"off\",\"aria-controls\":F},key:\"tags_field\"},[H(\"div\",{staticClass:\"d-flex\",attrs:{role:\"group\"}},[$,M])]),Q=H(\"ul\",{staticClass:\"b-form-tags-list list-unstyled mb-0 d-flex flex-wrap align-items-center\",attrs:{id:F},key:\"tags_list\"},[W,X]),q=H();if(p||s||P){var K=this.feedbackAriaLive,U=this.computedJoiner,le=H();j&&(le=H(wd,{props:{id:j,ariaLive:K,forceShow:!0},key:\"tags_invalid_feedback\"},[this.invalidTagText,\": \",this.invalidTags.join(U)]));var be=H();E&&(be=H(_d,{props:{id:E,ariaLive:K},key:\"tags_duplicate_feedback\"},[this.duplicateTagText,\": \",this.duplicateTags.join(U)]));var me=H();v&&(me=H(_d,{props:{id:v,ariaLive:K},key:\"tags_limit_feedback\"},[P])),q=H(\"div\",{attrs:{\"aria-live\":\"polite\",\"aria-atomic\":\"true\"},key:\"tags_feedback\"},[le,be,me])}return[Q,q]}},render:function(e){var r=this.name,n=this.disabled,i=this.required,a=this.form,o=this.tags,s=this.computedInputId,l=this.hasFocus,u=this.noOuterFocus,f=dn({tags:o.slice(),inputAttrs:this.computedInputAttrs,inputType:this.computedInputType,inputHandlers:this.computedInputHandlers,removeTag:this.removeTag,addTag:this.addTag,reset:this.reset,inputId:s,isInvalid:this.hasInvalidTags,invalidTags:this.invalidTags.slice(),isDuplicate:this.hasDuplicateTags,duplicateTags:this.duplicateTags.slice(),isLimitReached:this.isLimitReached,disableAddButton:this.disableAddButton},Zn(this.$props,[\"addButtonText\",\"addButtonVariant\",\"disabled\",\"duplicateTagText\",\"form\",\"inputClass\",\"invalidTagText\",\"limit\",\"limitTagsText\",\"noTagRemove\",\"placeholder\",\"required\",\"separator\",\"size\",\"state\",\"tagClass\",\"tagPills\",\"tagRemoveLabel\",\"tagVariant\"])),d=this.normalizeSlot(kt,f)||this.defaultRender(f),p=e(\"output\",{staticClass:\"sr-only\",attrs:{id:this.safeId(\"__selected_tags__\"),role:\"status\",for:s,\"aria-live\":l?\"polite\":\"off\",\"aria-atomic\":\"true\",\"aria-relevant\":\"additions text\"}},this.tags.join(\", \")),h=e(\"div\",{staticClass:\"sr-only\",attrs:{id:this.safeId(\"__removed_tags__\"),role:\"status\",\"aria-live\":l?\"assertive\":\"off\",\"aria-atomic\":\"true\"}},this.removedTags.length>0?\"(\".concat(this.tagRemovedLabel,\") \").concat(this.removedTags.join(\", \")):\"\"),b=e();if(r&&!n){var y=o.length>0;b=(y?o:[\"\"]).map(function(P){return e(\"input\",{class:{\"sr-only\":!y},attrs:{type:y?\"hidden\":\"text\",value:P,required:i,name:r,form:a},key:\"tag_input_\".concat(P)})})}return e(\"div\",{staticClass:\"b-form-tags form-control h-auto\",class:[{focus:l&&!u&&!n,disabled:n},this.sizeFormClass,this.stateClass],attrs:{id:this.safeId(),role:\"group\",tabindex:n||u?null:\"-1\",\"aria-describedby\":this.safeId(\"__selected_tags__\")},on:{click:this.onClick,focusin:this.onFocusin,focusout:this.onFocusout}},[p,h,d,b])}}),E8=ae({components:{BFormTags:CS,BTags:CS,BFormTag:vg,BTag:vg}});function DS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function ua(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?DS(Object(r),!0).forEach(function(n){$8(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):DS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function $8(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var C8=z(ie(ua(ua(ua(ua(ua(ua({},Ke),ti),ri),ni),uy),{},{maxRows:c(re),noAutoShrink:c(_,!1),noResize:c(_,!1),rows:c(re,2),wrap:c(g,\"soft\")})),SC),AS=I({name:SC,directives:{\"b-visible\":qb},mixins:[Zi,Ze,Qn,Lo,Qi,Si,bR,mR,yR],props:C8,data:function(){return{heightInPx:null}},computed:{type:function(){return null},computedStyle:function(){var e={resize:!this.computedRows||this.noResize?\"none\":null};return this.computedRows||(e.height=this.heightInPx,e.overflowY=\"scroll\"),e},computedMinRows:function(){return Fe(ee(this.rows,2),2)},computedMaxRows:function(){return Fe(this.computedMinRows,ee(this.maxRows,0))},computedRows:function(){return this.computedMinRows===this.computedMaxRows?this.computedMinRows:null},computedAttrs:function(){var e=this.disabled,r=this.required;return{id:this.safeId(),name:this.name||null,form:this.form||null,disabled:e,placeholder:this.placeholder||null,required:r,autocomplete:this.autocomplete||null,readonly:this.readonly||this.plaintext,rows:this.computedRows,wrap:this.wrap||null,\"aria-required\":this.required?\"true\":null,\"aria-invalid\":this.computedAriaInvalid}},computedListeners:function(){return ua(ua({},this.bvListeners),{},{input:this.onInput,change:this.onChange,blur:this.onBlur})}},watch:{localValue:function(){this.setHeight()}},mounted:function(){this.setHeight()},methods:{visibleCallback:function(e){e&&this.$nextTick(this.setHeight)},setHeight:function(){var e=this;this.$nextTick(function(){We(function(){e.heightInPx=e.computeHeight()})})},computeHeight:function(){if(this.$isServer||!nt(this.computedRows))return null;var e=this.$el;if(!Yn(e))return null;var r=hn(e),n=Ee(r.lineHeight,1),i=Ee(r.borderTopWidth,0)+Ee(r.borderBottomWidth,0),a=Ee(r.paddingTop,0)+Ee(r.paddingBottom,0),o=i+a,s=n*this.computedMinRows+o,l=ws(e,\"height\")||r.height;lr(e,\"height\",\"auto\");var u=e.scrollHeight;lr(e,\"height\",l);var f=Fe((u-a)/n,2),d=Fi(Fe(f,this.computedMinRows),this.computedMaxRows),p=Fe(KD(d*n+o),s);return this.noAutoShrink&&Ee(l,0)>p?l:\"\".concat(p,\"px\")}},render:function(e){return e(\"textarea\",{class:this.computedClass,style:this.computedStyle,directives:[{name:\"b-visible\",value:this.visibleCallback,modifiers:{640:!0}}],attrs:this.computedAttrs,domProps:{value:this.localValue},on:this.computedListeners,ref:\"input\"})}}),D8=ae({components:{BFormTextarea:AS,BTextarea:AS}}),qa;function RS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function ru(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?RS(Object(r),!0).forEach(function(n){to(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):RS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function to(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function A8(t,e){return N8(t)||M8(t,e)||x8(t,e)||R8()}function R8(){throw new TypeError(`Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function x8(t,e){if(!!t){if(typeof t==\"string\")return xS(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);if(r===\"Object\"&&t.constructor&&(r=t.constructor.name),r===\"Map\"||r===\"Set\")return Array.from(t);if(r===\"Arguments\"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return xS(t,e)}}function xS(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}function M8(t,e){var r=t==null?null:typeof Symbol<\"u\"&&t[Symbol.iterator]||t[\"@@iterator\"];if(r!=null){var n=[],i=!0,a=!1,o,s;try{for(r=r.call(t);!(i=(o=r.next()).done)&&(n.push(o.value),!(e&&n.length===e));i=!0);}catch(l){a=!0,s=l}finally{try{!i&&r.return!=null&&r.return()}finally{if(a)throw s}}return n}}function N8(t){if(Array.isArray(t))return t}var xp=Nt(\"value\",{type:g,defaultValue:\"\"}),I8=xp.mixin,B8=xp.props,MS=xp.prop,k8=xp.event,as=\"numeric\",L8=function(e){return\"00\".concat(e||\"\").slice(-2)},Vc=function(e){e=ce(e);var r=null,n=null,i=null;if(hF.test(e)){var a=e.split(\":\").map(function(s){return ee(s,null)}),o=A8(a,3);r=o[0],n=o[1],i=o[2]}return{hours:Ge(r)?null:r,minutes:Ge(n)?null:n,seconds:Ge(i)?null:i,ampm:Ge(r)||r<12?0:1}},F8=function(e){var r=e.hours,n=e.minutes,i=e.seconds,a=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;if(nt(r)||nt(n)||a&&nt(i))return\"\";var o=[r,n,a?i:0];return o.map(L8).join(\":\")},xR=z(ie(ru(ru(ru(ru({},Ke),B8),Zn(AR,[\"labelIncrement\",\"labelDecrement\"])),{},{ariaLabelledby:c(g),disabled:c(_,!1),footerTag:c(g,\"footer\"),headerTag:c(g,\"header\"),hidden:c(_,!1),hideHeader:c(_,!1),hour12:c(_,null),labelAm:c(g,\"AM\"),labelAmpm:c(g,\"AM/PM\"),labelHours:c(g,\"Hours\"),labelMinutes:c(g,\"Minutes\"),labelNoTimeSelected:c(g,\"No time selected\"),labelPm:c(g,\"PM\"),labelSeconds:c(g,\"Seconds\"),labelSelected:c(g,\"Selected time\"),locale:c(Or),minutesStep:c(re,1),readonly:c(_,!1),secondsStep:c(re,1),showSeconds:c(_,!1)})),vD),MR=I({name:vD,mixins:[Ze,I8,ve],props:xR,data:function(){var e=Vc(this[MS]||\"\");return{modelHours:e.hours,modelMinutes:e.minutes,modelSeconds:e.seconds,modelAmpm:e.ampm,isLive:!1}},computed:{computedHMS:function(){var e=this.modelHours,r=this.modelMinutes,n=this.modelSeconds;return F8({hours:e,minutes:r,seconds:n},this.showSeconds)},resolvedOptions:function(){var e=Me(this.locale).filter(pe),r={hour:as,minute:as,second:as};Ge(this.hour12)||(r.hour12=!!this.hour12);var n=new Intl.DateTimeFormat(e,r),i=n.resolvedOptions(),a=i.hour12||!1,o=i.hourCycle||(a?\"h12\":\"h23\");return{locale:i.locale,hour12:a,hourCycle:o}},computedLocale:function(){return this.resolvedOptions.locale},computedLang:function(){return(this.computedLocale||\"\").replace(/-u-.*$/,\"\")},computedRTL:function(){return pp(this.computedLang)},computedHourCycle:function(){return this.resolvedOptions.hourCycle},is12Hour:function(){return!!this.resolvedOptions.hour12},context:function(){return{locale:this.computedLocale,isRTL:this.computedRTL,hourCycle:this.computedHourCycle,hour12:this.is12Hour,hours:this.modelHours,minutes:this.modelMinutes,seconds:this.showSeconds?this.modelSeconds:0,value:this.computedHMS,formatted:this.formattedTimeString}},valueId:function(){return this.safeId()||null},computedAriaLabelledby:function(){return[this.ariaLabelledby,this.valueId].filter(pe).join(\" \")||null},timeFormatter:function(){var e={hour12:this.is12Hour,hourCycle:this.computedHourCycle,hour:as,minute:as,timeZone:\"UTC\"};return this.showSeconds&&(e.second=as),Xl(this.computedLocale,e)},numberFormatter:function(){var e=new Intl.NumberFormat(this.computedLocale,{style:\"decimal\",minimumIntegerDigits:2,minimumFractionDigits:0,maximumFractionDigits:0,notation:\"standard\"});return e.format},formattedTimeString:function(){var e=this.modelHours,r=this.modelMinutes,n=this.showSeconds&&this.modelSeconds||0;return this.computedHMS?this.timeFormatter(Jt(Date.UTC(0,0,1,e,r,n))):this.labelNoTimeSelected||\" \"},spinScopedSlots:function(){var e=this.$createElement;return{increment:function(n){var i=n.hasFocus;return e(pw,{props:{scale:i?1.5:1.25},attrs:{\"aria-hidden\":\"true\"}})},decrement:function(n){var i=n.hasFocus;return e(pw,{props:{flipV:!0,scale:i?1.5:1.25},attrs:{\"aria-hidden\":\"true\"}})}}}},watch:(qa={},to(qa,MS,function(t,e){if(t!==e&&!je(Vc(t),Vc(this.computedHMS))){var r=Vc(t),n=r.hours,i=r.minutes,a=r.seconds,o=r.ampm;this.modelHours=n,this.modelMinutes=i,this.modelSeconds=a,this.modelAmpm=o}}),to(qa,\"computedHMS\",function(e,r){e!==r&&this.$emit(k8,e)}),to(qa,\"context\",function(e,r){je(e,r)||this.$emit(Ms,e)}),to(qa,\"modelAmpm\",function(e,r){var n=this;if(e!==r){var i=nt(this.modelHours)?0:this.modelHours;this.$nextTick(function(){e===0&&i>11?n.modelHours=i-12:e===1&&i<12&&(n.modelHours=i+12)})}}),to(qa,\"modelHours\",function(e,r){e!==r&&(this.modelAmpm=e>11?1:0)}),qa),created:function(){var e=this;this.$nextTick(function(){e.$emit(Ms,e.context)})},mounted:function(){this.setLive(!0)},activated:function(){this.setLive(!0)},deactivated:function(){this.setLive(!1)},beforeDestroy:function(){this.setLive(!1)},methods:{focus:function(){this.disabled||we(this.$refs.spinners[0])},blur:function(){if(!this.disabled){var e=Da();Rt(this.$el,e)&&rn(e)}},formatHours:function(e){var r=this.computedHourCycle;return e=this.is12Hour&&e>12?e-12:e,e=e===0&&r===\"h12\"?12:e===0&&r===\"h24\"?24:e===12&&r===\"h11\"?0:e,this.numberFormatter(e)},formatMinutes:function(e){return this.numberFormatter(e)},formatSeconds:function(e){return this.numberFormatter(e)},formatAmpm:function(e){return e===0?this.labelAm:e===1?this.labelPm:\"\"},setHours:function(e){this.modelHours=e},setMinutes:function(e){this.modelMinutes=e},setSeconds:function(e){this.modelSeconds=e},setAmpm:function(e){this.modelAmpm=e},onSpinLeftRight:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},r=e.type,n=e.keyCode;if(!this.disabled&&r===\"keydown\"&&(n===Xn||n===Yi)){_e(e);var i=this.$refs.spinners||[],a=i.map(function(o){return!!o.hasFocus}).indexOf(!0);a=a+(n===Xn?-1:1),a=a>=i.length?0:a<0?i.length-1:a,we(i[a])}},setLive:function(e){var r=this;e?this.$nextTick(function(){We(function(){r.isLive=!0})}):this.isLive=!1}},render:function(e){var r=this;if(this.hidden)return e();var n=this.disabled,i=this.readonly,a=this.computedLocale,o=this.computedAriaLabelledby,s=this.labelIncrement,l=this.labelDecrement,u=this.valueId,f=this.focus,d=[],p=function(B,A,V){var N=arguments.length>3&&arguments[3]!==void 0?arguments[3]:{},G=r.safeId(\"_spinbutton_\".concat(A,\"_\"))||null;return d.push(G),e(hg,to({class:V,props:ru({id:G,placeholder:\"--\",vertical:!0,required:!0,disabled:n,readonly:i,locale:a,labelIncrement:s,labelDecrement:l,wrap:!0,ariaControls:u,min:0},N),scopedSlots:r.spinScopedSlots,on:{change:B},key:A,ref:\"spinners\"},Pb,!0))},h=function(){return e(\"div\",{staticClass:\"d-flex flex-column\",class:{\"text-muted\":n||i},attrs:{\"aria-hidden\":\"true\"}},[e(Wm,{props:{shiftV:4,scale:.5}}),e(Wm,{props:{shiftV:-4,scale:.5}})])},b=[];b.push(p(this.setHours,\"hours\",\"b-time-hours\",{value:this.modelHours,max:23,step:1,formatterFn:this.formatHours,ariaLabel:this.labelHours})),b.push(h()),b.push(p(this.setMinutes,\"minutes\",\"b-time-minutes\",{value:this.modelMinutes,max:59,step:this.minutesStep||1,formatterFn:this.formatMinutes,ariaLabel:this.labelMinutes})),this.showSeconds&&(b.push(h()),b.push(p(this.setSeconds,\"seconds\",\"b-time-seconds\",{value:this.modelSeconds,max:59,step:this.secondsStep||1,formatterFn:this.formatSeconds,ariaLabel:this.labelSeconds}))),this.isLive&&this.is12Hour&&b.push(p(this.setAmpm,\"ampm\",\"b-time-ampm\",{value:this.modelAmpm,max:1,formatterFn:this.formatAmpm,ariaLabel:this.labelAmpm,required:!1})),b=e(\"div\",{staticClass:\"d-flex align-items-center justify-content-center mx-auto\",attrs:{role:\"group\",tabindex:n||i?null:\"-1\",\"aria-labelledby\":o},on:{keydown:this.onSpinLeftRight,click:function(B){B.target===B.currentTarget&&f()}}},b);var y=e(\"output\",{staticClass:\"form-control form-control-sm text-center\",class:{disabled:n||i},attrs:{id:u,role:\"status\",for:d.filter(pe).join(\" \")||null,tabindex:n?null:\"-1\",\"aria-live\":this.isLive?\"polite\":\"off\",\"aria-atomic\":\"true\"},on:{click:f,focus:f}},[e(\"bdi\",this.formattedTimeString),this.computedHMS?e(\"span\",{staticClass:\"sr-only\"},\" (\".concat(this.labelSelected,\") \")):\"\"]),P=e(this.headerTag,{staticClass:\"b-time-header\",class:{\"sr-only\":this.hideHeader}},[y]),C=this.normalizeSlot(),R=C?e(this.footerTag,{staticClass:\"b-time-footer\"},C):e();return e(\"div\",{staticClass:\"b-time d-inline-flex flex-column text-center\",attrs:{role:\"group\",lang:this.computedLang||null,\"aria-labelledby\":o||null,\"aria-disabled\":n?\"true\":null,\"aria-readonly\":i&&!n?\"true\":null}},[P,b,R])}}),Hc;function NS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Ii(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?NS(Object(r),!0).forEach(function(n){Tf(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):NS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Tf(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Mp=Nt(\"value\",{type:g,defaultValue:\"\"}),j8=Mp.mixin,V8=Mp.props,IS=Mp.prop,H8=Mp.event,NR=Pe(xR,[\"hidden\",\"id\",\"value\"]),IR=Pe(ly,[\"formattedValue\",\"id\",\"lang\",\"rtl\",\"value\"]),z8=z(ie(Ii(Ii(Ii(Ii(Ii({},Ke),V8),NR),IR),{},{closeButtonVariant:c(g,\"outline-secondary\"),labelCloseButton:c(g,\"Close\"),labelNowButton:c(g,\"Select now\"),labelResetButton:c(g,\"Reset\"),noCloseButton:c(_,!1),nowButton:c(_,!1),nowButtonVariant:c(g,\"outline-primary\"),resetButton:c(_,!1),resetButtonVariant:c(g,\"outline-danger\"),resetValue:c(ho)})),PC),BS=I({name:PC,mixins:[Ze,j8],props:z8,data:function(){return{localHMS:this[IS]||\"\",localLocale:null,isRTL:!1,formattedValue:\"\",isVisible:!1}},computed:{computedLang:function(){return(this.localLocale||\"\").replace(/-u-.*$/i,\"\")||null}},watch:(Hc={},Tf(Hc,IS,function(t){this.localHMS=t||\"\"}),Tf(Hc,\"localHMS\",function(e){this.isVisible&&this.$emit(H8,e||\"\")}),Hc),methods:{focus:function(){this.disabled||we(this.$refs.control)},blur:function(){this.disabled||rn(this.$refs.control)},setAndClose:function(e){var r=this;this.localHMS=e,this.$nextTick(function(){r.$refs.control.hide(!0)})},onInput:function(e){this.localHMS!==e&&(this.localHMS=e)},onContext:function(e){var r=e.isRTL,n=e.locale,i=e.value,a=e.formatted;this.isRTL=r,this.localLocale=n,this.formattedValue=a,this.localHMS=i||\"\",this.$emit(Ms,e)},onNowButton:function(){var e=new Date,r=e.getHours(),n=e.getMinutes(),i=this.showSeconds?e.getSeconds():0,a=[r,n,i].map(function(o){return\"00\".concat(o||\"\").slice(-2)}).join(\":\");this.setAndClose(a)},onResetButton:function(){this.setAndClose(this.resetValue)},onCloseButton:function(){this.$refs.control.hide(!0)},onShow:function(){this.isVisible=!0},onShown:function(){var e=this;this.$nextTick(function(){we(e.$refs.time),e.$emit(Dr)})},onHidden:function(){this.isVisible=!1,this.$emit(Pt)},defaultButtonFn:function(e){var r=e.isHovered,n=e.hasFocus;return this.$createElement(r||n?gV:mV,{attrs:{\"aria-hidden\":\"true\"}})}},render:function(e){var r=this.localHMS,n=this.disabled,i=this.readonly,a=this.$props,o=Ge(this.placeholder)?this.labelNoTimeSelected:this.placeholder,s=[];if(this.nowButton){var l=this.labelNowButton;s.push(e(Qr,{props:{size:\"sm\",disabled:n||i,variant:this.nowButtonVariant},attrs:{\"aria-label\":l||null},on:{click:this.onNowButton},key:\"now-btn\"},l))}if(this.resetButton){s.length>0&&s.push(e(\"span\",\"\\xA0\"));var u=this.labelResetButton;s.push(e(Qr,{props:{size:\"sm\",disabled:n||i,variant:this.resetButtonVariant},attrs:{\"aria-label\":u||null},on:{click:this.onResetButton},key:\"reset-btn\"},u))}if(!this.noCloseButton){s.length>0&&s.push(e(\"span\",\"\\xA0\"));var f=this.labelCloseButton;s.push(e(Qr,{props:{size:\"sm\",disabled:n,variant:this.closeButtonVariant},attrs:{\"aria-label\":f||null},on:{click:this.onCloseButton},key:\"close-btn\"},f))}s.length>0&&(s=[e(\"div\",{staticClass:\"b-form-date-controls d-flex flex-wrap\",class:{\"justify-content-between\":s.length>1,\"justify-content-end\":s.length<2}},s)]);var d=e(MR,{staticClass:\"b-form-time-control\",props:Ii(Ii({},at(NR,a)),{},{value:r,hidden:!this.isVisible}),on:{input:this.onInput,context:this.onContext},ref:\"time\"},s);return e(cR,{staticClass:\"b-form-timepicker\",props:Ii(Ii({},at(IR,a)),{},{id:this.safeId(),value:r,formattedValue:r?this.formattedValue:\"\",placeholder:o,rtl:this.isRTL,lang:this.computedLang}),on:{show:this.onShow,shown:this.onShown,hidden:this.onHidden},scopedSlots:Tf({},Wi,this.$scopedSlots[Wi]||this.defaultButtonFn),ref:\"control\"},[d])}}),U8=ae({components:{BFormTimepicker:BS,BTimepicker:BS}}),G8=ae({components:{BImg:Wb,BImgLazy:CA}}),W8=z({tag:c(g,\"div\")},NC),Ed=I({name:NC,functional:!0,props:W8,render:function(e,r){var n=r.props,i=r.data,a=r.children;return e(n.tag,oe(i,{staticClass:\"input-group-text\"}),a)}}),cy=z({append:c(_,!1),id:c(g),isText:c(_,!1),tag:c(g,\"div\")},RC),fy=I({name:RC,functional:!0,props:cy,render:function(e,r){var n=r.props,i=r.data,a=r.children,o=n.append;return e(n.tag,oe(i,{class:{\"input-group-append\":o,\"input-group-prepend\":!o},attrs:{id:n.id}}),n.isText?[e(Ed,a)]:a)}});function kS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function LS(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?kS(Object(r),!0).forEach(function(n){K8(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):kS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function K8(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Y8=z(Pe(cy,[\"append\"]),xC),BR=I({name:xC,functional:!0,props:Y8,render:function(e,r){var n=r.props,i=r.data,a=r.children;return e(fy,oe(i,{props:LS(LS({},n),{},{append:!0})}),a)}});function FS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function jS(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?FS(Object(r),!0).forEach(function(n){q8(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):FS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function q8(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var X8=z(Pe(cy,[\"append\"]),MC),kR=I({name:MC,functional:!0,props:X8,render:function(e,r){var n=r.props,i=r.data,a=r.children;return e(fy,oe(i,{props:jS(jS({},n),{},{append:!1})}),a)}});function J8(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Z8=z({append:c(g),appendHtml:c(g),id:c(g),prepend:c(g),prependHtml:c(g),size:c(g),tag:c(g,\"div\")},AC),Q8=I({name:AC,functional:!0,props:Z8,render:function(e,r){var n=r.props,i=r.data,a=r.slots,o=r.scopedSlots,s=n.prepend,l=n.prependHtml,u=n.append,f=n.appendHtml,d=n.size,p=o||{},h=a(),b={},y=e(),P=Ki(K_,p,h);(P||s||l)&&(y=e(kR,[P?rr(K_,b,p,h):e(Ed,{domProps:dt(l,s)})]));var C=e(),R=Ki(F_,p,h);return(R||u||f)&&(C=e(BR,[R?rr(F_,b,p,h):e(Ed,{domProps:dt(f,u)})])),e(n.tag,oe(i,{staticClass:\"input-group\",class:J8({},\"input-group-\".concat(d),d),attrs:{id:n.id||null,role:\"group\"}}),[y,rr(kt,b,p,h),C])}}),eU=ae({components:{BInputGroup:Q8,BInputGroupAddon:fy,BInputGroupPrepend:kR,BInputGroupAppend:BR,BInputGroupText:Ed}});function tU(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var rU=z({fluid:c(_r,!1),tag:c(g,\"div\")},X$),LR=I({name:X$,functional:!0,props:rU,render:function(e,r){var n=r.props,i=r.data,a=r.children,o=n.fluid;return e(n.tag,oe(i,{class:tU({container:!(o||o===\"\"),\"container-fluid\":o===!0||o===\"\"},\"container-\".concat(o),o&&o!==!0)}),a)}});function Bl(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var nU=z({bgVariant:c(g),borderVariant:c(g),containerFluid:c(_r,!1),fluid:c(_,!1),header:c(g),headerHtml:c(g),headerLevel:c(re,3),headerTag:c(g,\"h1\"),lead:c(g),leadHtml:c(g),leadTag:c(g,\"p\"),tag:c(g,\"div\"),textVariant:c(g)},IC),iU=I({name:IC,functional:!0,props:nU,render:function(e,r){var n,i=r.props,a=r.data,o=r.slots,s=r.scopedSlots,l=i.header,u=i.headerHtml,f=i.lead,d=i.leadHtml,p=i.textVariant,h=i.bgVariant,b=i.borderVariant,y=s||{},P=o(),C={},R=e(),D=Ki(Ca,y,P);if(D||l||u){var B=i.headerLevel;R=e(i.headerTag,{class:Bl({},\"display-\".concat(B),B),domProps:D?{}:dt(u,l)},rr(Ca,C,y,P))}var A=e(),V=Ki(U_,y,P);(V||f||d)&&(A=e(i.leadTag,{staticClass:\"lead\",domProps:V?{}:dt(d,f)},rr(U_,C,y,P)));var N=[R,A,rr(kt,C,y,P)];return i.fluid&&(N=[e(LR,{props:{fluid:i.containerFluid}},N)]),e(i.tag,oe(a,{staticClass:\"jumbotron\",class:(n={\"jumbotron-fluid\":i.fluid},Bl(n,\"text-\".concat(p),p),Bl(n,\"bg-\".concat(h),h),Bl(n,\"border-\".concat(b),b),Bl(n,\"border\",b),n)}),N)}}),aU=ae({components:{BJumbotron:iU}});function VS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function HS(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?VS(Object(r),!0).forEach(function(n){Sf(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):VS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Sf(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var _v=[\"start\",\"end\",\"center\"],oU=Ku(function(t,e){return e=ya(ce(e)),e?od([\"row-cols\",t,e].filter(pe).join(\"-\")):null}),sU=Ku(function(t){return od(t.replace(\"cols\",\"\"))}),FR=[],lU=function(){var e=xu().reduce(function(r,n){return r[Oa(n,\"cols\")]=c(re),r},va(null));return FR=ge(e),z(ie(HS(HS({},e),{},{alignContent:c(g,null,function(r){return he(Me(_v,\"between\",\"around\",\"stretch\"),r)}),alignH:c(g,null,function(r){return he(Me(_v,\"between\",\"around\"),r)}),alignV:c(g,null,function(r){return he(Me(_v,\"baseline\",\"stretch\"),r)}),noGutters:c(_,!1),tag:c(g,\"div\")})),ZC)},uU={name:ZC,functional:!0,get props(){return delete this.props,this.props=lU(),this.props},render:function(e,r){var n,i=r.props,a=r.data,o=r.children,s=i.alignV,l=i.alignH,u=i.alignContent,f=[];return FR.forEach(function(d){var p=oU(sU(d),i[d]);p&&f.push(p)}),f.push((n={\"no-gutters\":i.noGutters},Sf(n,\"align-items-\".concat(s),s),Sf(n,\"justify-content-\".concat(l),l),Sf(n,\"align-content-\".concat(u),u),n)),e(i.tag,oe(a,{staticClass:\"row\",class:f}),o)}},cU=ae({components:{BContainer:LR,BRow:uU,BCol:Of,BFormRow:Td}}),fU=ae({components:{BLink:tn}});function dU(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var pU=z({flush:c(_,!1),horizontal:c(_r,!1),tag:c(g,\"div\")},BC),hU=I({name:BC,functional:!0,props:pU,render:function(e,r){var n=r.props,i=r.data,a=r.children,o=n.horizontal===\"\"?!0:n.horizontal;o=n.flush?!1:o;var s={staticClass:\"list-group\",class:dU({\"list-group-flush\":n.flush,\"list-group-horizontal\":o===!0},\"list-group-horizontal-\".concat(o),Ae(o))};return e(n.tag,oe(i,s),a)}});function zS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function US(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?zS(Object(r),!0).forEach(function(n){nu(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):zS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function nu(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var vU=[\"a\",\"router-link\",\"button\",\"b-link\"],Np=Pe(ei,[\"event\",\"routerTag\"]);delete Np.href.default;delete Np.to.default;var mU=z(ie(US(US({},Np),{},{action:c(_,!1),button:c(_,!1),tag:c(g,\"div\"),variant:c(g)})),kC),gU=I({name:kC,functional:!0,props:mU,render:function(e,r){var n,i=r.props,a=r.data,o=r.children,s=i.button,l=i.variant,u=i.active,f=i.disabled,d=Yu(i),p=s?\"button\":d?tn:i.tag,h=!!(i.action||d||s||he(vU,i.tag)),b={},y={};return wi(p,\"button\")?((!a.attrs||!a.attrs.type)&&(b.type=\"button\"),i.disabled&&(b.disabled=!0)):y=at(Np,i),e(p,oe(a,{attrs:b,props:y,staticClass:\"list-group-item\",class:(n={},nu(n,\"list-group-item-\".concat(l),l),nu(n,\"list-group-item-action\",h),nu(n,\"active\",u),nu(n,\"disabled\",f),n)}),o)}}),bU=ae({components:{BListGroup:hU,BListGroupItem:gU}});function yU(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var OU=z({right:c(_,!1),tag:c(g,\"div\"),verticalAlign:c(g,\"top\")},FC),jR=I({name:FC,functional:!0,props:OU,render:function(e,r){var n=r.props,i=r.data,a=r.children,o=n.verticalAlign,s=o===\"top\"?\"start\":o===\"bottom\"?\"end\":o;return e(n.tag,oe(i,{staticClass:\"media-aside\",class:yU({\"media-aside-right\":n.right},\"align-self-\".concat(s),s)}),a)}}),_U=z({tag:c(g,\"div\")},jC),VR=I({name:jC,functional:!0,props:_U,render:function(e,r){var n=r.props,i=r.data,a=r.children;return e(n.tag,oe(i,{staticClass:\"media-body\"}),a)}}),wU=z({noBody:c(_,!1),rightAlign:c(_,!1),tag:c(g,\"div\"),verticalAlign:c(g,\"top\")},LC),TU=I({name:LC,functional:!0,props:wU,render:function(e,r){var n=r.props,i=r.data,a=r.slots,o=r.scopedSlots,s=r.children,l=n.noBody,u=n.rightAlign,f=n.verticalAlign,d=l?s:[];if(!l){var p={},h=a(),b=o||{};d.push(e(VR,rr(kt,p,b,h)));var y=rr(jj,p,b,h);y&&d[u?\"push\":\"unshift\"](e(jR,{props:{right:u,verticalAlign:f}},y))}return e(n.tag,oe(i,{staticClass:\"media\"}),d)}}),SU=ae({components:{BMedia:TU,BMediaAside:jR,BMediaBody:VR}}),sn=\"$_documentListeners\",PU=I({created:function(){this[sn]={}},beforeDestroy:function(){var e=this;ge(this[sn]||{}).forEach(function(r){e[sn][r].forEach(function(n){e.listenOffDocument(r,n)})}),this[sn]=null},methods:{registerDocumentListener:function(e,r){this[sn]&&(this[sn][e]=this[sn][e]||[],he(this[sn][e],r)||this[sn][e].push(r))},unregisterDocumentListener:function(e,r){this[sn]&&this[sn][e]&&(this[sn][e]=this[sn][e].filter(function(n){return n!==r}))},listenDocument:function(e,r,n){e?this.listenOnDocument(r,n):this.listenOffDocument(r,n)},listenOnDocument:function(e,r){Je&&(it(document,e,r,De),this.registerDocumentListener(e,r))},listenOffDocument:function(e,r){Je&&ft(document,e,r,De),this.unregisterDocumentListener(e,r)}}}),ln=\"$_windowListeners\",EU=I({created:function(){this[ln]={}},beforeDestroy:function(){var e=this;ge(this[ln]||{}).forEach(function(r){e[ln][r].forEach(function(n){e.listenOffWindow(r,n)})}),this[ln]=null},methods:{registerWindowListener:function(e,r){this[ln]&&(this[ln][e]=this[ln][e]||[],he(this[ln][e],r)||this[ln][e].push(r))},unregisterWindowListener:function(e,r){this[ln]&&this[ln][e]&&(this[ln][e]=this[ln][e].filter(function(n){return n!==r}))},listenWindow:function(e,r,n){e?this.listenOnWindow(r,n):this.listenOffWindow(r,n)},listenOnWindow:function(e,r){Je&&(it(window,e,r,De),this.registerWindowListener(e,r))},listenOffWindow:function(e,r){Je&&ft(window,e,r,De),this.unregisterWindowListener(e,r)}}}),Ba=I({computed:{bvParent:function(){return this.$parent||this.$root===this&&this.$options.bvParent}}}),js=function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:null;return e&&e.$options._scopeId||r};function $U(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var dy=I({mixins:[Ba],computed:{scopedStyleAttrs:function(){var e=js(this.bvParent);return e?$U({},e,\"\"):{}}}});function GS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function WS(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?GS(Object(r),!0).forEach(function(n){CU(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):GS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function CU(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var ka=function(e,r){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},i=e.$root?e.$root.$options.bvEventRoot||e.$root:null;return new r(WS(WS({},n),{},{parent:e,bvParent:e,bvEventRoot:i}))},DU=I({abstract:!0,name:uj,props:{nodes:c(MD)},data:function(e){return{updatedNodes:e.nodes}},destroyed:function(){M2(this.$el)},render:function(e){var r=this.updatedNodes,n=se(r)?r({}):r;return n=Me(n).filter(pe),n&&n.length>0&&!n[0].text?n[0]:e()}}),HR={container:c([ba,g],\"body\"),disabled:c(_,!1),tag:c(g,\"div\")},AU=I({name:gD,mixins:[ve],props:HR,watch:{disabled:{immediate:!0,handler:function(e){e?this.unmountTarget():this.$nextTick(this.mountTarget)}}},created:function(){this.$_defaultFn=null,this.$_target=null},beforeMount:function(){this.mountTarget()},updated:function(){this.updateTarget()},beforeDestroy:function(){this.unmountTarget(),this.$_defaultFn=null},methods:{getContainer:function(){if(Je){var e=this.container;return Ae(e)?gn(e):e}else return null},mountTarget:function(){if(!this.$_target){var e=this.getContainer();if(e){var r=document.createElement(\"div\");e.appendChild(r),this.$_target=ka(this,DU,{el:r,propsData:{nodes:Me(this.normalizeSlot())}})}}},updateTarget:function(){if(Je&&this.$_target){var e=this.$scopedSlots.default;this.disabled||(e&&this.$_defaultFn!==e?this.$_target.updatedNodes=e:e||(this.$_target.updatedNodes=this.$slots.default)),this.$_defaultFn=e}},unmountTarget:function(){this.$_target&&this.$_target.$destroy(),this.$_target=null}},render:function(e){if(this.disabled){var r=Me(this.normalizeSlot()).filter(pe);if(r.length>0&&!r[0].text)return r[0]}return e()}}),RU=I({name:gD,mixins:[ve],props:HR,render:function(e){if(this.disabled){var r=Me(this.normalizeSlot()).filter(pe);if(r.length>0)return r[0]}return e(ye.Teleport,{to:this.container},this.normalizeSlot())}}),xU=Nr?RU:AU;function gg(t){return gg=typeof Symbol==\"function\"&&typeof Symbol.iterator==\"symbol\"?function(e){return typeof e}:function(e){return e&&typeof Symbol==\"function\"&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},gg(t)}function KS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function YS(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?KS(Object(r),!0).forEach(function(n){MU(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):KS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function MU(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function NU(t,e){if(!(t instanceof e))throw new TypeError(\"Cannot call a class as a function\")}function qS(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,\"value\"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}function IU(t,e,r){return e&&qS(t.prototype,e),r&&qS(t,r),Object.defineProperty(t,\"prototype\",{writable:!1}),t}function Pf(){return typeof Reflect<\"u\"&&Reflect.get?Pf=Reflect.get:Pf=function(e,r,n){var i=BU(e,r);if(!!i){var a=Object.getOwnPropertyDescriptor(i,r);return a.get?a.get.call(arguments.length<3?e:n):a.value}},Pf.apply(this,arguments)}function BU(t,e){for(;!Object.prototype.hasOwnProperty.call(t,e)&&(t=Vs(t),t!==null););return t}function kU(t,e){if(typeof e!=\"function\"&&e!==null)throw new TypeError(\"Super expression must either be null or a function\");Object.defineProperty(t,\"prototype\",{value:Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),writable:!1}),e&&bg(t,e)}function bg(t,e){return bg=Object.setPrototypeOf||function(n,i){return n.__proto__=i,n},bg(t,e)}function LU(t){var e=jU();return function(){var n=Vs(t),i;if(e){var a=Vs(this).constructor;i=Reflect.construct(n,arguments,a)}else i=n.apply(this,arguments);return FU(this,i)}}function FU(t,e){if(e&&(gg(e)===\"object\"||typeof e==\"function\"))return e;if(e!==void 0)throw new TypeError(\"Derived constructors may only return object or undefined\");return zR(t)}function zR(t){if(t===void 0)throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");return t}function jU(){if(typeof Reflect>\"u\"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy==\"function\")return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch{return!1}}function Vs(t){return Vs=Object.setPrototypeOf?Object.getPrototypeOf:function(r){return r.__proto__||Object.getPrototypeOf(r)},Vs(t)}var VU=function(t){kU(r,t);var e=LU(r);function r(n){var i,a=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return NU(this,r),i=e.call(this,n,a),ip(zR(i),{trigger:xn()}),i}return IU(r,null,[{key:\"Defaults\",get:function(){return YS(YS({},Pf(Vs(r),\"Defaults\",this)),{},{trigger:null})}}]),r}(ko),XS=1040,HU=\".fixed-top, .fixed-bottom, .is-fixed, .sticky-top\",zU=\".sticky-top\",UU=\".navbar-toggler\",GU=I({data:function(){return{modals:[],baseZIndex:null,scrollbarWidth:null,isBodyOverflowing:!1}},computed:{modalCount:function(){return this.modals.length},modalsAreOpen:function(){return this.modalCount>0}},watch:{modalCount:function(e,r){Je&&(this.getScrollbarWidth(),e>0&&r===0?(this.checkScrollbar(),this.setScrollbar(),$r(document.body,\"modal-open\")):e===0&&r>0&&(this.resetScrollbar(),hr(document.body,\"modal-open\")),st(document.body,\"data-modal-open-count\",String(e)))},modals:function(e){var r=this;this.checkScrollbar(),We(function(){r.updateModals(e||[])})}},methods:{registerModal:function(e){e&&this.modals.indexOf(e)===-1&&this.modals.push(e)},unregisterModal:function(e){var r=this.modals.indexOf(e);r>-1&&(this.modals.splice(r,1),!e._isBeingDestroyed&&!e._isDestroyed&&this.resetModal(e))},getBaseZIndex:function(){if(Je&&nt(this.baseZIndex)){var e=document.createElement(\"div\");$r(e,\"modal-backdrop\"),$r(e,\"d-none\"),lr(e,\"display\",\"none\"),document.body.appendChild(e),this.baseZIndex=ee(hn(e).zIndex,XS),document.body.removeChild(e)}return this.baseZIndex||XS},getScrollbarWidth:function(){if(Je&&nt(this.scrollbarWidth)){var e=document.createElement(\"div\");$r(e,\"modal-scrollbar-measure\"),document.body.appendChild(e),this.scrollbarWidth=Ro(e).width-e.clientWidth,document.body.removeChild(e)}return this.scrollbarWidth||0},updateModals:function(e){var r=this,n=this.getBaseZIndex(),i=this.getScrollbarWidth();e.forEach(function(a,o){a.zIndex=n+o,a.scrollbarWidth=i,a.isTop=o===r.modals.length-1,a.isBodyOverflowing=r.isBodyOverflowing})},resetModal:function(e){e&&(e.zIndex=this.getBaseZIndex(),e.isTop=!0,e.isBodyOverflowing=!1)},checkScrollbar:function(){var e=Ro(document.body),r=e.left,n=e.right;this.isBodyOverflowing=r+n<window.innerWidth},setScrollbar:function(){var e=document.body;if(e._paddingChangedForModal=e._paddingChangedForModal||[],e._marginChangedForModal=e._marginChangedForModal||[],this.isBodyOverflowing){var r=this.scrollbarWidth;yn(HU).forEach(function(i){var a=ws(i,\"paddingRight\")||\"\";st(i,\"data-padding-right\",a),lr(i,\"paddingRight\",\"\".concat(Ee(hn(i).paddingRight,0)+r,\"px\")),e._paddingChangedForModal.push(i)}),yn(zU).forEach(function(i){var a=ws(i,\"marginRight\")||\"\";st(i,\"data-margin-right\",a),lr(i,\"marginRight\",\"\".concat(Ee(hn(i).marginRight,0)-r,\"px\")),e._marginChangedForModal.push(i)}),yn(UU).forEach(function(i){var a=ws(i,\"marginRight\")||\"\";st(i,\"data-margin-right\",a),lr(i,\"marginRight\",\"\".concat(Ee(hn(i).marginRight,0)+r,\"px\")),e._marginChangedForModal.push(i)});var n=ws(e,\"paddingRight\")||\"\";st(e,\"data-padding-right\",n),lr(e,\"paddingRight\",\"\".concat(Ee(hn(e).paddingRight,0)+r,\"px\"))}},resetScrollbar:function(){var e=document.body;e._paddingChangedForModal&&e._paddingChangedForModal.forEach(function(r){mi(r,\"data-padding-right\")&&(lr(r,\"paddingRight\",bn(r,\"data-padding-right\")||\"\"),vi(r,\"data-padding-right\"))}),e._marginChangedForModal&&e._marginChangedForModal.forEach(function(r){mi(r,\"data-margin-right\")&&(lr(r,\"marginRight\",bn(r,\"data-margin-right\")||\"\"),vi(r,\"data-margin-right\"))}),e._paddingChangedForModal=null,e._marginChangedForModal=null,mi(e,\"data-padding-right\")&&(lr(e,\"paddingRight\",bn(e,\"data-padding-right\")||\"\"),vi(e,\"data-padding-right\"))}}}),os=new GU;function JS(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function da(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?JS(Object(r),!0).forEach(function(n){un(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):JS(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function un(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Ip=Nt(\"visible\",{type:_,defaultValue:!1,event:en}),WU=Ip.mixin,KU=Ip.props,wv=Ip.prop,YU=Ip.event,qU=\"backdrop\",XU=\"esc\",JU=\"FORCE\",ZU=\"toggle\",Ef=\"cancel\",$f=\"headerclose\",Cf=\"ok\",QU=[Ef,$f,Cf],eG={subtree:!0,childList:!0,characterData:!0,attributes:!0,attributeFilter:[\"style\",\"class\"]},UR=z(ie(da(da(da({},Ke),KU),{},{ariaLabel:c(g),autoFocusButton:c(g,null,function(t){return Ge(t)||he(QU,t)}),bodyBgVariant:c(g),bodyClass:c(de),bodyTextVariant:c(g),busy:c(_,!1),buttonSize:c(g),cancelDisabled:c(_,!1),cancelTitle:c(g,\"Cancel\"),cancelTitleHtml:c(g),cancelVariant:c(g,\"secondary\"),centered:c(_,!1),contentClass:c(de),dialogClass:c(de),footerBgVariant:c(g),footerBorderVariant:c(g),footerClass:c(de),footerTag:c(g,\"footer\"),footerTextVariant:c(g),headerBgVariant:c(g),headerBorderVariant:c(g),headerClass:c(de),headerCloseContent:c(g,\"&times;\"),headerCloseLabel:c(g,\"Close\"),headerCloseVariant:c(g),headerTag:c(g,\"header\"),headerTextVariant:c(g),hideBackdrop:c(_,!1),hideFooter:c(_,!1),hideHeader:c(_,!1),hideHeaderClose:c(_,!1),ignoreEnforceFocusSelector:c(Or),lazy:c(_,!1),modalClass:c(de),noCloseOnBackdrop:c(_,!1),noCloseOnEsc:c(_,!1),noEnforceFocus:c(_,!1),noFade:c(_,!1),noStacking:c(_,!1),okDisabled:c(_,!1),okOnly:c(_,!1),okTitle:c(g,\"OK\"),okTitleHtml:c(g),okVariant:c(g,\"primary\"),returnFocus:c([ba,Mt,g]),scrollable:c(_,!1),size:c(g,\"md\"),static:c(_,!1),title:c(g),titleClass:c(de),titleHtml:c(g),titleSrOnly:c(_,!1),titleTag:c(g,\"h5\")})),Gr),GR=I({name:Gr,mixins:[Vt,Ze,WU,PU,Qn,EU,ve,dy],inheritAttrs:!1,props:UR,data:function(){return{isHidden:!0,isVisible:!1,isTransitioning:!1,isShow:!1,isBlock:!1,isOpening:!1,isClosing:!1,ignoreBackdropClick:!1,isModalOverflowing:!1,scrollbarWidth:0,zIndex:os.getBaseZIndex(),isTop:!0,isBodyOverflowing:!1}},computed:{modalId:function(){return this.safeId()},modalOuterId:function(){return this.safeId(\"__BV_modal_outer_\")},modalHeaderId:function(){return this.safeId(\"__BV_modal_header_\")},modalBodyId:function(){return this.safeId(\"__BV_modal_body_\")},modalTitleId:function(){return this.safeId(\"__BV_modal_title_\")},modalContentId:function(){return this.safeId(\"__BV_modal_content_\")},modalFooterId:function(){return this.safeId(\"__BV_modal_footer_\")},modalBackdropId:function(){return this.safeId(\"__BV_modal_backdrop_\")},modalClasses:function(){return[{fade:!this.noFade,show:this.isShow},this.modalClass]},modalStyles:function(){var e=\"\".concat(this.scrollbarWidth,\"px\");return{paddingLeft:!this.isBodyOverflowing&&this.isModalOverflowing?e:\"\",paddingRight:this.isBodyOverflowing&&!this.isModalOverflowing?e:\"\",display:this.isBlock?\"block\":\"none\"}},dialogClasses:function(){var e;return[(e={},un(e,\"modal-\".concat(this.size),this.size),un(e,\"modal-dialog-centered\",this.centered),un(e,\"modal-dialog-scrollable\",this.scrollable),e),this.dialogClass]},headerClasses:function(){var e;return[(e={},un(e,\"bg-\".concat(this.headerBgVariant),this.headerBgVariant),un(e,\"text-\".concat(this.headerTextVariant),this.headerTextVariant),un(e,\"border-\".concat(this.headerBorderVariant),this.headerBorderVariant),e),this.headerClass]},titleClasses:function(){return[{\"sr-only\":this.titleSrOnly},this.titleClass]},bodyClasses:function(){var e;return[(e={},un(e,\"bg-\".concat(this.bodyBgVariant),this.bodyBgVariant),un(e,\"text-\".concat(this.bodyTextVariant),this.bodyTextVariant),e),this.bodyClass]},footerClasses:function(){var e;return[(e={},un(e,\"bg-\".concat(this.footerBgVariant),this.footerBgVariant),un(e,\"text-\".concat(this.footerTextVariant),this.footerTextVariant),un(e,\"border-\".concat(this.footerBorderVariant),this.footerBorderVariant),e),this.footerClass]},modalOuterStyle:function(){return{position:\"absolute\",zIndex:this.zIndex}},slotScope:function(){return{cancel:this.onCancel,close:this.onClose,hide:this.hide,ok:this.onOk,visible:this.isVisible}},computeIgnoreEnforceFocusSelector:function(){return Me(this.ignoreEnforceFocusSelector).filter(pe).join(\",\").trim()},computedAttrs:function(){var e=this.static?{}:this.scopedStyleAttrs;return da(da(da({},e),this.bvAttrs),{},{id:this.modalOuterId})},computedModalAttrs:function(){var e=this.isVisible,r=this.ariaLabel;return{id:this.modalId,role:\"dialog\",\"aria-hidden\":e?null:\"true\",\"aria-modal\":e?\"true\":null,\"aria-label\":r,\"aria-labelledby\":this.hideHeader||r||!(this.hasNormalizedSlot(Wh)||this.titleHtml||this.title)?null:this.modalTitleId,\"aria-describedby\":this.modalBodyId}}},watch:un({},wv,function(t,e){t!==e&&this[t?\"show\":\"hide\"]()}),created:function(){this.$_observer=null,this.$_returnFocus=this.returnFocus||null},mounted:function(){this.zIndex=os.getBaseZIndex(),this.listenOnRoot(xt(Gr,tr),this.showHandler),this.listenOnRoot(xt(Gr,Xr),this.hideHandler),this.listenOnRoot(xt(Gr,DD),this.toggleHandler),this.listenOnRoot(bt(Gr,tr),this.modalListener),this[wv]===!0&&this.$nextTick(this.show)},beforeDestroy:function(){os.unregisterModal(this),this.setObserver(!1),this.isVisible&&(this.isVisible=!1,this.isShow=!1,this.isTransitioning=!1)},methods:{setObserver:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:!1;this.$_observer&&this.$_observer.disconnect(),this.$_observer=null,e&&(this.$_observer=Iu(this.$refs.content,this.checkModalOverflow.bind(this),eG))},updateModel:function(e){e!==this[wv]&&this.$emit(YU,e)},buildEvent:function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return new VU(e,da(da({cancelable:!1,target:this.$refs.modal||this.$el||null,relatedTarget:null,trigger:null},r),{},{vueTarget:this,componentId:this.modalId}))},show:function(){if(!(this.isVisible||this.isOpening)){if(this.isClosing){this.$once(Pt,this.show);return}this.isOpening=!0,this.$_returnFocus=this.$_returnFocus||this.getActiveElement();var e=this.buildEvent(tr,{cancelable:!0});if(this.emitEvent(e),e.defaultPrevented||this.isVisible){this.isOpening=!1,this.updateModel(!1);return}this.doShow()}},hide:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:\"\";if(!(!this.isVisible||this.isClosing)){this.isClosing=!0;var r=this.buildEvent(Xr,{cancelable:e!==JU,trigger:e||null});if(e===Cf?this.$emit(gj,r):e===Ef?this.$emit(fj,r):e===$f&&this.$emit(Bm,r),this.emitEvent(r),r.defaultPrevented||!this.isVisible){this.isClosing=!1,this.updateModel(!0);return}this.setObserver(!1),this.isVisible=!1,this.updateModel(!1)}},toggle:function(e){e&&(this.$_returnFocus=e),this.isVisible?this.hide(ZU):this.show()},getActiveElement:function(){var e=Da(Je?[document.body]:[]);return e&&e.focus?e:null},doShow:function(){var e=this;if(os.modalsAreOpen&&this.noStacking){this.listenOnRootOnce(bt(Gr,Pt),this.doShow);return}os.registerModal(this),this.isHidden=!1,this.$nextTick(function(){e.isVisible=!0,e.isOpening=!1,e.updateModel(!0),e.$nextTick(function(){e.setObserver(!0)})})},onBeforeEnter:function(){this.isTransitioning=!0,this.setResizeEvent(!0)},onEnter:function(){var e=this;this.isBlock=!0,We(function(){We(function(){e.isShow=!0})})},onAfterEnter:function(){var e=this;this.checkModalOverflow(),this.isTransitioning=!1,We(function(){e.emitEvent(e.buildEvent(Dr)),e.setEnforceFocus(!0),e.$nextTick(function(){e.focusFirst()})})},onBeforeLeave:function(){this.isTransitioning=!0,this.setResizeEvent(!1),this.setEnforceFocus(!1)},onLeave:function(){this.isShow=!1},onAfterLeave:function(){var e=this;this.isBlock=!1,this.isTransitioning=!1,this.isModalOverflowing=!1,this.isHidden=!0,this.$nextTick(function(){e.isClosing=!1,os.unregisterModal(e),e.returnFocusTo(),e.emitEvent(e.buildEvent(Pt))})},emitEvent:function(e){var r=e.type;this.emitOnRoot(bt(Gr,r),e,e.componentId),this.$emit(r,e)},onDialogMousedown:function(){var e=this,r=this.$refs.modal,n=function i(a){ft(r,\"mouseup\",i,De),a.target===r&&(e.ignoreBackdropClick=!0)};it(r,\"mouseup\",n,De)},onClickOut:function(e){if(this.ignoreBackdropClick){this.ignoreBackdropClick=!1;return}!this.isVisible||this.noCloseOnBackdrop||!Rt(document.body,e.target)||Rt(this.$refs.content,e.target)||this.hide(qU)},onOk:function(){this.hide(Cf)},onCancel:function(){this.hide(Ef)},onClose:function(){this.hide($f)},onEsc:function(e){e.keyCode===Fb&&this.isVisible&&!this.noCloseOnEsc&&this.hide(XU)},focusHandler:function(e){var r=this.$refs.content,n=e.target;if(!(this.noEnforceFocus||!this.isTop||!this.isVisible||!r||document===n||Rt(r,n)||this.computeIgnoreEnforceFocusSelector&&Jr(this.computeIgnoreEnforceFocusSelector,n,!0))){var i=zm(this.$refs.content),a=this.$refs[\"bottom-trap\"],o=this.$refs[\"top-trap\"];if(a&&n===a){if(we(i[0]))return}else if(o&&n===o&&we(i[i.length-1]))return;we(r,{preventScroll:!0})}},setEnforceFocus:function(e){this.listenDocument(e,\"focusin\",this.focusHandler)},setResizeEvent:function(e){this.listenWindow(e,\"resize\",this.checkModalOverflow),this.listenWindow(e,\"orientationchange\",this.checkModalOverflow)},showHandler:function(e,r){e===this.modalId&&(this.$_returnFocus=r||this.getActiveElement(),this.show())},hideHandler:function(e){e===this.modalId&&this.hide(\"event\")},toggleHandler:function(e,r){e===this.modalId&&this.toggle(r)},modalListener:function(e){this.noStacking&&e.vueTarget!==this&&this.hide()},focusFirst:function(){var e=this;Je&&We(function(){var r=e.$refs.modal,n=e.$refs.content,i=e.getActiveElement();if(r&&n&&!(i&&Rt(n,i))){var a=e.$refs[\"ok-button\"],o=e.$refs[\"cancel-button\"],s=e.$refs[\"close-button\"],l=e.autoFocusButton,u=l===Cf&&a?a.$el||a:l===Ef&&o?o.$el||o:l===$f&&s?s.$el||s:n;we(u),u===n&&e.$nextTick(function(){r.scrollTop=0})}})},returnFocusTo:function(){var e=this.returnFocus||this.$_returnFocus||null;this.$_returnFocus=null,this.$nextTick(function(){e=Ae(e)?gn(e):e,e&&(e=e.$el||e,we(e))})},checkModalOverflow:function(){if(this.isVisible){var e=this.$refs.modal;this.isModalOverflowing=e.scrollHeight>document.documentElement.clientHeight}},makeModal:function(e){var r=e();if(!this.hideHeader){var n=this.normalizeSlot(o2,this.slotScope);if(!n){var i=e();this.hideHeaderClose||(i=e(xo,{props:{content:this.headerCloseContent,disabled:this.isTransitioning,ariaLabel:this.headerCloseLabel,textVariant:this.headerCloseVariant||this.headerTextVariant},on:{click:this.onClose},ref:\"close-button\"},[this.normalizeSlot(s2)])),n=[e(this.titleTag,{staticClass:\"modal-title\",class:this.titleClasses,attrs:{id:this.modalTitleId},domProps:this.hasNormalizedSlot(Wh)?{}:dt(this.titleHtml,this.title)},this.normalizeSlot(Wh,this.slotScope)),i]}r=e(this.headerTag,{staticClass:\"modal-header\",class:this.headerClasses,attrs:{id:this.modalHeaderId},ref:\"header\"},[n])}var a=e(\"div\",{staticClass:\"modal-body\",class:this.bodyClasses,attrs:{id:this.modalBodyId},ref:\"body\"},this.normalizeSlot(kt,this.slotScope)),o=e();if(!this.hideFooter){var s=this.normalizeSlot(a2,this.slotScope);if(!s){var l=e();this.okOnly||(l=e(Qr,{props:{variant:this.cancelVariant,size:this.buttonSize,disabled:this.cancelDisabled||this.busy||this.isTransitioning},domProps:this.hasNormalizedSlot(G_)?{}:dt(this.cancelTitleHtml,this.cancelTitle),on:{click:this.onCancel},ref:\"cancel-button\"},this.normalizeSlot(G_)));var u=e(Qr,{props:{variant:this.okVariant,size:this.buttonSize,disabled:this.okDisabled||this.busy||this.isTransitioning},domProps:this.hasNormalizedSlot(W_)?{}:dt(this.okTitleHtml,this.okTitle),on:{click:this.onOk},ref:\"ok-button\"},this.normalizeSlot(W_));s=[l,u]}o=e(this.footerTag,{staticClass:\"modal-footer\",class:this.footerClasses,attrs:{id:this.modalFooterId},ref:\"footer\"},[s])}var f=e(\"div\",{staticClass:\"modal-content\",class:this.contentClass,attrs:{id:this.modalContentId,tabindex:\"-1\"},ref:\"content\"},[r,a,o]),d=e(),p=e();this.isVisible&&!this.noEnforceFocus&&(d=e(\"span\",{attrs:{tabindex:\"0\"},ref:\"top-trap\"}),p=e(\"span\",{attrs:{tabindex:\"0\"},ref:\"bottom-trap\"}));var h=e(\"div\",{staticClass:\"modal-dialog\",class:this.dialogClasses,on:{mousedown:this.onDialogMousedown},ref:\"dialog\"},[d,f,p]),b=e(\"div\",{staticClass:\"modal\",class:this.modalClasses,style:this.modalStyles,attrs:this.computedModalAttrs,on:{keydown:this.onEsc,click:this.onClickOut},directives:[{name:\"show\",value:this.isVisible}],ref:\"modal\"},[h]);b=e(\"transition\",{props:{enterClass:\"\",enterToClass:\"\",enterActiveClass:\"\",leaveClass:\"\",leaveActiveClass:\"\",leaveToClass:\"\"},on:{beforeEnter:this.onBeforeEnter,enter:this.onEnter,afterEnter:this.onAfterEnter,beforeLeave:this.onBeforeLeave,leave:this.onLeave,afterLeave:this.onAfterLeave}},[b]);var y=e();return!this.hideBackdrop&&this.isVisible&&(y=e(\"div\",{staticClass:\"modal-backdrop\",attrs:{id:this.modalBackdropId}},this.normalizeSlot(i2))),y=e(Io,{props:{noFade:this.noFade}},[y]),e(\"div\",{style:this.modalOuterStyle,attrs:this.computedAttrs,key:\"modal-outer-\".concat(this[ji])},[b,y])}},render:function(e){return this.static?this.lazy&&this.isHidden?e():this.makeModal(e):this.isHidden?e():e(xU,[this.makeModal(e)])}}),tG=xt(Gr,tr),$d=\"__bv_modal_directive__\",WR=function(e){var r=e.modifiers,n=r===void 0?{}:r,i=e.arg,a=e.value;return Ae(a)?a:Ae(i)?i:ge(n).reverse()[0]},KR=function(e){return e&&Vi(e,\".dropdown-menu > li, li.nav-item\")&&gn(\"a, button\",e)||e},YR=function(e){e&&e.tagName!==\"BUTTON\"&&(mi(e,\"role\")||st(e,\"role\",\"button\"),e.tagName!==\"A\"&&!mi(e,\"tabindex\")&&st(e,\"tabindex\",\"0\"))},rG=function(e,r,n){var i=WR(r),a=KR(e);if(i&&a){var o=function(l){var u=l.currentTarget;if(!lo(u)){var f=l.type,d=l.keyCode;(f===\"click\"||f===\"keydown\"&&(d===Ji||d===Ti))&&Oi(gi(n,r)).$emit(tG,i,u)}};e[$d]={handler:o,target:i,trigger:a},YR(a),it(a,\"click\",o,Yr),a.tagName!==\"BUTTON\"&&bn(a,\"role\")===\"button\"&&it(a,\"keydown\",o,Yr)}},qR=function(e){var r=e[$d]||{},n=r.trigger,i=r.handler;n&&i&&(ft(n,\"click\",i,Yr),ft(n,\"keydown\",i,Yr),ft(e,\"click\",i,Yr),ft(e,\"keydown\",i,Yr)),delete e[$d]},ZS=function(e,r,n){var i=e[$d]||{},a=WR(r),o=KR(e);(a!==i.target||o!==i.trigger)&&(qR(e),rG(e,r,n)),YR(o)},nG=function(){},XR={inserted:ZS,updated:nG,componentUpdated:ZS,unbind:qR};function iG(t,e){if(!(t instanceof e))throw new TypeError(\"Cannot call a class as a function\")}function QS(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,\"value\"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}function aG(t,e,r){return e&&QS(t.prototype,e),r&&QS(t,r),Object.defineProperty(t,\"prototype\",{writable:!1}),t}function eP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Ci(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?eP(Object(r),!0).forEach(function(n){oG(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):eP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function oG(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function sG(t){return fG(t)||cG(t)||uG(t)||lG()}function lG(){throw new TypeError(`Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function uG(t,e){if(!!t){if(typeof t==\"string\")return yg(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);if(r===\"Object\"&&t.constructor&&(r=t.constructor.name),r===\"Map\"||r===\"Set\")return Array.from(t);if(r===\"Arguments\"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return yg(t,e)}}function cG(t){if(typeof Symbol<\"u\"&&t[Symbol.iterator]!=null||t[\"@@iterator\"]!=null)return Array.from(t)}function fG(t){if(Array.isArray(t))return yg(t)}function yg(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}var Xa=\"$bvModal\",Tv=\"_bv__modal\",dG=[\"id\"].concat(sG(ge(Pe(UR,[\"busy\",\"lazy\",\"noStacking\",\"static\",\"visible\"])))),pG=function(){},Sv={msgBoxContent:\"default\",title:\"modal-title\",okTitle:\"modal-ok\",cancelTitle:\"modal-cancel\"},tP=function(e){return dG.reduce(function(r,n){return Et(e[n])||(r[n]=e[n]),r},{})},hG=function(e){var r=e.extend({name:XF,extends:GR,mixins:[Ba],destroyed:function(){this.$el&&this.$el.parentNode&&this.$el.parentNode.removeChild(this.$el)},mounted:function(){var s=this,l=function(){s.$nextTick(function(){We(function(){s.$destroy()})})};this.bvParent.$once(Du,l),this.$once(Pt,l),this.$router&&this.$route&&this.$once(AD,this.$watch(\"$router\",l)),this.show()}}),n=function(s,l){var u=arguments.length>2&&arguments[2]!==void 0?arguments[2]:pG;if(!(rd(Xa)||N_(Xa))){var f=ka(s,r,{propsData:Ci(Ci(Ci({},tP(vn(Gr))),{},{hideHeaderClose:!0,hideHeader:!(l.title||l.titleHtml)},Pe(l,ge(Sv))),{},{lazy:!1,busy:!1,visible:!1,noStacking:!1,noEnforceFocus:!1})});return ge(Sv).forEach(function(d){Et(l[d])||(f.$slots[Sv[d]]=Me(l[d]))}),new Promise(function(d,p){var h=!1;f.$once(Du,function(){h||p(new Error(\"BootstrapVue MsgBox destroyed before resolve\"))}),f.$on(Xr,function(y){if(!y.defaultPrevented){var P=u(y);y.defaultPrevented||(h=!0,d(P))}});var b=document.createElement(\"div\");document.body.appendChild(b),f.$mount(b)})}},i=function(s,l){var u=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},f=arguments.length>3&&arguments[3]!==void 0?arguments[3]:null;if(!(!l||N_(Xa)||rd(Xa)||!se(f)))return n(s,Ci(Ci({},tP(u)),{},{msgBoxContent:l}),f)},a=function(){function o(s){iG(this,o),Gu(this,{_vm:s,_root:Oi(s)}),ip(this,{_vm:xn(),_root:xn()})}return aG(o,[{key:\"show\",value:function(l){if(l&&this._root){for(var u,f=arguments.length,d=new Array(f>1?f-1:0),p=1;p<f;p++)d[p-1]=arguments[p];(u=this._root).$emit.apply(u,[xt(Gr,\"show\"),l].concat(d))}}},{key:\"hide\",value:function(l){if(l&&this._root){for(var u,f=arguments.length,d=new Array(f>1?f-1:0),p=1;p<f;p++)d[p-1]=arguments[p];(u=this._root).$emit.apply(u,[xt(Gr,\"hide\"),l].concat(d))}}},{key:\"msgBoxOk\",value:function(l){var u=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},f=Ci(Ci({},u),{},{okOnly:!0,okDisabled:!1,hideFooter:!1,msgBoxContent:l});return i(this._vm,l,f,function(){return!0})}},{key:\"msgBoxConfirm\",value:function(l){var u=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},f=Ci(Ci({},u),{},{okOnly:!1,okDisabled:!1,cancelDisabled:!1,hideFooter:!1});return i(this._vm,l,f,function(d){var p=d.trigger;return p===\"ok\"?!0:p===\"cancel\"?!1:null})}}]),o}();e.mixin({beforeCreate:function(){this[Tv]=new a(this)}}),$o(e.prototype,Xa)||Cb(e.prototype,Xa,{get:function(){return(!this||!this[Tv])&&jt('\"'.concat(Xa,'\" must be accessed from a Vue instance \"this\" context.'),Gr),this[Tv]}})},vG=ae({plugins:{plugin:hG}}),mG=ae({components:{BModal:GR},directives:{VBModal:XR},plugins:{BVModalPlugin:vG}});function rP(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var gG=function(e){return e=e===\"left\"?\"start\":e===\"right\"?\"end\":e,\"justify-content-\".concat(e)},py=z({align:c(g),cardHeader:c(_,!1),fill:c(_,!1),justified:c(_,!1),pills:c(_,!1),small:c(_,!1),tabs:c(_,!1),tag:c(g,\"ul\"),vertical:c(_,!1)},VC),JR=I({name:VC,functional:!0,props:py,render:function(e,r){var n,i=r.props,a=r.data,o=r.children,s=i.tabs,l=i.pills,u=i.vertical,f=i.align,d=i.cardHeader;return e(i.tag,oe(a,{staticClass:\"nav\",class:(n={\"nav-tabs\":s,\"nav-pills\":l&&!s,\"card-header-tabs\":!u&&d&&s,\"card-header-pills\":!u&&d&&l&&!s,\"flex-column\":u,\"nav-fill\":!u&&i.fill,\"nav-justified\":!u&&i.justified},rP(n,gG(f),!u&&f),rP(n,\"small\",i.small),n)}),o)}});function nP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function iP(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?nP(Object(r),!0).forEach(function(n){bG(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):nP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function bG(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var ZR=Pe(ei,[\"event\",\"routerTag\"]),yG=z(ie(iP(iP({},ZR),{},{linkAttrs:c(Mt,{}),linkClasses:c(de)})),KC),OG=I({name:KC,functional:!0,props:yG,render:function(e,r){var n=r.props,i=r.data,a=r.listeners,o=r.children;return e(\"li\",oe(Pe(i,[\"on\"]),{staticClass:\"nav-item\"}),[e(tn,{staticClass:\"nav-link\",class:n.linkClasses,attrs:n.linkAttrs,props:at(ZR,n),on:a},o)])}}),_G={},wG=I({name:JF,functional:!0,props:_G,render:function(e,r){var n=r.data,i=r.children;return e(\"li\",oe(n,{staticClass:\"navbar-text\"}),i)}});function aP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Cd(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?aP(Object(r),!0).forEach(function(n){TG(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):aP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function TG(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var QR=Pe(ny,[\"inline\"]),SG=z(ie(Cd(Cd({},QR),{},{formClass:c(de)})),WC),PG=I({name:WC,functional:!0,props:SG,render:function(e,r){var n=r.props,i=r.data,a=r.children,o=r.listeners,s=e(iy,{class:n.formClass,props:Cd(Cd({},at(QR,n)),{},{inline:!0}),attrs:i.attrs,on:o},a);return e(\"li\",oe(Pe(i,[\"attrs\",\"on\"]),{staticClass:\"form-inline\"}),[s])}});function EG(t){return AG(t)||DG(t)||CG(t)||$G()}function $G(){throw new TypeError(`Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function CG(t,e){if(!!t){if(typeof t==\"string\")return Og(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);if(r===\"Object\"&&t.constructor&&(r=t.constructor.name),r===\"Map\"||r===\"Set\")return Array.from(t);if(r===\"Arguments\"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return Og(t,e)}}function DG(t){if(typeof Symbol<\"u\"&&t[Symbol.iterator]!=null||t[\"@@iterator\"]!=null)return Array.from(t)}function AG(t){if(Array.isArray(t))return Og(t)}function Og(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}function oP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function sP(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?oP(Object(r),!0).forEach(function(n){RG(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):oP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function RG(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var xG=z(ie(sP(sP({},Ke),Zn(QA,[].concat(EG(ge(Op)),[\"html\",\"lazy\",\"menuClass\",\"noCaret\",\"role\",\"text\",\"toggleClass\"])))),YC),zc=I({name:YC,mixins:[Ze,ry,ve],props:xG,computed:{toggleId:function(){return this.safeId(\"_BV_toggle_\")},menuId:function(){return this.safeId(\"_BV_toggle_menu_\")},dropdownClasses:function(){return[this.directionClass,this.boundaryClass,{show:this.visible}]},menuClasses:function(){return[this.menuClass,{\"dropdown-menu-right\":this.right,show:this.visible}]},toggleClasses:function(){return[this.toggleClass,{\"dropdown-toggle-no-caret\":this.noCaret}]}},render:function(e){var r=this.toggleId,n=this.menuId,i=this.visible,a=this.hide,o=e(tn,{staticClass:\"nav-link dropdown-toggle\",class:this.toggleClasses,props:{href:\"#\".concat(this.id||\"\"),disabled:this.disabled},attrs:{id:r,role:\"button\",\"aria-haspopup\":\"true\",\"aria-expanded\":i?\"true\":\"false\",\"aria-controls\":n},on:{mousedown:this.onMousedown,click:this.toggle,keydown:this.toggle},ref:\"toggle\"},[this.normalizeSlot([Wi,w2])||e(\"span\",{domProps:dt(this.html,this.text)})]),s=e(\"ul\",{staticClass:\"dropdown-menu\",class:this.menuClasses,attrs:{tabindex:\"-1\",\"aria-labelledby\":r,id:n},on:{keydown:this.onKeydown},ref:\"menu\"},!this.lazy||i?this.normalizeSlot(kt,{hide:a}):[e()]);return e(\"li\",{staticClass:\"nav-item b-nav-dropdown dropdown\",class:this.dropdownClasses,attrs:{id:this.safeId()}},[o,s])}}),ex=ae({components:{BNav:JR,BNavItem:OG,BNavText:wG,BNavForm:PG,BNavItemDropdown:zc,BNavItemDd:zc,BNavDropdown:zc,BNavDd:zc},plugins:{DropdownPlugin:ay}});function Pv(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var MG=z({fixed:c(g),print:c(_,!1),sticky:c(_,!1),tag:c(g,\"nav\"),toggleable:c(_r,!1),type:c(g,\"light\"),variant:c(g)},HC),NG=I({name:HC,mixins:[ve],provide:function(){var e=this;return{getBvNavbar:function(){return e}}},props:MG,computed:{breakpointClass:function(){var e=this.toggleable,r=FD()[0],n=null;return e&&Ae(e)&&e!==r?n=\"navbar-expand-\".concat(e):e===!1&&(n=\"navbar-expand\"),n}},render:function(e){var r,n=this.tag,i=this.type,a=this.variant,o=this.fixed;return e(n,{staticClass:\"navbar\",class:[(r={\"d-print\":this.print,\"sticky-top\":this.sticky},Pv(r,\"navbar-\".concat(i),i),Pv(r,\"bg-\".concat(a),a),Pv(r,\"fixed-\".concat(o),o),r),this.breakpointClass],attrs:{role:wi(n,\"nav\")?null:\"navigation\"}},[this.normalizeSlot()])}});function lP(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var IG=function(e){return e=e===\"left\"?\"start\":e===\"right\"?\"end\":e,\"justify-content-\".concat(e)},BG=z(Zn(py,[\"tag\",\"fill\",\"justified\",\"align\",\"small\"]),UC),kG=I({name:UC,functional:!0,props:BG,render:function(e,r){var n,i=r.props,a=r.data,o=r.children,s=i.align;return e(i.tag,oe(a,{staticClass:\"navbar-nav\",class:(n={\"nav-fill\":i.fill,\"nav-justified\":i.justified},lP(n,IG(s),s),lP(n,\"small\",i.small),n)}),o)}});function uP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function cP(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?uP(Object(r),!0).forEach(function(n){LG(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):uP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function LG(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Bp=Pe(ei,[\"event\",\"routerTag\"]);Bp.href.default=void 0;Bp.to.default=void 0;var FG=z(ie(cP(cP({},Bp),{},{tag:c(g,\"div\")})),zC),jG=I({name:zC,functional:!0,props:FG,render:function(e,r){var n=r.props,i=r.data,a=r.children,o=n.to||n.href,s=o?tn:n.tag;return e(s,oe(i,{staticClass:\"navbar-brand\",props:o?at(Bp,n):{}}),a)}}),fP=\"navbar-toggler\",VG=bt(fr,\"state\"),HG=bt(fr,\"sync-state\"),zG=z({disabled:c(_,!1),label:c(g,\"Toggle navigation\"),target:c(Or,void 0,!0)},GC),dP=I({name:GC,directives:{VBToggle:BA},mixins:[Qn,ve],props:zG,data:function(){return{toggleState:!1}},created:function(){this.listenOnRoot(VG,this.handleStateEvent),this.listenOnRoot(HG,this.handleStateEvent)},methods:{onClick:function(e){this.disabled||this.$emit(Ln,e)},handleStateEvent:function(e,r){e===this.target&&(this.toggleState=r)}},render:function(e){var r=this.disabled;return e(\"button\",{staticClass:fP,class:{disabled:r},directives:[{name:\"VBToggle\",value:this.target}],attrs:{type:\"button\",disabled:r,\"aria-label\":this.label},on:{click:this.onClick}},[this.normalizeSlot(kt,{expanded:this.toggleState})||e(\"span\",{staticClass:\"\".concat(fP,\"-icon\")})])}}),UG=ae({components:{BNavbar:NG,BNavbarNav:kG,BNavbarBrand:jG,BNavbarToggle:dP,BNavToggle:dP},plugins:{NavPlugin:ex,CollapsePlugin:kA,DropdownPlugin:ay}});function Ev(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var GG=z({label:c(g),role:c(g,\"status\"),small:c(_,!1),tag:c(g,\"span\"),type:c(g,\"border\"),variant:c(g)},aD),tx=I({name:aD,functional:!0,props:GG,render:function(e,r){var n,i=r.props,a=r.data,o=r.slots,s=r.scopedSlots,l=o(),u=s||{},f=rr(BD,{},u,l)||i.label;return f&&(f=e(\"span\",{staticClass:\"sr-only\"},f)),e(i.tag,oe(a,{attrs:{role:f?i.role||\"status\":null,\"aria-hidden\":f?null:\"true\"},class:(n={},Ev(n,\"spinner-\".concat(i.type),i.type),Ev(n,\"spinner-\".concat(i.type,\"-sm\"),i.small),Ev(n,\"text-\".concat(i.variant),i.variant),n)}),[f||e()])}});function pP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function kl(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?pP(Object(r),!0).forEach(function(n){WG(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):pP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function WG(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var $v={top:0,left:0,bottom:0,right:0},KG=z({bgColor:c(g),blur:c(g,\"2px\"),fixed:c(_,!1),noCenter:c(_,!1),noFade:c(_,!1),noWrap:c(_,!1),opacity:c(re,.85,function(t){var e=Ee(t,0);return e>=0&&e<=1}),overlayTag:c(g,\"div\"),rounded:c(_r,!1),show:c(_,!1),spinnerSmall:c(_,!1),spinnerType:c(g,\"border\"),spinnerVariant:c(g),variant:c(g,\"light\"),wrapTag:c(g,\"div\"),zIndex:c(re,10)},qC),YG=I({name:qC,mixins:[ve],props:KG,computed:{computedRounded:function(){var e=this.rounded;return e===!0||e===\"\"?\"rounded\":e?\"rounded-\".concat(e):\"\"},computedVariant:function(){var e=this.variant;return e&&!this.bgColor?\"bg-\".concat(e):\"\"},slotScope:function(){return{spinnerType:this.spinnerType||null,spinnerVariant:this.spinnerVariant||null,spinnerSmall:this.spinnerSmall}}},methods:{defaultOverlayFn:function(e){var r=e.spinnerType,n=e.spinnerVariant,i=e.spinnerSmall;return this.$createElement(tx,{props:{type:r,variant:n,small:i}})}},render:function(e){var r=this,n=this.show,i=this.fixed,a=this.noFade,o=this.noWrap,s=this.slotScope,l=e();if(n){var u=e(\"div\",{staticClass:\"position-absolute\",class:[this.computedVariant,this.computedRounded],style:kl(kl({},$v),{},{opacity:this.opacity,backgroundColor:this.bgColor||null,backdropFilter:this.blur?\"blur(\".concat(this.blur,\")\"):null})}),f=e(\"div\",{staticClass:\"position-absolute\",style:this.noCenter?kl({},$v):{top:\"50%\",left:\"50%\",transform:\"translateX(-50%) translateY(-50%)\"}},[this.normalizeSlot(m2,s)||this.defaultOverlayFn(s)]);l=e(this.overlayTag,{staticClass:\"b-overlay\",class:{\"position-absolute\":!o||o&&!i,\"position-fixed\":o&&i},style:kl(kl({},$v),{},{zIndex:this.zIndex||10}),on:{click:function(p){return r.$emit(Ln,p)}},key:\"overlay\"},[u,f])}return l=e(Io,{props:{noFade:a,appear:!0},on:{\"after-enter\":function(){return r.$emit(Dr)},\"after-leave\":function(){return r.$emit(Pt)}}},[l]),o?l:e(this.wrapTag,{staticClass:\"b-overlay-wrap position-relative\",attrs:{\"aria-busy\":n?\"true\":null}},o?[l]:[this.normalizeSlot(),l])}}),qG=ae({components:{BOverlay:YG}}),Ll;function hP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function vP(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?hP(Object(r),!0).forEach(function(n){Df(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):hP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Df(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var kp=Nt(\"value\",{type:Au,defaultValue:null,validator:function(e){return!nt(e)&&ee(e,0)<1?(jt('\"v-model\" value must be a number greater than \"0\"',ap),!1):!0}}),XG=kp.mixin,JG=kp.props,_g=kp.prop,ZG=kp.event,Uc=3,hy=5,QG=function(e,r){return du(r,function(n,i){return{number:e+i,classes:null}})},mP=function(e){var r=ee(e)||1;return r<1?hy:r},gP=function(e,r){var n=ee(e)||1;return n>r?r:n<1?1:n},bP=function(e){if(e.keyCode===Ti)return _e(e,{immediatePropagation:!0}),e.currentTarget.click(),!1},vy=z(ie(vP(vP({},JG),{},{align:c(g,\"left\"),ariaLabel:c(g,\"Pagination\"),disabled:c(_,!1),ellipsisClass:c(de),ellipsisText:c(g,\"\\u2026\"),firstClass:c(de),firstNumber:c(_,!1),firstText:c(g,\"\\xAB\"),hideEllipsis:c(_,!1),hideGotoEndButtons:c(_,!1),labelFirstPage:c(g,\"Go to first page\"),labelLastPage:c(g,\"Go to last page\"),labelNextPage:c(g,\"Go to next page\"),labelPage:c(Bj,\"Go to page\"),labelPrevPage:c(g,\"Go to previous page\"),lastClass:c(de),lastNumber:c(_,!1),lastText:c(g,\"\\xBB\"),limit:c(re,hy,function(t){return ee(t,0)<1?(jt('Prop \"limit\" must be a number greater than \"0\"',ap),!1):!0}),nextClass:c(de),nextText:c(g,\"\\u203A\"),pageClass:c(de),pills:c(_,!1),prevClass:c(de),prevText:c(g,\"\\u2039\"),size:c(g)})),\"pagination\"),rx=I({mixins:[XG,ve],props:vy,data:function(){var e=ee(this[_g],0);return e=e>0?e:-1,{currentPage:e,localNumberOfPages:1,localLimit:hy}},computed:{btnSize:function(){var e=this.size;return e?\"pagination-\".concat(e):\"\"},alignment:function(){var e=this.align;return e===\"center\"?\"justify-content-center\":e===\"end\"||e===\"right\"?\"justify-content-end\":e===\"fill\"?\"text-center\":\"\"},styleClass:function(){return this.pills?\"b-pagination-pills\":\"\"},computedCurrentPage:function(){return gP(this.currentPage,this.localNumberOfPages)},paginationParams:function(){var e=this.localLimit,r=this.localNumberOfPages,n=this.computedCurrentPage,i=this.hideEllipsis,a=this.firstNumber,o=this.lastNumber,s=!1,l=!1,u=e,f=1;r<=e?u=r:n<e-1&&e>Uc?((!i||o)&&(l=!0,u=e-(a?0:1)),u=Fi(u,e)):r-n+2<e&&e>Uc?((!i||a)&&(s=!0,u=e-(o?0:1)),f=r-u+1):(e>Uc&&(u=e-(i?0:2),s=!!(!i||a),l=!!(!i||o)),f=n-Mu(u/2)),f<1?(f=1,s=!1):f>r-u&&(f=r-u+1,l=!1),s&&a&&f<4&&(u=u+2,f=1,s=!1);var d=f+u-1;return l&&o&&d>r-3&&(u=u+(d===r-2?2:3),l=!1),e<=Uc&&(a&&f===1?u=Fi(u+1,r,e+1):o&&r===f+u-1&&(f=Fe(f-1,1),u=Fi(r-f+1,r,e+1))),u=Fi(u,r-f+1),{showFirstDots:s,showLastDots:l,numberOfLinks:u,startNumber:f}},pageList:function(){var e=this.paginationParams,r=e.numberOfLinks,n=e.startNumber,i=this.computedCurrentPage,a=QG(n,r);if(a.length>3){var o=i-n,s=\"bv-d-xs-down-none\";if(o===0)for(var l=3;l<a.length;l++)a[l].classes=s;else if(o===a.length-1)for(var u=0;u<a.length-3;u++)a[u].classes=s;else{for(var f=0;f<o-1;f++)a[f].classes=s;for(var d=a.length-1;d>o+1;d--)a[d].classes=s}}return a}},watch:(Ll={},Df(Ll,_g,function(t,e){t!==e&&(this.currentPage=gP(t,this.localNumberOfPages))}),Df(Ll,\"currentPage\",function(e,r){e!==r&&this.$emit(ZG,e>0?e:null)}),Df(Ll,\"limit\",function(e,r){e!==r&&(this.localLimit=mP(e))}),Ll),created:function(){var e=this;this.localLimit=mP(this.limit),this.$nextTick(function(){e.currentPage=e.currentPage>e.localNumberOfPages?e.localNumberOfPages:e.currentPage})},methods:{handleKeyNav:function(e){var r=e.keyCode,n=e.shiftKey;this.isNav||(r===Xn||r===Zr?(_e(e,{propagation:!1}),n?this.focusFirst():this.focusPrev()):(r===Yi||r===Rr)&&(_e(e,{propagation:!1}),n?this.focusLast():this.focusNext()))},getButtons:function(){return yn(\"button.page-link, a.page-link\",this.$el).filter(function(e){return Yn(e)})},focusCurrent:function(){var e=this;this.$nextTick(function(){var r=e.getButtons().find(function(n){return ee(bn(n,\"aria-posinset\"),0)===e.computedCurrentPage});we(r)||e.focusFirst()})},focusFirst:function(){var e=this;this.$nextTick(function(){var r=e.getButtons().find(function(n){return!lo(n)});we(r)})},focusLast:function(){var e=this;this.$nextTick(function(){var r=e.getButtons().reverse().find(function(n){return!lo(n)});we(r)})},focusPrev:function(){var e=this;this.$nextTick(function(){var r=e.getButtons(),n=r.indexOf(Da());n>0&&!lo(r[n-1])&&we(r[n-1])})},focusNext:function(){var e=this;this.$nextTick(function(){var r=e.getButtons(),n=r.indexOf(Da());n<r.length-1&&!lo(r[n+1])&&we(r[n+1])})}},render:function(e){var r=this,n=Tt(this),i=n.disabled,a=n.labelPage,o=n.ariaLabel,s=n.isNav,l=n.localNumberOfPages,u=n.computedCurrentPage,f=this.pageList.map(function(G){return G.number}),d=this.paginationParams,p=d.showFirstDots,h=d.showLastDots,b=this.align===\"fill\",y=[],P=function(H){return H===u},C=this.currentPage<1,R=function(H,W,j,E,v,w,$){var M=i||P(w)||C||H<1||H>l,F=H<1?1:H>l?l:H,X={disabled:M,page:F,index:F-1},Q=r.normalizeSlot(j,X)||ce(E)||e(),q=e(M?\"span\":s?tn:\"button\",{staticClass:\"page-link\",class:{\"flex-grow-1\":!s&&!M&&b},props:M||!s?{}:r.linkProps(H),attrs:{role:s?null:\"menuitem\",type:s||M?null:\"button\",tabindex:M||s?null:\"-1\",\"aria-label\":W,\"aria-controls\":Tt(r).ariaControls||null,\"aria-disabled\":M?\"true\":null},on:M?{}:{\"!click\":function(U){r.onClick(U,H)},keydown:bP}},[Q]);return e(\"li\",{key:$,staticClass:\"page-item\",class:[{disabled:M,\"flex-fill\":b,\"d-flex\":b&&!s&&!M},v],attrs:{role:s?null:\"presentation\",\"aria-hidden\":M?\"true\":null}},[q])},D=function(H){return e(\"li\",{staticClass:\"page-item\",class:[\"disabled\",\"bv-d-xs-down-none\",b?\"flex-fill\":\"\",r.ellipsisClass],attrs:{role:\"separator\"},key:\"ellipsis-\".concat(H?\"last\":\"first\")},[e(\"span\",{staticClass:\"page-link\"},[r.normalizeSlot(Gj)||ce(r.ellipsisText)||e()])])},B=function(H,W){var j=H.number,E=P(j)&&!C,v=i?null:E||C&&W===0?\"0\":\"-1\",w={role:s?null:\"menuitemradio\",type:s||i?null:\"button\",\"aria-disabled\":i?\"true\":null,\"aria-controls\":Tt(r).ariaControls||null,\"aria-label\":yi(a)?a(j):\"\".concat(se(a)?a():a,\" \").concat(j),\"aria-checked\":s?null:E?\"true\":\"false\",\"aria-current\":s&&E?\"page\":null,\"aria-posinset\":s?null:j,\"aria-setsize\":s?null:l,tabindex:s?null:v},$=ce(r.makePage(j)),M={page:j,index:j-1,content:$,active:E,disabled:i},F=e(i?\"span\":s?tn:\"button\",{props:i||!s?{}:r.linkProps(j),staticClass:\"page-link\",class:{\"flex-grow-1\":!s&&!i&&b},attrs:w,on:i?{}:{\"!click\":function(Q){r.onClick(Q,j)},keydown:bP}},[r.normalizeSlot(g2,M)||$]);return e(\"li\",{staticClass:\"page-item\",class:[{disabled:i,active:E,\"flex-fill\":b,\"d-flex\":b&&!s&&!i},H.classes,r.pageClass],attrs:{role:s?null:\"presentation\"},key:\"page-\".concat(j)},[F])},A=e();!this.firstNumber&&!this.hideGotoEndButtons&&(A=R(1,this.labelFirstPage,Kj,this.firstText,this.firstClass,1,\"pagination-goto-first\")),y.push(A),y.push(R(u-1,this.labelPrevPage,y2,this.prevText,this.prevClass,1,\"pagination-goto-prev\")),y.push(this.firstNumber&&f[0]!==1?B({number:1},0):e()),y.push(p?D(!1):e()),this.pageList.forEach(function(G,H){var W=p&&r.firstNumber&&f[0]!==1?1:0;y.push(B(G,H+W))}),y.push(h?D(!0):e()),y.push(this.lastNumber&&f[f.length-1]!==l?B({number:l},-1):e()),y.push(R(u+1,this.labelNextPage,v2,this.nextText,this.nextClass,l,\"pagination-goto-next\"));var V=e();!this.lastNumber&&!this.hideGotoEndButtons&&(V=R(l,this.labelLastPage,r2,this.lastText,this.lastClass,l,\"pagination-goto-last\")),y.push(V);var N=e(\"ul\",{staticClass:\"pagination\",class:[\"b-pagination\",this.btnSize,this.alignment,this.styleClass],attrs:{role:s?null:\"menubar\",\"aria-disabled\":i?\"true\":\"false\",\"aria-label\":s?null:o||null},on:s?{}:{keydown:this.handleKeyNav},ref:\"ul\"},y);return s?e(\"nav\",{attrs:{\"aria-disabled\":i?\"true\":null,\"aria-hidden\":i?\"true\":\"false\",\"aria-label\":s&&o||null}},[N]):N}});function yP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function OP(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?yP(Object(r),!0).forEach(function(n){e4(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):yP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function e4(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var nx=20,ix=0,_P=function(e){return Fe(ee(e)||nx,1)},wP=function(e){return Fe(ee(e)||ix,0)},t4=z(ie(OP(OP({},vy),{},{ariaControls:c(g),perPage:c(re,nx),totalRows:c(re,ix)})),ap),r4=I({name:ap,mixins:[rx],props:t4,computed:{numberOfPages:function(){var e=KD(wP(this.totalRows)/_P(this.perPage));return e<1?1:e},pageSizeNumberOfPages:function(){return{perPage:_P(this.perPage),totalRows:wP(this.totalRows),numberOfPages:this.numberOfPages}}},watch:{pageSizeNumberOfPages:function(e,r){Ge(r)||(e.perPage!==r.perPage&&e.totalRows===r.totalRows?this.currentPage=1:e.numberOfPages!==r.numberOfPages&&this.currentPage>e.numberOfPages&&(this.currentPage=1)),this.localNumberOfPages=e.numberOfPages}},created:function(){var e=this;this.localNumberOfPages=this.numberOfPages;var r=ee(this[_g],0);r>0?this.currentPage=r:this.$nextTick(function(){e.currentPage=0})},methods:{onClick:function(e,r){var n=this;if(r!==this.currentPage){var i=e.target,a=new ko(ED,{cancelable:!0,vueTarget:this,target:i});this.$emit(a.type,a,r),!a.defaultPrevented&&(this.currentPage=r,this.$emit(en,this.currentPage),this.$nextTick(function(){Yn(i)&&n.$el.contains(i)?we(i):n.focusCurrent()}))}},makePage:function(e){return e},linkProps:function(){return{}}}}),n4=ae({components:{BPagination:r4}});function TP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Cv(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?TP(Object(r),!0).forEach(function(n){i4(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):TP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function i4(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var a4=function(e){return Fe(ee(e,0),1)},ax=Pe(ei,[\"event\",\"routerTag\"]),o4=z(ie(Cv(Cv(Cv({},vy),ax),{},{baseUrl:c(g,\"/\"),linkGen:c(xr),noPageDetect:c(_,!1),numberOfPages:c(re,1,function(t){var e=ee(t,0);return e<1?(jt('Prop \"number-of-pages\" must be a number greater than \"0\"',Im),!1):!0}),pageGen:c(xr),pages:c(Ar),useRouter:c(_,!1)})),Im),s4=I({name:Im,mixins:[rx],props:o4,computed:{isNav:function(){return!0},computedValue:function(){var e=ee(this.value,0);return e<1?null:e}},watch:{numberOfPages:function(){var e=this;this.$nextTick(function(){e.setNumberOfPages()})},pages:function(){var e=this;this.$nextTick(function(){e.setNumberOfPages()})}},created:function(){this.setNumberOfPages()},mounted:function(){var e=this;this.$router&&this.$watch(\"$route\",function(){e.$nextTick(function(){We(function(){e.guessCurrentPage()})})})},methods:{setNumberOfPages:function(){var e=this;He(this.pages)&&this.pages.length>0?this.localNumberOfPages=this.pages.length:this.localNumberOfPages=a4(this.numberOfPages),this.$nextTick(function(){e.guessCurrentPage()})},onClick:function(e,r){var n=this;if(r!==this.currentPage){var i=e.currentTarget||e.target,a=new ko(ED,{cancelable:!0,vueTarget:this,target:i});this.$emit(a.type,a,r),!a.defaultPrevented&&(We(function(){n.currentPage=r,n.$emit(en,r)}),this.$nextTick(function(){rn(i)}))}},getPageInfo:function(e){if(!He(this.pages)||this.pages.length===0||Et(this.pages[e-1])){var r=\"\".concat(this.baseUrl).concat(e);return{link:this.useRouter?{path:r}:r,text:ce(e)}}var n=this.pages[e-1];if(St(n)){var i=n.link;return{link:St(i)?i:this.useRouter?{path:i}:i,text:ce(n.text||e)}}else return{link:ce(n),text:ce(e)}},makePage:function(e){var r=this.pageGen,n=this.getPageInfo(e);return yi(r)?r(e,n):n.text},makeLink:function(e){var r=this.linkGen,n=this.getPageInfo(e);return yi(r)?r(e,n):n.link},linkProps:function(e){var r=at(ax,this),n=this.makeLink(e);return this.useRouter||St(n)?r.to=n:r.href=n,r},resolveLink:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:\"\",r;try{r=document.createElement(\"a\"),r.href=ZD({to:e},\"a\",\"/\",\"/\"),document.body.appendChild(r);var n=r,i=n.pathname,a=n.hash,o=n.search;return document.body.removeChild(r),{path:i,hash:a,query:aw(o)}}catch{try{r&&r.parentNode&&r.parentNode.removeChild(r)}catch{}return{}}},resolveRoute:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:\"\";try{var r=this.$router.resolve(e,this.$route).route;return{path:r.path,hash:r.hash,query:r.query}}catch{return{}}},guessCurrentPage:function(){var e=this.$router,r=this.$route,n=this.computedValue;if(!this.noPageDetect&&!n&&(Je||!Je&&e))for(var i=e&&r?{path:r.path,hash:r.hash,query:r.query}:{},a=Je?window.location||document.location:null,o=a?{path:a.pathname,hash:a.hash,query:aw(a.search)}:{},s=1;!n&&s<=this.localNumberOfPages;s++){var l=this.makeLink(s);e&&(St(l)||this.useRouter)?n=je(this.resolveRoute(l),i)?s:null:Je?n=je(this.resolveLink(l),o)?s:null:n=-1}this.currentPage=n>0?n:0}}}),l4=ae({components:{BPaginationNav:s4}}),u4={AUTO:\"auto\",TOP:\"top\",RIGHT:\"right\",BOTTOM:\"bottom\",LEFT:\"left\",TOPLEFT:\"top\",TOPRIGHT:\"top\",RIGHTTOP:\"right\",RIGHTBOTTOM:\"right\",BOTTOMLEFT:\"bottom\",BOTTOMRIGHT:\"bottom\",LEFTTOP:\"left\",LEFTBOTTOM:\"left\"},c4={AUTO:0,TOPLEFT:-1,TOP:0,TOPRIGHT:1,RIGHTTOP:-1,RIGHT:0,RIGHTBOTTOM:1,BOTTOMLEFT:-1,BOTTOM:0,BOTTOMRIGHT:1,LEFTTOP:-1,LEFT:0,LEFTBOTTOM:1},f4={arrowPadding:c(re,6),boundary:c([ba,g],\"scrollParent\"),boundaryPadding:c(re,5),fallbackPlacement:c(Or,\"flip\"),offset:c(re,0),placement:c(g,\"top\"),target:c([ba,O$])},d4=I({name:nj,mixins:[Ba],props:f4,data:function(){return{noFade:!1,localShow:!0,attachment:this.getAttachment(this.placement)}},computed:{templateType:function(){return\"unknown\"},popperConfig:function(){var e=this,r=this.placement;return{placement:this.getAttachment(r),modifiers:{offset:{offset:this.getOffset(r)},flip:{behavior:this.fallbackPlacement},arrow:{element:\".arrow\"},preventOverflow:{padding:this.boundaryPadding,boundariesElement:this.boundary}},onCreate:function(i){i.originalPlacement!==i.placement&&e.popperPlacementChange(i)},onUpdate:function(i){e.popperPlacementChange(i)}}}},created:function(){var e=this;this.$_popper=null,this.localShow=!0,this.$on(tr,function(n){e.popperCreate(n)});var r=function(){e.$nextTick(function(){We(function(){e.$destroy()})})};this.bvParent.$once(Du,r),this.$once(Pt,r)},beforeMount:function(){this.attachment=this.getAttachment(this.placement)},updated:function(){this.updatePopper()},beforeDestroy:function(){this.destroyPopper()},destroyed:function(){var e=this.$el;e&&e.parentNode&&e.parentNode.removeChild(e)},methods:{hide:function(){this.localShow=!1},getAttachment:function(e){return u4[String(e).toUpperCase()]||\"auto\"},getOffset:function(e){if(!this.offset){var r=this.$refs.arrow||gn(\".arrow\",this.$el),n=Ee(hn(r).width,0)+Ee(this.arrowPadding,0);switch(c4[String(e).toUpperCase()]||0){case 1:return\"+50%p - \".concat(n,\"px\");case-1:return\"-50%p + \".concat(n,\"px\");default:return 0}}return this.offset},popperCreate:function(e){this.destroyPopper(),this.$_popper=new sg(this.target,e,this.popperConfig)},destroyPopper:function(){this.$_popper&&this.$_popper.destroy(),this.$_popper=null},updatePopper:function(){this.$_popper&&this.$_popper.scheduleUpdate()},popperPlacementChange:function(e){this.attachment=this.getAttachment(e.placement)},renderTemplate:function(e){return e(\"div\")}},render:function(e){var r=this,n=this.noFade;return e(Io,{props:{appear:!0,noFade:n},on:{beforeEnter:function(a){return r.$emit(tr,a)},afterEnter:function(a){return r.$emit(Dr,a)},beforeLeave:function(a){return r.$emit(Xr,a)},afterLeave:function(a){return r.$emit(Pt,a)}}},[this.localShow?this.renderTemplate(e):e()])}});function SP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function PP(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?SP(Object(r),!0).forEach(function(n){wg(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):SP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function wg(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var p4={html:c(_,!1),id:c(g)},ox=I({name:sj,extends:d4,mixins:[dy],props:p4,data:function(){return{title:\"\",content:\"\",variant:null,customClass:null,interactive:!0}},computed:{templateType:function(){return\"tooltip\"},templateClasses:function(){var e,r=this.variant,n=this.attachment,i=this.templateType;return[(e={noninteractive:!this.interactive},wg(e,\"b-\".concat(i,\"-\").concat(r),r),wg(e,\"bs-\".concat(i,\"-\").concat(n),n),e),this.customClass]},templateAttributes:function(){var e=this.id;return PP(PP({},this.bvParent.bvParent.$attrs),{},{id:e,role:\"tooltip\",tabindex:\"-1\"},this.scopedStyleAttrs)},templateListeners:function(){var e=this;return{mouseenter:function(n){e.$emit(TD,n)},mouseleave:function(n){e.$emit(SD,n)},focusin:function(n){e.$emit(nd,n)},focusout:function(n){e.$emit(id,n)}}}},methods:{renderTemplate:function(e){var r=this.title,n=se(r)?r({}):r,i=this.html&&!se(r)?{innerHTML:r}:{};return e(\"div\",{staticClass:\"tooltip b-tooltip\",class:this.templateClasses,attrs:this.templateAttributes,on:this.templateListeners},[e(\"div\",{staticClass:\"arrow\",ref:\"arrow\"}),e(\"div\",{staticClass:\"tooltip-inner\",domProps:i},[n])])}}});function EP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Dv(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?EP(Object(r),!0).forEach(function(n){h4(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):EP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function h4(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var sx=\".modal-content\",v4=bt(Gr,Pt),m4=\".b-sidebar\",g4=[sx,m4].join(\", \"),b4=\"dropdown\",y4=\".dropdown-menu.show\",Gc=\"data-original-title\",$P={title:\"\",content:\"\",variant:null,customClass:null,triggers:\"\",placement:\"auto\",fallbackPlacement:\"flip\",target:null,container:null,noFade:!1,boundary:\"scrollParent\",boundaryPadding:5,offset:0,delay:0,arrowPadding:6,interactive:!0,disabled:!1,id:null,html:!1},my=I({name:oj,mixins:[Qn,Ba],data:function(){return Dv(Dv({},$P),{},{activeTrigger:{hover:!1,click:!1,focus:!1},localShow:!1})},computed:{templateType:function(){return\"tooltip\"},computedId:function(){return this.id||\"__bv_\".concat(this.templateType,\"_\").concat(this[ji],\"__\")},computedDelay:function(){var e={show:0,hide:0};return yr(this.delay)?(e.show=Fe(ee(this.delay.show,0),0),e.hide=Fe(ee(this.delay.hide,0),0)):(Kn(this.delay)||Ae(this.delay))&&(e.show=e.hide=Fe(ee(this.delay,0),0)),e},computedTriggers:function(){return Me(this.triggers).filter(pe).join(\" \").trim().toLowerCase().split(/\\s+/).sort()},isWithActiveTrigger:function(){for(var e in this.activeTrigger)if(this.activeTrigger[e])return!0;return!1},computedTemplateData:function(){var e=this.title,r=this.content,n=this.variant,i=this.customClass,a=this.noFade,o=this.interactive;return{title:e,content:r,variant:n,customClass:i,noFade:a,interactive:o}}},watch:{computedTriggers:function(e,r){var n=this;je(e,r)||this.$nextTick(function(){n.unListen(),r.forEach(function(i){he(e,i)||n.activeTrigger[i]&&(n.activeTrigger[i]=!1)}),n.listen()})},computedTemplateData:function(){this.handleTemplateUpdate()},title:function(e,r){e!==r&&!e&&this.hide()},disabled:function(e){e?this.disable():this.enable()}},created:function(){var e=this;this.$_tip=null,this.$_hoverTimeout=null,this.$_hoverState=\"\",this.$_visibleInterval=null,this.$_enabled=!this.disabled,this.$_noop=Nu.bind(this),this.bvParent&&this.bvParent.$once(AD,function(){e.$nextTick(function(){We(function(){e.$destroy()})})}),this.$nextTick(function(){var r=e.getTarget();r&&Rt(document.body,r)?(e.scopeId=js(e.bvParent),e.listen()):jt(Ae(e.target)?'Unable to find target element by ID \"#'.concat(e.target,'\" in document.'):\"The provided target is no valid HTML element.\",e.templateType)})},updated:function(){this.$nextTick(this.handleTemplateUpdate)},deactivated:function(){this.forceHide()},beforeDestroy:function(){this.unListen(),this.setWhileOpenListeners(!1),this.clearHoverTimeout(),this.clearVisibilityInterval(),this.destroyTemplate(),this.$_noop=null},methods:{getTemplate:function(){return ox},updateData:function(){var e=this,r=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},n=!1;ge($P).forEach(function(i){!Et(r[i])&&e[i]!==r[i]&&(e[i]=r[i],i===\"title\"&&(n=!0))}),n&&this.localShow&&this.fixTitle()},createTemplateAndShow:function(){var e=this.getContainer(),r=this.getTemplate(),n=this.$_tip=ka(this,r,{propsData:{id:this.computedId,html:this.html,placement:this.placement,fallbackPlacement:this.fallbackPlacement,target:this.getPlacementTarget(),boundary:this.getBoundary(),offset:ee(this.offset,0),arrowPadding:ee(this.arrowPadding,0),boundaryPadding:ee(this.boundaryPadding,0)}});this.handleTemplateUpdate(),n.$once(tr,this.onTemplateShow),n.$once(Dr,this.onTemplateShown),n.$once(Xr,this.onTemplateHide),n.$once(Pt,this.onTemplateHidden),n.$once(Du,this.destroyTemplate),n.$on(nd,this.handleEvent),n.$on(id,this.handleEvent),n.$on(TD,this.handleEvent),n.$on(SD,this.handleEvent),n.$mount(e.appendChild(document.createElement(\"div\")))},hideTemplate:function(){this.$_tip&&this.$_tip.hide(),this.clearActiveTriggers(),this.$_hoverState=\"\"},destroyTemplate:function(){this.setWhileOpenListeners(!1),this.clearHoverTimeout(),this.$_hoverState=\"\",this.clearActiveTriggers(),this.localPlacementTarget=null;try{this.$_tip.$destroy()}catch{}this.$_tip=null,this.removeAriaDescribedby(),this.restoreTitle(),this.localShow=!1},getTemplateElement:function(){return this.$_tip?this.$_tip.$el:null},handleTemplateUpdate:function(){var e=this,r=this.$_tip;if(r){var n=[\"title\",\"content\",\"variant\",\"customClass\",\"noFade\",\"interactive\"];n.forEach(function(i){r[i]!==e[i]&&(r[i]=e[i])})}},show:function(){var e=this.getTarget();if(!(!e||!Rt(document.body,e)||!Yn(e)||this.dropdownOpen()||(Ge(this.title)||this.title===\"\")&&(Ge(this.content)||this.content===\"\"))&&!(this.$_tip||this.localShow)){this.localShow=!0;var r=this.buildEvent(tr,{cancelable:!0});if(this.emitEvent(r),r.defaultPrevented){this.destroyTemplate();return}this.fixTitle(),this.addAriaDescribedby(),this.createTemplateAndShow()}},hide:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:!1,r=this.getTemplateElement();if(!r||!this.localShow){this.restoreTitle();return}var n=this.buildEvent(Xr,{cancelable:!e});this.emitEvent(n),!n.defaultPrevented&&this.hideTemplate()},forceHide:function(){var e=this.getTemplateElement();!e||!this.localShow||(this.setWhileOpenListeners(!1),this.clearHoverTimeout(),this.$_hoverState=\"\",this.clearActiveTriggers(),this.$_tip&&(this.$_tip.noFade=!0),this.hide(!0))},enable:function(){this.$_enabled=!0,this.emitEvent(this.buildEvent(cf))},disable:function(){this.$_enabled=!1,this.emitEvent(this.buildEvent(uf))},onTemplateShow:function(){this.setWhileOpenListeners(!0)},onTemplateShown:function(){var e=this.$_hoverState;this.$_hoverState=\"\",e===\"out\"&&this.leave(null),this.emitEvent(this.buildEvent(Dr))},onTemplateHide:function(){this.setWhileOpenListeners(!1)},onTemplateHidden:function(){this.destroyTemplate(),this.emitEvent(this.buildEvent(Pt))},getTarget:function(){var e=this.target;return Ae(e)?e=Vm(e.replace(/^#/,\"\")):se(e)?e=e():e&&(e=e.$el||e),et(e)?e:null},getPlacementTarget:function(){return this.getTarget()},getTargetId:function(){var e=this.getTarget();return e&&e.id?e.id:null},getContainer:function(){var e=this.container?this.container.$el||this.container:!1,r=document.body,n=this.getTarget();return e===!1?Jr(g4,n)||r:Ae(e)&&Vm(e.replace(/^#/,\"\"))||r},getBoundary:function(){return this.boundary?this.boundary.$el||this.boundary:\"scrollParent\"},isInModal:function(){var e=this.getTarget();return e&&Jr(sx,e)},isDropdown:function(){var e=this.getTarget();return e&&Ru(e,b4)},dropdownOpen:function(){var e=this.getTarget();return this.isDropdown()&&e&&gn(y4,e)},clearHoverTimeout:function(){clearTimeout(this.$_hoverTimeout),this.$_hoverTimeout=null},clearVisibilityInterval:function(){clearInterval(this.$_visibleInterval),this.$_visibleInterval=null},clearActiveTriggers:function(){for(var e in this.activeTrigger)this.activeTrigger[e]=!1},addAriaDescribedby:function(){var e=this.getTarget(),r=bn(e,\"aria-describedby\")||\"\";r=r.split(/\\s+/).concat(this.computedId).join(\" \").trim(),st(e,\"aria-describedby\",r)},removeAriaDescribedby:function(){var e=this,r=this.getTarget(),n=bn(r,\"aria-describedby\")||\"\";n=n.split(/\\s+/).filter(function(i){return i!==e.computedId}).join(\" \").trim(),n?st(r,\"aria-describedby\",n):vi(r,\"aria-describedby\")},fixTitle:function(){var e=this.getTarget();if(mi(e,\"title\")){var r=bn(e,\"title\");st(e,\"title\",\"\"),r&&st(e,Gc,r)}},restoreTitle:function(){var e=this.getTarget();if(mi(e,Gc)){var r=bn(e,Gc);vi(e,Gc),r&&st(e,\"title\",r)}},buildEvent:function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return new ko(e,Dv({cancelable:!1,target:this.getTarget(),relatedTarget:this.getTemplateElement()||null,componentId:this.computedId,vueTarget:this},r))},emitEvent:function(e){var r=e.type;this.emitOnRoot(bt(this.templateType,r),e),this.$emit(r,e)},listen:function(){var e=this,r=this.getTarget();!r||(this.setRootListener(!0),this.computedTriggers.forEach(function(n){n===\"click\"?it(r,\"click\",e.handleEvent,De):n===\"focus\"?(it(r,\"focusin\",e.handleEvent,De),it(r,\"focusout\",e.handleEvent,De)):n===\"blur\"?it(r,\"focusout\",e.handleEvent,De):n===\"hover\"&&(it(r,\"mouseenter\",e.handleEvent,De),it(r,\"mouseleave\",e.handleEvent,De))},this))},unListen:function(){var e=this,r=[\"click\",\"focusin\",\"focusout\",\"mouseenter\",\"mouseleave\"],n=this.getTarget();this.setRootListener(!1),r.forEach(function(i){n&&ft(n,i,e.handleEvent,De)},this)},setRootListener:function(e){var r=e?\"listenOnRoot\":\"listenOffRoot\",n=this.templateType;this[r](xt(n,Xr),this.doHide),this[r](xt(n,tr),this.doShow),this[r](xt(n,km),this.doDisable),this[r](xt(n,Lm),this.doEnable)},setWhileOpenListeners:function(e){this.setModalListener(e),this.setDropdownListener(e),this.visibleCheck(e),this.setOnTouchStartListener(e)},visibleCheck:function(e){var r=this;this.clearVisibilityInterval();var n=this.getTarget();e&&(this.$_visibleInterval=setInterval(function(){var i=r.getTemplateElement();i&&r.localShow&&(!n.parentNode||!Yn(n))&&r.forceHide()},100))},setModalListener:function(e){this.isInModal()&&this[e?\"listenOnRoot\":\"listenOffRoot\"](v4,this.forceHide)},setOnTouchStartListener:function(e){var r=this;\"ontouchstart\"in document.documentElement&&Ao(document.body.children).forEach(function(n){qn(e,n,\"mouseover\",r.$_noop)})},setDropdownListener:function(e){var r=this.getTarget();if(!(!r||!this.bvEventRoot||!this.isDropdown)){var n=Pz(r);n&&n[e?\"$on\":\"$off\"](Dr,this.forceHide)}},handleEvent:function(e){var r=this.getTarget();if(!(!r||lo(r)||!this.$_enabled||this.dropdownOpen())){var n=e.type,i=this.computedTriggers;if(n===\"click\"&&he(i,\"click\"))this.click(e);else if(n===\"mouseenter\"&&he(i,\"hover\"))this.enter(e);else if(n===\"focusin\"&&he(i,\"focus\"))this.enter(e);else if(n===\"focusout\"&&(he(i,\"focus\")||he(i,\"blur\"))||n===\"mouseleave\"&&he(i,\"hover\")){var a=this.getTemplateElement(),o=e.target,s=e.relatedTarget;if(a&&Rt(a,o)&&Rt(r,s)||a&&Rt(r,o)&&Rt(a,s)||a&&Rt(a,o)&&Rt(a,s)||Rt(r,o)&&Rt(r,s))return;this.leave(e)}}},doHide:function(e){(!e||this.getTargetId()===e||this.computedId===e)&&this.forceHide()},doShow:function(e){(!e||this.getTargetId()===e||this.computedId===e)&&this.show()},doDisable:function(e){(!e||this.getTargetId()===e||this.computedId===e)&&this.disable()},doEnable:function(e){(!e||this.getTargetId()===e||this.computedId===e)&&this.enable()},click:function(e){!this.$_enabled||this.dropdownOpen()||(we(e.currentTarget),this.activeTrigger.click=!this.activeTrigger.click,this.isWithActiveTrigger?this.enter(null):this.leave(null))},toggle:function(){!this.$_enabled||this.dropdownOpen()||(this.localShow?this.leave(null):this.enter(null))},enter:function(){var e=this,r=arguments.length>0&&arguments[0]!==void 0?arguments[0]:null;if(r&&(this.activeTrigger[r.type===\"focusin\"?\"focus\":\"hover\"]=!0),this.localShow||this.$_hoverState===\"in\"){this.$_hoverState=\"in\";return}this.clearHoverTimeout(),this.$_hoverState=\"in\",this.computedDelay.show?(this.fixTitle(),this.$_hoverTimeout=setTimeout(function(){e.$_hoverState===\"in\"?e.show():e.localShow||e.restoreTitle()},this.computedDelay.show)):this.show()},leave:function(){var e=this,r=arguments.length>0&&arguments[0]!==void 0?arguments[0]:null;r&&(this.activeTrigger[r.type===\"focusout\"?\"focus\":\"hover\"]=!1,r.type===\"focusout\"&&he(this.computedTriggers,\"blur\")&&(this.activeTrigger.click=!1,this.activeTrigger.hover=!1)),!this.isWithActiveTrigger&&(this.clearHoverTimeout(),this.$_hoverState=\"out\",this.computedDelay.hide?this.$_hoverTimeout=setTimeout(function(){e.$_hoverState===\"out\"&&e.hide()},this.computedDelay.hide):this.hide())}}}),Vr,Ja;function CP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function O4(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?CP(Object(r),!0).forEach(function(n){Xt(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):CP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Xt(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var gu=\"disabled\",DP=Ia+gu,Dd=\"show\",_4=Ia+Dd,lx=z((Vr={boundary:c([ba,Mt,g],\"scrollParent\"),boundaryPadding:c(re,50),container:c([ba,Mt,g]),customClass:c(g),delay:c(kj,50)},Xt(Vr,gu,c(_,!1)),Xt(Vr,\"fallbackPlacement\",c(Or,\"flip\")),Xt(Vr,\"id\",c(g)),Xt(Vr,\"noFade\",c(_,!1)),Xt(Vr,\"noninteractive\",c(_,!1)),Xt(Vr,\"offset\",c(re,0)),Xt(Vr,\"placement\",c(g,\"top\")),Xt(Vr,Dd,c(_,!1)),Xt(Vr,\"target\",c([ba,O$,xr,Mt,g],void 0,!0)),Xt(Vr,\"title\",c(g)),Xt(Vr,\"triggers\",c(Or,\"hover focus\")),Xt(Vr,\"variant\",c(g)),Vr),io),ux=I({name:io,mixins:[ve,Ba],inheritAttrs:!1,props:lx,data:function(){return{localShow:this[Dd],localTitle:\"\",localContent:\"\"}},computed:{templateData:function(){return O4({title:this.localTitle,content:this.localContent,interactive:!this.noninteractive},Zn(this.$props,[\"boundary\",\"boundaryPadding\",\"container\",\"customClass\",\"delay\",\"fallbackPlacement\",\"id\",\"noFade\",\"offset\",\"placement\",\"target\",\"target\",\"triggers\",\"variant\",gu]))},templateTitleContent:function(){var e=this.title,r=this.content;return{title:e,content:r}}},watch:(Ja={},Xt(Ja,Dd,function(t,e){t!==e&&t!==this.localShow&&this.$_toolpop&&(t?this.$_toolpop.show():this.$_toolpop.forceHide())}),Xt(Ja,gu,function(t){t?this.doDisable():this.doEnable()}),Xt(Ja,\"localShow\",function(e){this.$emit(_4,e)}),Xt(Ja,\"templateData\",function(){var e=this;this.$nextTick(function(){e.$_toolpop&&e.$_toolpop.updateData(e.templateData)})}),Xt(Ja,\"templateTitleContent\",function(){this.$nextTick(this.updateContent)}),Ja),created:function(){this.$_toolpop=null},updated:function(){this.$nextTick(this.updateContent)},beforeDestroy:function(){this.$off(L_,this.doOpen),this.$off(Bm,this.doClose),this.$off(km,this.doDisable),this.$off(Lm,this.doEnable),this.$_toolpop&&(this.$_toolpop.$destroy(),this.$_toolpop=null)},mounted:function(){var e=this;this.$nextTick(function(){var r=e.getComponent();e.updateContent();var n=js(e)||js(e.bvParent),i=e.$_toolpop=ka(e,r,{_scopeId:n||void 0});i.updateData(e.templateData),i.$on(tr,e.onShow),i.$on(Dr,e.onShown),i.$on(Xr,e.onHide),i.$on(Pt,e.onHidden),i.$on(uf,e.onDisabled),i.$on(cf,e.onEnabled),e[gu]&&e.doDisable(),e.$on(L_,e.doOpen),e.$on(Bm,e.doClose),e.$on(km,e.doDisable),e.$on(Lm,e.doEnable),e.localShow&&i.show()})},methods:{getComponent:function(){return my},updateContent:function(){this.setTitle(this.normalizeSlot()||this.title)},setTitle:function(e){e=Ge(e)?\"\":e,this.localTitle!==e&&(this.localTitle=e)},setContent:function(e){e=Ge(e)?\"\":e,this.localContent!==e&&(this.localContent=e)},onShow:function(e){this.$emit(tr,e),e&&(this.localShow=!e.defaultPrevented)},onShown:function(e){this.localShow=!0,this.$emit(Dr,e)},onHide:function(e){this.$emit(Xr,e)},onHidden:function(e){this.$emit(Pt,e),this.localShow=!1},onDisabled:function(e){e&&e.type===uf&&(this.$emit(DP,!0),this.$emit(uf,e))},onEnabled:function(e){e&&e.type===cf&&(this.$emit(DP,!1),this.$emit(cf,e))},doOpen:function(){!this.localShow&&this.$_toolpop&&this.$_toolpop.show()},doClose:function(){this.localShow&&this.$_toolpop&&this.$_toolpop.hide()},doDisable:function(){this.$_toolpop&&this.$_toolpop.disable()},doEnable:function(){this.$_toolpop&&this.$_toolpop.enable()}},render:function(e){return e()}}),w4=I({name:rj,extends:ox,computed:{templateType:function(){return\"popover\"}},methods:{renderTemplate:function(e){var r=this.title,n=this.content,i=se(r)?r({}):r,a=se(n)?n({}):n,o=this.html&&!se(r)?{innerHTML:r}:{},s=this.html&&!se(n)?{innerHTML:n}:{};return e(\"div\",{staticClass:\"popover b-popover\",class:this.templateClasses,attrs:this.templateAttributes,on:this.templateListeners},[e(\"div\",{staticClass:\"arrow\",ref:\"arrow\"}),Ge(i)||i===\"\"?e():e(\"h3\",{staticClass:\"popover-header\",domProps:o},[i]),Ge(a)||a===\"\"?e():e(\"div\",{staticClass:\"popover-body\",domProps:s},[a])])}}}),cx=I({name:tj,extends:my,computed:{templateType:function(){return\"popover\"}},methods:{getTemplate:function(){return w4}}});function AP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function RP(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?AP(Object(r),!0).forEach(function(n){T4(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):AP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function T4(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var S4=z(ie(RP(RP({},lx),{},{content:c(g),placement:c(g,\"right\"),triggers:c(Or,Ln)})),no),P4=I({name:no,extends:ux,inheritAttrs:!1,props:S4,methods:{getComponent:function(){return cx},updateContent:function(){this.setContent(this.normalizeSlot()||this.content),this.setTitle(this.normalizeSlot(Wu)||this.title)}}});function xP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function MP(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?xP(Object(r),!0).forEach(function(n){E4(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):xP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function E4(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var An=\"__BV_Popover__\",$4=\"click\",NP={focus:!0,hover:!0,click:!0,blur:!0,manual:!0},C4=/^html$/i,D4=/^nofade$/i,A4=/^(auto|top(left|right)?|bottom(left|right)?|left(top|bottom)?|right(top|bottom)?)$/i,R4=/^(window|viewport|scrollParent)$/i,x4=/^d\\d+$/i,M4=/^ds\\d+$/i,N4=/^dh\\d+$/i,I4=/^o-?\\d+$/i,B4=/^v-.+$/i,k4=/\\s+/,L4=function(e,r){var n={title:void 0,content:void 0,trigger:\"\",placement:\"right\",fallbackPlacement:\"flip\",container:!1,animation:!0,offset:0,disabled:!1,id:null,html:!1,delay:vn(no,\"delay\",50),boundary:String(vn(no,\"boundary\",\"scrollParent\")),boundaryPadding:ee(vn(no,\"boundaryPadding\",5),0),variant:vn(no,\"variant\"),customClass:vn(no,\"customClass\")};if(Ae(e.value)||Kn(e.value)||se(e.value)?n.content=e.value:yr(e.value)&&(n=MP(MP({},n),e.value)),e.arg&&(n.container=\"#\".concat(e.arg)),Et(n.title)){var i=r.data||{};n.title=i.attrs&&!Ge(i.attrs.title)?i.attrs.title:void 0}yr(n.delay)||(n.delay={show:ee(n.delay,0),hide:ee(n.delay,0)}),ge(e.modifiers).forEach(function(o){if(C4.test(o))n.html=!0;else if(D4.test(o))n.animation=!1;else if(A4.test(o))n.placement=o;else if(R4.test(o))o=o===\"scrollparent\"?\"scrollParent\":o,n.boundary=o;else if(x4.test(o)){var s=ee(o.slice(1),0);n.delay.show=s,n.delay.hide=s}else M4.test(o)?n.delay.show=ee(o.slice(2),0):N4.test(o)?n.delay.hide=ee(o.slice(2),0):I4.test(o)?n.offset=ee(o.slice(1),0):B4.test(o)&&(n.variant=o.slice(2)||null)});var a={};return Me(n.trigger||\"\").filter(pe).join(\" \").trim().toLowerCase().split(k4).forEach(function(o){NP[o]&&(a[o]=!0)}),ge(e.modifiers).forEach(function(o){o=o.toLowerCase(),NP[o]&&(a[o]=!0)}),n.trigger=ge(a).join(\" \"),n.trigger===\"blur\"&&(n.trigger=\"focus\"),n.trigger||(n.trigger=$4),n},IP=function(e,r,n){if(!!Je){var i=L4(r,n);if(!e[An]){var a=gi(n,r);e[An]=ka(a,cx,{_scopeId:js(a,void 0)}),e[An].__bv_prev_data__={},e[An].$on(tr,function(){var u={};se(i.title)&&(u.title=i.title(e)),se(i.content)&&(u.content=i.content(e)),ge(u).length>0&&e[An].updateData(u)})}var o={title:i.title,content:i.content,triggers:i.trigger,placement:i.placement,fallbackPlacement:i.fallbackPlacement,variant:i.variant,customClass:i.customClass,container:i.container,boundary:i.boundary,delay:i.delay,offset:i.offset,noFade:!i.animation,id:i.id,disabled:i.disabled,html:i.html},s=e[An].__bv_prev_data__;if(e[An].__bv_prev_data__=o,!je(o,s)){var l={target:e};ge(o).forEach(function(u){o[u]!==s[u]&&(l[u]=(u===\"title\"||u===\"content\")&&se(o[u])?o[u](e):o[u])}),e[An].updateData(l)}}},F4=function(e){e[An]&&(e[An].$destroy(),e[An]=null),delete e[An]},j4={bind:function(e,r,n){IP(e,r,n)},componentUpdated:function(e,r,n){Eb(function(){IP(e,r,n)})},unbind:function(e){F4(e)}},fx=ae({directives:{VBPopover:j4}}),V4=ae({components:{BPopover:P4},plugins:{VBPopoverPlugin:fx}}),dx=z({animated:c(_,null),label:c(g),labelHtml:c(g),max:c(re,null),precision:c(re,null),showProgress:c(_,null),showValue:c(_,null),striped:c(_,null),value:c(re,0),variant:c(g)},JC),px=I({name:JC,mixins:[ve],inject:{getBvProgress:{default:function(){return function(){return{}}}}},props:dx,computed:{bvProgress:function(){return this.getBvProgress()},progressBarClasses:function(){var e=this.computedAnimated,r=this.computedVariant;return[r?\"bg-\".concat(r):\"\",this.computedStriped||e?\"progress-bar-striped\":\"\",e?\"progress-bar-animated\":\"\"]},progressBarStyles:function(){return{width:100*(this.computedValue/this.computedMax)+\"%\"}},computedValue:function(){return Ee(this.value,0)},computedMax:function(){var e=Ee(this.max)||Ee(this.bvProgress.max,0);return e>0?e:100},computedPrecision:function(){return Fe(ee(this.precision,ee(this.bvProgress.precision,0)),0)},computedProgress:function(){var e=this.computedPrecision,r=YD(10,e);return Kh(100*r*this.computedValue/this.computedMax/r,e)},computedVariant:function(){return this.variant||this.bvProgress.variant},computedStriped:function(){return Mn(this.striped)?this.striped:this.bvProgress.striped||!1},computedAnimated:function(){return Mn(this.animated)?this.animated:this.bvProgress.animated||!1},computedShowProgress:function(){return Mn(this.showProgress)?this.showProgress:this.bvProgress.showProgress||!1},computedShowValue:function(){return Mn(this.showValue)?this.showValue:this.bvProgress.showValue||!1}},render:function(e){var r=this.label,n=this.labelHtml,i=this.computedValue,a=this.computedPrecision,o,s={};return this.hasNormalizedSlot()?o=this.normalizeSlot():r||n?s=dt(n,r):this.computedShowProgress?o=this.computedProgress:this.computedShowValue&&(o=Kh(i,a)),e(\"div\",{staticClass:\"progress-bar\",class:this.progressBarClasses,style:this.progressBarStyles,attrs:{role:\"progressbar\",\"aria-valuemin\":\"0\",\"aria-valuemax\":ce(this.computedMax),\"aria-valuenow\":Kh(i,a)},domProps:s},o)}});function BP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function kP(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?BP(Object(r),!0).forEach(function(n){H4(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):BP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function H4(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var hx=Pe(dx,[\"label\",\"labelHtml\"]),z4=z(ie(kP(kP({},hx),{},{animated:c(_,!1),height:c(g),max:c(re,100),precision:c(re,0),showProgress:c(_,!1),showValue:c(_,!1),striped:c(_,!1)})),XC),U4=I({name:XC,mixins:[ve],provide:function(){var e=this;return{getBvProgress:function(){return e}}},props:z4,computed:{progressHeight:function(){return{height:this.height||null}}},render:function(e){var r=this.normalizeSlot();return r||(r=e(px,{props:at(hx,this.$props)})),e(\"div\",{staticClass:\"progress\",style:this.progressHeight},[r])}}),G4=ae({components:{BProgress:U4,BProgressBar:px}}),Fl;function LP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function bu(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?LP(Object(r),!0).forEach(function(n){xi(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):LP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function xi(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var ku=\"b-sidebar\",W4=xt(fr,\"request-state\"),K4=xt(fr,\"toggle\"),Y4=bt(fr,\"state\"),q4=bt(fr,\"sync-state\"),Lp=Nt(\"visible\",{type:_,defaultValue:!1,event:en}),X4=Lp.mixin,J4=Lp.props,FP=Lp.prop,Z4=Lp.event,Q4=z(ie(bu(bu(bu({},Ke),J4),{},{ariaLabel:c(g),ariaLabelledby:c(g),backdrop:c(_,!1),backdropVariant:c(g,\"dark\"),bgVariant:c(g,\"light\"),bodyClass:c(de),closeLabel:c(g),footerClass:c(de),footerTag:c(g,\"footer\"),headerClass:c(de),headerTag:c(g,\"header\"),lazy:c(_,!1),noCloseOnBackdrop:c(_,!1),noCloseOnEsc:c(_,!1),noCloseOnRouteChange:c(_,!1),noEnforceFocus:c(_,!1),noHeader:c(_,!1),noHeaderClose:c(_,!1),noSlide:c(_,!1),right:c(_,!1),shadow:c(_r,!1),sidebarClass:c(de),tag:c(g,\"div\"),textVariant:c(g,\"dark\"),title:c(g),width:c(g),zIndex:c(re)})),QC),e6=function(e,r){var n=r.normalizeSlot(Wu,r.slotScope)||r.title;return n?e(\"strong\",{attrs:{id:r.safeId(\"__title__\")}},[n]):e(\"span\")},t6=function(e,r){if(r.noHeaderClose)return e();var n=r.closeLabel,i=r.textVariant,a=r.hide;return e(xo,{props:{ariaLabel:n,textVariant:i},on:{click:a},ref:\"close-button\"},[r.normalizeSlot(Yj)||e(QD)])},r6=function(e,r){if(r.noHeader)return e();var n=r.normalizeSlot(Ca,r.slotScope);if(!n){var i=e6(e,r),a=t6(e,r);n=r.right?[a,i]:[i,a]}return e(r.headerTag,{staticClass:\"\".concat(ku,\"-header\"),class:r.headerClass,key:\"header\"},n)},n6=function(e,r){return e(\"div\",{staticClass:\"\".concat(ku,\"-body\"),class:r.bodyClass,key:\"body\"},[r.normalizeSlot(kt,r.slotScope)])},i6=function(e,r){var n=r.normalizeSlot(jm,r.slotScope);return n?e(r.footerTag,{staticClass:\"\".concat(ku,\"-footer\"),class:r.footerClass,key:\"footer\"},[n]):e()},a6=function(e,r){var n=r6(e,r);return r.lazy&&!r.isOpen?n:[n,n6(e,r),i6(e,r)]},o6=function(e,r){if(!r.backdrop)return e();var n=r.backdropVariant;return e(\"div\",{directives:[{name:\"show\",value:r.localShow}],staticClass:\"b-sidebar-backdrop\",class:xi({},\"bg-\".concat(n),n),on:{click:r.onBackdropClick}})},s6=I({name:QC,mixins:[Vt,Ze,X4,Qn,ve],inheritAttrs:!1,props:Q4,data:function(){var e=!!this[FP];return{localShow:e,isOpen:e}},computed:{transitionProps:function(){return this.noSlide?{css:!0}:{css:!0,enterClass:\"\",enterActiveClass:\"slide\",enterToClass:\"show\",leaveClass:\"show\",leaveActiveClass:\"slide\",leaveToClass:\"\"}},slotScope:function(){var e=this.hide,r=this.right,n=this.localShow;return{hide:e,right:r,visible:n}},hasTitle:function(){var e=this.$scopedSlots,r=this.$slots;return!this.noHeader&&!this.hasNormalizedSlot(Ca)&&!!(this.normalizeSlot(Wu,this.slotScope,e,r)||this.title)},titleId:function(){return this.hasTitle?this.safeId(\"__title__\"):null},computedAttrs:function(){return bu(bu({},this.bvAttrs),{},{id:this.safeId(),tabindex:\"-1\",role:\"dialog\",\"aria-modal\":this.backdrop?\"true\":\"false\",\"aria-hidden\":this.localShow?null:\"true\",\"aria-label\":this.ariaLabel||null,\"aria-labelledby\":this.ariaLabelledby||this.titleId||null})}},watch:(Fl={},xi(Fl,FP,function(t,e){t!==e&&(this.localShow=t)}),xi(Fl,\"localShow\",function(e,r){e!==r&&(this.emitState(e),this.$emit(Z4,e))}),xi(Fl,\"$route\",function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};!this.noCloseOnRouteChange&&e.fullPath!==r.fullPath&&this.hide()}),Fl),created:function(){this.$_returnFocusEl=null},mounted:function(){var e=this;this.listenOnRoot(K4,this.handleToggle),this.listenOnRoot(W4,this.handleSync),this.$nextTick(function(){e.emitState(e.localShow)})},activated:function(){this.emitSync()},beforeDestroy:function(){this.localShow=!1,this.$_returnFocusEl=null},methods:{hide:function(){this.localShow=!1},emitState:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:this.localShow;this.emitOnRoot(Y4,this.safeId(),e)},emitSync:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:this.localShow;this.emitOnRoot(q4,this.safeId(),e)},handleToggle:function(e){e&&e===this.safeId()&&(this.localShow=!this.localShow)},handleSync:function(e){var r=this;e&&e===this.safeId()&&this.$nextTick(function(){r.emitSync(r.localShow)})},onKeydown:function(e){var r=e.keyCode;!this.noCloseOnEsc&&r===Fb&&this.localShow&&this.hide()},onBackdropClick:function(){this.localShow&&!this.noCloseOnBackdrop&&this.hide()},onTopTrapFocus:function(){var e=zm(this.$refs.content);this.enforceFocus(e.reverse()[0])},onBottomTrapFocus:function(){var e=zm(this.$refs.content);this.enforceFocus(e[0])},onBeforeEnter:function(){this.$_returnFocusEl=Da(Je?[document.body]:[]),this.isOpen=!0},onAfterEnter:function(e){Rt(e,Da())||this.enforceFocus(e),this.$emit(Dr)},onAfterLeave:function(){this.enforceFocus(this.$_returnFocusEl),this.$_returnFocusEl=null,this.isOpen=!1,this.$emit(Pt)},enforceFocus:function(e){this.noEnforceFocus||we(e)}},render:function(e){var r,n=this.bgVariant,i=this.width,a=this.textVariant,o=this.localShow,s=this.shadow===\"\"?!0:this.shadow,l=e(this.tag,{staticClass:ku,class:[(r={shadow:s===!0},xi(r,\"shadow-\".concat(s),s&&s!==!0),xi(r,\"\".concat(ku,\"-right\"),this.right),xi(r,\"bg-\".concat(n),n),xi(r,\"text-\".concat(a),a),r),this.sidebarClass],style:{width:i},attrs:this.computedAttrs,directives:[{name:\"show\",value:o}],ref:\"content\"},[a6(e,this)]);l=e(\"transition\",{props:this.transitionProps,on:{beforeEnter:this.onBeforeEnter,afterEnter:this.onAfterEnter,afterLeave:this.onAfterLeave}},[l]);var u=e(Io,{props:{noFade:this.noSlide}},[o6(e,this)]),f=e(),d=e();return this.backdrop&&o&&(f=e(\"div\",{attrs:{tabindex:\"0\"},on:{focus:this.onTopTrapFocus}}),d=e(\"div\",{attrs:{tabindex:\"0\"},on:{focus:this.onBottomTrapFocus}})),e(\"div\",{staticClass:\"b-sidebar-outer\",style:{zIndex:this.zIndex},attrs:{tabindex:\"-1\"},on:{keydown:this.onKeydown}},[f,l,d,u])}}),l6=ae({components:{BSidebar:s6},plugins:{VBTogglePlugin:Xb}});function Av(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var u6=z({animation:c(g,\"wave\"),height:c(g),size:c(g),type:c(g,\"text\"),variant:c(g),width:c(g)},eD),Ad=I({name:eD,functional:!0,props:u6,render:function(e,r){var n,i=r.data,a=r.props,o=a.size,s=a.animation,l=a.variant;return e(\"div\",oe(i,{staticClass:\"b-skeleton\",style:{width:o||a.width,height:o||a.height},class:(n={},Av(n,\"b-skeleton-\".concat(a.type),!0),Av(n,\"b-skeleton-animate-\".concat(s),s),Av(n,\"bg-\".concat(l),l),n)}))}});function jP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function VP(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?jP(Object(r),!0).forEach(function(n){vx(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):jP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function vx(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var c6=z({animation:c(g,\"wave\"),icon:c(g),iconProps:c(Mt,{})},tD),f6=I({name:tD,functional:!0,props:c6,render:function(e,r){var n=r.data,i=r.props,a=i.icon,o=i.animation,s=e(sd,{staticClass:\"b-skeleton-icon\",props:VP(VP({},i.iconProps),{},{icon:a})});return e(\"div\",oe(n,{staticClass:\"b-skeleton-icon-wrapper position-relative d-inline-block overflow-hidden\",class:vx({},\"b-skeleton-animate-\".concat(o),o)}),[s])}});function d6(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var p6=z({animation:c(g),aspect:c(g,\"16:9\"),cardImg:c(g),height:c(g),noAspect:c(_,!1),variant:c(g),width:c(g)},rD),h6=I({name:rD,functional:!0,props:p6,render:function(e,r){var n=r.data,i=r.props,a=i.aspect,o=i.width,s=i.height,l=i.animation,u=i.variant,f=i.cardImg,d=e(Ad,oe(n,{props:{type:\"img\",width:o,height:s,animation:l,variant:u},class:d6({},\"card-img-\".concat(f),f)}));return i.noAspect?d:e(qD,{props:{aspect:a}},[d])}}),gy=I({methods:{hasListener:function(e){if(Nr)return!0;var r=this.$listeners||{},n=this._events||{};return!Et(r[e])||He(n[e])&&n[e].length>0}}});function HP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function v6(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?HP(Object(r),!0).forEach(function(n){m6(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):HP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function m6(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var zP=\"light\",UP=\"dark\",g6=z({variant:c(g)},mD),qi=I({name:mD,mixins:[Vt,Zi,ve],provide:function(){var e=this;return{getBvTableTr:function(){return e}}},inject:{getBvTableRowGroup:{default:function(){return function(){return{}}}}},inheritAttrs:!1,props:g6,computed:{bvTableRowGroup:function(){return this.getBvTableRowGroup()},inTbody:function(){return this.bvTableRowGroup.isTbody},inThead:function(){return this.bvTableRowGroup.isThead},inTfoot:function(){return this.bvTableRowGroup.isTfoot},isDark:function(){return this.bvTableRowGroup.isDark},isStacked:function(){return this.bvTableRowGroup.isStacked},isResponsive:function(){return this.bvTableRowGroup.isResponsive},isStickyHeader:function(){return this.bvTableRowGroup.isStickyHeader},hasStickyHeader:function(){return!this.isStacked&&this.bvTableRowGroup.hasStickyHeader},tableVariant:function(){return this.bvTableRowGroup.tableVariant},headVariant:function(){return this.inThead?this.bvTableRowGroup.headVariant:null},footVariant:function(){return this.inTfoot?this.bvTableRowGroup.footVariant:null},isRowDark:function(){return this.headVariant===zP||this.footVariant===zP?!1:this.headVariant===UP||this.footVariant===UP?!0:this.isDark},trClasses:function(){var e=this.variant;return[e?\"\".concat(this.isRowDark?\"bg\":\"table\",\"-\").concat(e):null]},trAttrs:function(){return v6({role:\"row\"},this.bvAttrs)}},render:function(e){return e(\"tr\",{class:this.trClasses,attrs:this.trAttrs,on:this.bvListeners},this.normalizeSlot())}}),mx={},b6=I({props:mx,methods:{renderBottomRow:function(){var e=this.computedFields,r=this.stacked,n=this.tbodyTrClass,i=this.tbodyTrAttr,a=this.$createElement;return!this.hasNormalizedSlot(V_)||r===!0||r===\"\"?a():a(qi,{staticClass:\"b-table-bottom-row\",class:[se(n)?n(null,\"row-bottom\"):n],attrs:se(i)?i(null,\"row-bottom\"):i,key:\"b-bottom-row\"},this.normalizeSlot(V_,{columns:e.length,fields:e}))}}});function GP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function WP(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?GP(Object(r),!0).forEach(function(n){y6(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):GP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function y6(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Tg=function(e){return e=ee(e,0),e>0?e:null},KP=function(e){return Ge(e)||Tg(e)>0},gx=z({colspan:c(re,null,KP),rowspan:c(re,null,KP),stackedHeading:c(g),stickyColumn:c(_,!1),variant:c(g)},sD),Hs=I({name:sD,mixins:[Vt,Zi,ve],inject:{getBvTableTr:{default:function(){return function(){return{}}}}},inheritAttrs:!1,props:gx,computed:{bvTableTr:function(){return this.getBvTableTr()},tag:function(){return\"td\"},inTbody:function(){return this.bvTableTr.inTbody},inThead:function(){return this.bvTableTr.inThead},inTfoot:function(){return this.bvTableTr.inTfoot},isDark:function(){return this.bvTableTr.isDark},isStacked:function(){return this.bvTableTr.isStacked},isStackedCell:function(){return this.inTbody&&this.isStacked},isResponsive:function(){return this.bvTableTr.isResponsive},isStickyHeader:function(){return this.bvTableTr.isStickyHeader},hasStickyHeader:function(){return this.bvTableTr.hasStickyHeader},isStickyColumn:function(){return!this.isStacked&&(this.isResponsive||this.hasStickyHeader)&&this.stickyColumn},rowVariant:function(){return this.bvTableTr.variant},headVariant:function(){return this.bvTableTr.headVariant},footVariant:function(){return this.bvTableTr.footVariant},tableVariant:function(){return this.bvTableTr.tableVariant},computedColspan:function(){return Tg(this.colspan)},computedRowspan:function(){return Tg(this.rowspan)},cellClasses:function(){var e=this.variant,r=this.headVariant,n=this.isStickyColumn;return(!e&&this.isStickyHeader&&!r||!e&&n&&this.inTfoot&&!this.footVariant||!e&&n&&this.inThead&&!r||!e&&n&&this.inTbody)&&(e=this.rowVariant||this.tableVariant||\"b-table-default\"),[e?\"\".concat(this.isDark?\"bg\":\"table\",\"-\").concat(e):null,n?\"b-table-sticky-column\":null]},cellAttrs:function(){var e=this.stackedHeading,r=this.inThead||this.inTfoot,n=this.computedColspan,i=this.computedRowspan,a=\"cell\",o=null;return r?(a=\"columnheader\",o=n>0?\"colspan\":\"col\"):wi(this.tag,\"th\")&&(a=\"rowheader\",o=i>0?\"rowgroup\":\"row\"),WP(WP({colspan:n,rowspan:i,role:a,scope:o},this.bvAttrs),{},{\"data-label\":this.isStackedCell&&!Ge(e)?ce(e):null})}},render:function(e){var r=[this.normalizeSlot()];return e(this.tag,{class:this.cellClasses,attrs:this.cellAttrs,on:this.bvListeners},[this.isStackedCell?e(\"div\",[r]):r])}});function O6(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var by=\"busy\",_6=Ia+by,bx=O6({},by,c(_,!1)),w6=I({props:bx,data:function(){return{localBusy:!1}},computed:{computedBusy:function(){return this[by]||this.localBusy}},watch:{localBusy:function(e,r){e!==r&&this.$emit(_6,e)}},methods:{stopIfBusy:function(e){return this.computedBusy?(_e(e),!0):!1},renderBusy:function(){var e=this.tbodyTrClass,r=this.tbodyTrAttr,n=this.$createElement;return this.computedBusy&&this.hasNormalizedSlot(Yl)?n(qi,{staticClass:\"b-table-busy-slot\",class:[se(e)?e(null,Yl):e],attrs:se(r)?r(null,Yl):r,key:\"table-busy-slot\"},[n(Hs,{props:{colspan:this.computedFields.length||null}},[this.normalizeSlot(Yl)])]):null}}}),yy={caption:c(g),captionHtml:c(g)},yx=I({props:yy,computed:{captionId:function(){return this.isStacked?this.safeId(\"_caption_\"):null}},methods:{renderCaption:function(){var e=this.caption,r=this.captionHtml,n=this.$createElement,i=n(),a=this.hasNormalizedSlot(Y_);return(a||e||r)&&(i=n(\"caption\",{attrs:{id:this.captionId},domProps:a?{}:dt(r,e),key:\"caption\",ref:\"caption\"},this.normalizeSlot(Y_))),i}}}),Ox={},_x=I({methods:{renderColgroup:function(){var e=this.computedFields,r=this.$createElement,n=r();return this.hasNormalizedSlot(q_)&&(n=r(\"colgroup\",{key:\"colgroup\"},[this.normalizeSlot(q_,{columns:e.length,fields:e})])),n}}}),wx={emptyFilteredHtml:c(g),emptyFilteredText:c(g,\"There are no records matching your request\"),emptyHtml:c(g),emptyText:c(g,\"There are no records to show\"),showEmpty:c(_,!1)},T6=I({props:wx,methods:{renderEmpty:function(){var e=Tt(this),r=e.computedItems,n=e.computedBusy,i=this.$createElement,a=i();if(this.showEmpty&&(!r||r.length===0)&&!(n&&this.hasNormalizedSlot(Yl))){var o=this.computedFields,s=this.isFiltered,l=this.emptyText,u=this.emptyHtml,f=this.emptyFilteredText,d=this.emptyFilteredHtml,p=this.tbodyTrClass,h=this.tbodyTrAttr;a=this.normalizeSlot(s?Wj:ID,{emptyFilteredHtml:d,emptyFilteredText:f,emptyHtml:u,emptyText:l,fields:o,items:r}),a||(a=i(\"div\",{class:[\"text-center\",\"my-2\"],domProps:s?dt(d,f):dt(u,l)})),a=i(Hs,{props:{colspan:o.length||null}},[i(\"div\",{attrs:{role:\"alert\",\"aria-live\":\"polite\"}},[a])]),a=i(qi,{staticClass:\"b-table-empty-row\",class:[se(p)?p(null,\"row-empty\"):p],attrs:se(h)?h(null,\"row-empty\"):h,key:s?\"b-empty-filtered-row\":\"b-empty-row\"},[a])}return a}}}),Sg=function t(e){return Ge(e)?\"\":St(e)&&!xs(e)?ge(e).sort().map(function(r){return t(e[r])}).filter(function(r){return!!r}).join(\" \"):ce(e)};function YP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function qP(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?YP(Object(r),!0).forEach(function(n){Tx(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):YP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Tx(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Af=\"_cellVariants\",Pg=\"_rowVariant\",iu=\"_showDetails\",Sx=[Af,Pg,iu].reduce(function(t,e){return qP(qP({},t),{},Tx({},e,!0))},{}),S6=[\"a\",\"a *\",\"button\",\"button *\",\"input:not(.disabled):not([disabled])\",\"select:not(.disabled):not([disabled])\",\"textarea:not(.disabled):not([disabled])\",'[role=\"link\"]','[role=\"link\"] *','[role=\"button\"]','[role=\"button\"] *',\"[tabindex]:not(.disabled):not([disabled])\"].join(\",\"),Eg=function(e,r,n){var i=arguments.length>3&&arguments[3]!==void 0?arguments[3]:{},a=ge(i).reduce(function(s,l){var u=i[l],f=u.filterByFormatted,d=se(f)?f:f?u.formatter:null;return se(d)&&(s[l]=d(e[l],l,e)),s},Na(e)),o=ge(a).filter(function(s){return!Sx[s]&&!(He(r)&&r.length>0&&he(r,s))&&!(He(n)&&n.length>0&&!he(n,s))});return Zn(a,o)},P6=function(e,r,n,i){return St(e)?Sg(Eg(e,r,n,i)):\"\"};function E6(t){return A6(t)||D6(t)||C6(t)||$6()}function $6(){throw new TypeError(`Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function C6(t,e){if(!!t){if(typeof t==\"string\")return $g(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);if(r===\"Object\"&&t.constructor&&(r=t.constructor.name),r===\"Map\"||r===\"Set\")return Array.from(t);if(r===\"Arguments\"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return $g(t,e)}}function D6(t){if(typeof Symbol<\"u\"&&t[Symbol.iterator]!=null||t[\"@@iterator\"]!=null)return Array.from(t)}function A6(t){if(Array.isArray(t))return $g(t)}function $g(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}var R6='Prop \"filter-debounce\" is deprecated. Use the debounce feature of \"<b-form-input>\" instead.',Px={filter:c([].concat(E6(de),[Mj])),filterDebounce:c(re,0,function(t){return g$.test(String(t))}),filterFunction:c(xr),filterIgnoredFields:c(Ar,[]),filterIncludedFields:c(Ar,[])},x6=I({props:Px,data:function(){return{isFiltered:!1,localFilter:this.filterSanitize(this.filter)}},computed:{computedFilterIgnored:function(){return Me(this.filterIgnoredFields||[]).filter(pe)},computedFilterIncluded:function(){return Me(this.filterIncludedFields||[]).filter(pe)},computedFilterDebounce:function(){var e=ee(this.filterDebounce,0);return e>0&&jt(R6,Do),e},localFiltering:function(){return this.hasProvider?!!this.noProviderFiltering:!0},filteredCheck:function(){var e=this.filteredItems,r=this.localItems,n=this.localFilter;return{filteredItems:e,localItems:r,localFilter:n}},localFilterFn:function(){var e=this.filterFunction;return yi(e)?e:null},filteredItems:function(){var e=this.localItems,r=this.localFilter,n=this.localFiltering?this.filterFnFactory(this.localFilterFn,r)||this.defaultFilterFnFactory(r):null;return n&&e.length>0?e.filter(n):e}},watch:{computedFilterDebounce:function(e){!e&&this.$_filterTimer&&(this.clearFilterTimer(),this.localFilter=this.filterSanitize(this.filter))},filter:{deep:!0,handler:function(e){var r=this,n=this.computedFilterDebounce;this.clearFilterTimer(),n&&n>0?this.$_filterTimer=setTimeout(function(){r.localFilter=r.filterSanitize(e)},n):this.localFilter=this.filterSanitize(e)}},filteredCheck:function(e){var r=e.filteredItems,n=e.localFilter,i=!1;n?je(n,[])||je(n,{})?i=!1:n&&(i=!0):i=!1,i&&this.$emit(Fm,r,r.length),this.isFiltered=i},isFiltered:function(e,r){if(e===!1&&r===!0){var n=this.localItems;this.$emit(Fm,n,n.length)}}},created:function(){var e=this;this.$_filterTimer=null,this.$nextTick(function(){e.isFiltered=Boolean(e.localFilter)})},beforeDestroy:function(){this.clearFilterTimer()},methods:{clearFilterTimer:function(){clearTimeout(this.$_filterTimer),this.$_filterTimer=null},filterSanitize:function(e){return this.localFiltering&&!this.localFilterFn&&!(Ae(e)||C_(e))?\"\":Nn(e)},filterFnFactory:function(e,r){if(!e||!se(e)||!r||je(r,[])||je(r,{}))return null;var n=function(a){return e(a,r)};return n},defaultFilterFnFactory:function(e){var r=this;if(!e||!(Ae(e)||C_(e)))return null;var n=e;if(Ae(n)){var i=Ib(e).replace(b$,\"\\\\s+\");n=new RegExp(\".*\".concat(i,\".*\"),\"i\")}var a=function(s){return n.lastIndex=0,n.test(P6(s,r.computedFilterIgnored,r.computedFilterIncluded,r.computedFieldsObj))};return a}}}),M6=function(e,r){var n=null;return Ae(r)?n={key:e,label:r}:se(r)?n={key:e,formatter:r}:St(r)?(n=Na(r),n.key=n.key||e):r!==!1&&(n={key:e}),n},N6=function(e,r){var n=[];if(He(e)&&e.filter(pe).forEach(function(o){if(Ae(o))n.push({key:o,label:ff(o)});else if(St(o)&&o.key&&Ae(o.key))n.push(Na(o));else if(St(o)&&ge(o).length===1){var s=ge(o)[0],l=M6(s,o[s]);l&&n.push(l)}}),n.length===0&&He(r)&&r.length>0){var i=r[0];ge(i).forEach(function(o){Sx[o]||n.push({key:o,label:ff(o)})})}var a={};return n.filter(function(o){return a[o.key]?!1:(a[o.key]=!0,o.label=Ae(o.label)?o.label:ff(o.key),!0)})};function XP(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function JP(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?XP(Object(r),!0).forEach(function(n){Ex(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):XP(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Ex(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Fp=Nt(\"value\",{type:Ar,defaultValue:[]}),I6=Fp.mixin,B6=Fp.props,k6=Fp.prop,ZP=Fp.event,Oy=ie(JP(JP({},B6),{},Ex({fields:c(Ar,null),items:c(Ar,[]),primaryKey:c(g)},k6,c(Ar,[])))),$x=I({mixins:[I6,Ba],props:Oy,data:function(){var e=this.items;return{localItems:He(e)?e.slice():[]}},computed:{computedFields:function(){return N6(this.fields,this.localItems)},computedFieldsObj:function(){var e=this.bvParent;return this.computedFields.reduce(function(r,n){if(r[n.key]=Na(n),n.formatter){var i=n.formatter;Ae(i)&&se(e[i])?i=e[i]:se(i)||(i=void 0),r[n.key].formatter=i}return r},{})},computedItems:function(){var e=Tt(this),r=e.paginatedItems,n=e.sortedItems,i=e.filteredItems,a=e.localItems;return(r||n||i||a||[]).slice()},context:function(){var e=Tt(this),r=e.perPage,n=e.currentPage;return{filter:this.localFilter,sortBy:this.localSortBy,sortDesc:this.localSortDesc,perPage:Fe(ee(r,0),0),currentPage:Fe(ee(n,0),1),apiUrl:this.apiUrl}}},watch:{items:function(e){this.localItems=He(e)?e.slice():[]},computedItems:function(e,r){je(e,r)||this.$emit(ZP,e)},context:function(e,r){je(e,r)||this.$emit(yD,e)}},mounted:function(){this.$emit(ZP,this.computedItems)},methods:{getFieldFormatter:function(e){var r=this.computedFieldsObj[e];return r?r.formatter:void 0}}}),Cx={currentPage:c(re,1),perPage:c(re,0)},L6=I({props:Cx,computed:{localPaging:function(){return this.hasProvider?!!this.noProviderPaging:!0},paginatedItems:function(){var e=Tt(this),r=e.sortedItems,n=e.filteredItems,i=e.localItems,a=r||n||i||[],o=Fe(ee(this.currentPage,1),1),s=Fe(ee(this.perPage,0),0);return this.localPaging&&s&&(a=a.slice((o-1)*s,o*s)),a}}}),F6=bt(Do,Kl),j6=xt(Do,yj),Dx={apiUrl:c(g),items:c(MD,[]),noProviderFiltering:c(_,!1),noProviderPaging:c(_,!1),noProviderSorting:c(_,!1)},V6=I({mixins:[Qn],props:Dx,computed:{hasProvider:function(){return se(this.items)},providerTriggerContext:function(){var e={apiUrl:this.apiUrl,filter:null,sortBy:null,sortDesc:null,perPage:null,currentPage:null};return this.noProviderFiltering||(e.filter=this.localFilter),this.noProviderSorting||(e.sortBy=this.localSortBy,e.sortDesc=this.localSortDesc),this.noProviderPaging||(e.perPage=this.perPage,e.currentPage=this.currentPage),Na(e)}},watch:{items:function(e){(this.hasProvider||se(e))&&this.$nextTick(this._providerUpdate)},providerTriggerContext:function(e,r){je(e,r)||this.$nextTick(this._providerUpdate)}},mounted:function(){var e=this;this.hasProvider&&(!this.localItems||this.localItems.length===0)&&this._providerUpdate(),this.listenOnRoot(j6,function(r){(r===e.id||r===e)&&e.refresh()})},methods:{refresh:function(){var e=Tt(this),r=e.items,n=e.refresh,i=e.computedBusy;this.$off(Kl,n),i?this.localBusy&&this.hasProvider&&this.$on(Kl,n):(this.clearSelected(),this.hasProvider?this.$nextTick(this._providerUpdate):this.localItems=He(r)?r.slice():[])},_providerSetLocal:function(e){this.localItems=He(e)?e.slice():[],this.localBusy=!1,this.$emit(Kl),this.id&&this.emitOnRoot(F6,this.id)},_providerUpdate:function(){var e=this;if(!!this.hasProvider){if(Tt(this).computedBusy){this.$nextTick(this.refresh);return}this.localBusy=!0,this.$nextTick(function(){try{var r=e.items(e.context,e._providerSetLocal);CF(r)?r.then(function(n){e._providerSetLocal(n)}):He(r)?e._providerSetLocal(r):e.items.length!==2&&(jt(\"Provider function didn't request callback and did not return a promise or data.\",Do),e.localBusy=!1)}catch(n){jt(\"Provider function error [\".concat(n.name,\"] \").concat(n.message,\".\"),Do),e.localBusy=!1,e.$off(Kl,e.refresh)}})}}}});function Wc(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var H6=[\"range\",\"multi\",\"single\"],QP=\"grid\",Ax={noSelectOnClick:c(_,!1),selectMode:c(g,\"multi\",function(t){return he(H6,t)}),selectable:c(_,!1),selectedVariant:c(g,\"active\")},z6=I({props:Ax,data:function(){return{selectedRows:[],selectedLastRow:-1}},computed:{isSelectable:function(){return this.selectable&&this.selectMode},hasSelectableRowClick:function(){return this.isSelectable&&!this.noSelectOnClick},supportsSelectableRows:function(){return!0},selectableHasSelection:function(){var e=this.selectedRows;return this.isSelectable&&e&&e.length>0&&e.some(pe)},selectableIsMultiSelect:function(){return this.isSelectable&&he([\"range\",\"multi\"],this.selectMode)},selectableTableClasses:function(){var e,r=this.isSelectable;return e={\"b-table-selectable\":r},Wc(e,\"b-table-select-\".concat(this.selectMode),r),Wc(e,\"b-table-selecting\",this.selectableHasSelection),Wc(e,\"b-table-selectable-no-click\",r&&!this.hasSelectableRowClick),e},selectableTableAttrs:function(){if(!this.isSelectable)return{};var e=this.bvAttrs.role||QP;return{role:e,\"aria-multiselectable\":e===QP?ce(this.selectableIsMultiSelect):null}}},watch:{computedItems:function(e,r){var n=!1;if(this.isSelectable&&this.selectedRows.length>0){n=He(e)&&He(r)&&e.length===r.length;for(var i=0;n&&i<e.length;i++)n=je(Eg(e[i]),Eg(r[i]))}n||this.clearSelected()},selectable:function(e){this.clearSelected(),this.setSelectionHandlers(e)},selectMode:function(){this.clearSelected()},hasSelectableRowClick:function(e){this.clearSelected(),this.setSelectionHandlers(!e)},selectedRows:function(e,r){var n=this;if(this.isSelectable&&!je(e,r)){var i=[];e.forEach(function(a,o){a&&i.push(n.computedItems[o])}),this.$emit(Pj,i)}}},beforeMount:function(){this.isSelectable&&this.setSelectionHandlers(!0)},methods:{selectRow:function(e){if(this.isSelectable&&Kn(e)&&e>=0&&e<this.computedItems.length&&!this.isRowSelected(e)){var r=this.selectableIsMultiSelect?this.selectedRows.slice():[];r[e]=!0,this.selectedLastClicked=-1,this.selectedRows=r}},unselectRow:function(e){if(this.isSelectable&&Kn(e)&&this.isRowSelected(e)){var r=this.selectedRows.slice();r[e]=!1,this.selectedLastClicked=-1,this.selectedRows=r}},selectAllRows:function(){var e=this.computedItems.length;this.isSelectable&&e>0&&(this.selectedLastClicked=-1,this.selectedRows=this.selectableIsMultiSelect?du(e,!0):[!0])},isRowSelected:function(e){return!!(Kn(e)&&this.selectedRows[e])},clearSelected:function(){this.selectedLastClicked=-1,this.selectedRows=[]},selectableRowClasses:function(e){if(this.isSelectable&&this.isRowSelected(e)){var r=this.selectedVariant;return Wc({\"b-table-row-selected\":!0},\"\".concat(this.dark?\"bg\":\"table\",\"-\").concat(r),r)}return{}},selectableRowAttrs:function(e){return{\"aria-selected\":this.isSelectable?this.isRowSelected(e)?\"true\":\"false\":null}},setSelectionHandlers:function(e){var r=e&&!this.noSelectOnClick?\"$on\":\"$off\";this[r](ad,this.selectionHandler),this[r](Fm,this.clearSelected),this[r](yD,this.clearSelected)},selectionHandler:function(e,r,n){if(!this.isSelectable||this.noSelectOnClick){this.clearSelected();return}var i=this.selectMode,a=this.selectedLastRow,o=this.selectedRows.slice(),s=!o[r];if(i===\"single\")o=[];else if(i===\"range\")if(a>-1&&n.shiftKey){for(var l=Fi(a,r);l<=Fe(a,r);l++)o[l]=!0;s=!0}else n.ctrlKey||n.metaKey||(o=[],s=!0),s&&(this.selectedLastRow=r);o[r]=s,this.selectedRows=o}}}),Rx=function(e,r){return e.map(function(n,i){return[i,n]}).sort(function(n,i){return this(n[1],i[1])||n[0]-i[0]}.bind(r)).map(function(n){return n[1]})},eE=function(e){return Ge(e)?\"\":cu(e)?Ee(e,e):e},U6=function(e,r){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},i=n.sortBy,a=i===void 0?null:i,o=n.formatter,s=o===void 0?null:o,l=n.locale,u=l===void 0?void 0:l,f=n.localeOptions,d=f===void 0?{}:f,p=n.nullLast,h=p===void 0?!1:p,b=ur(e,a,null),y=ur(r,a,null);return se(s)&&(b=s(b,a,e),y=s(y,a,r)),b=eE(b),y=eE(y),xs(b)&&xs(y)||Kn(b)&&Kn(y)?b<y?-1:b>y?1:0:h&&b===\"\"&&y!==\"\"?1:h&&b!==\"\"&&y===\"\"?-1:Sg(b).localeCompare(Sg(y),u,d)},si,ss;function tE(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function rE(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?tE(Object(r),!0).forEach(function(n){fn(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):tE(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function fn(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Rd=\"sortBy\",G6=Ia+Rd,xd=\"sortDesc\",W6=Ia+xd,Md=\"asc\",Cg=\"desc\",K6=\"last\",Y6=[Md,Cg,K6],xx=(si={labelSortAsc:c(g,\"Click to sort ascending\"),labelSortClear:c(g,\"Click to clear sorting\"),labelSortDesc:c(g,\"Click to sort descending\"),noFooterSorting:c(_,!1),noLocalSorting:c(_,!1),noSortReset:c(_,!1)},fn(si,Rd,c(g)),fn(si,\"sortCompare\",c(xr)),fn(si,\"sortCompareLocale\",c(Or)),fn(si,\"sortCompareOptions\",c(Mt,{numeric:!0})),fn(si,xd,c(_,!1)),fn(si,\"sortDirection\",c(g,Md,function(t){return he(Y6,t)})),fn(si,\"sortIconLeft\",c(_,!1)),fn(si,\"sortNullLast\",c(_,!1)),si),q6=I({props:xx,data:function(){return{localSortBy:this[Rd]||\"\",localSortDesc:this[xd]||!1}},computed:{localSorting:function(){return this.hasProvider?!!this.noProviderSorting:!this.noLocalSorting},isSortable:function(){return this.computedFields.some(function(e){return e.sortable})},sortedItems:function(){var e=Tt(this),r=e.localSortBy,n=e.localSortDesc,i=e.sortCompareLocale,a=e.sortNullLast,o=e.sortCompare,s=e.localSorting,l=e.filteredItems,u=e.localItems,f=(l||u||[]).slice(),d=rE(rE({},this.sortCompareOptions),{},{usage:\"sort\"});if(r&&s){var p=this.computedFieldsObj[r]||{},h=p.sortByFormatted,b=se(h)?h:h?this.getFieldFormatter(r):void 0;return Rx(f,function(y,P){var C=null;return se(o)&&(C=o(y,P,r,n,b,d,i)),(Ge(C)||C===!1)&&(C=U6(y,P,{sortBy:r,formatter:b,locale:i,localeOptions:d,nullLast:a})),(C||0)*(n?-1:1)})}return f}},watch:(ss={isSortable:function(e){e?this.isSortable&&this.$on(fu,this.handleSort):this.$off(fu,this.handleSort)}},fn(ss,xd,function(t){t!==this.localSortDesc&&(this.localSortDesc=t||!1)}),fn(ss,Rd,function(t){t!==this.localSortBy&&(this.localSortBy=t||\"\")}),fn(ss,\"localSortDesc\",function(e,r){e!==r&&this.$emit(W6,e)}),fn(ss,\"localSortBy\",function(e,r){e!==r&&this.$emit(G6,e)}),ss),created:function(){this.isSortable&&this.$on(fu,this.handleSort)},methods:{handleSort:function(e,r,n,i){var a=this;if(!!this.isSortable&&!(i&&this.noFooterSorting)){var o=!1,s=function(){var f=r.sortDirection||a.sortDirection;f===Md?a.localSortDesc=!1:f===Cg&&(a.localSortDesc=!0)};if(r.sortable){var l=!this.localSorting&&r.sortKey?r.sortKey:e;this.localSortBy===l?this.localSortDesc=!this.localSortDesc:(this.localSortBy=l,s()),o=!0}else this.localSortBy&&!this.noSortReset&&(this.localSortBy=\"\",s(),o=!0);o&&this.$emit(Cj,this.context)}},sortTheadThClasses:function(e,r,n){return{\"b-table-sort-icon-left\":r.sortable&&this.sortIconLeft&&!(n&&this.noFooterSorting)}},sortTheadThAttrs:function(e,r,n){var i,a=this.isSortable,o=this.noFooterSorting,s=this.localSortDesc,l=this.localSortBy,u=this.localSorting;if(!a||n&&o)return{};var f=r.sortable,d=u?e:(i=r.sortKey)!==null&&i!==void 0?i:e,p=f&&l===d?s?\"descending\":\"ascending\":f?\"none\":null;return{\"aria-sort\":p}},sortTheadThLabel:function(e,r,n){if(!this.isSortable||n&&this.noFooterSorting)return null;var i=this.localSortBy,a=this.localSortDesc,o=this.labelSortAsc,s=this.labelSortDesc,l=r.sortable,u=\"\";if(l)if(i===e)u=a?o:s;else{u=a?s:o;var f=this.sortDirection||r.sortDirection;f===Md?u=o:f===Cg&&(u=s)}else this.noSortReset||(u=i?this.labelSortClear:\"\");return ya(u)||null}}});function X6(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var jp={stacked:c(_r,!1)},Nd=I({props:jp,computed:{isStacked:function(){var e=this.stacked;return e===\"\"?!0:e},isStackedAlways:function(){return this.isStacked===!0},stackedTableClasses:function(){var e=this.isStackedAlways;return X6({\"b-table-stacked\":e},\"b-table-stacked-\".concat(this.stacked),!e&&this.isStacked)}}});function nE(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Rv(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?nE(Object(r),!0).forEach(function(n){J6(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):nE(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function J6(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Vp={bordered:c(_,!1),borderless:c(_,!1),captionTop:c(_,!1),dark:c(_,!1),fixed:c(_,!1),hover:c(_,!1),noBorderCollapse:c(_,!1),outlined:c(_,!1),responsive:c(_r,!1),small:c(_,!1),stickyHeader:c(_r,!1),striped:c(_,!1),tableClass:c(de),tableVariant:c(g)},_y=I({mixins:[Vt],provide:function(){var e=this;return{getBvTable:function(){return e}}},inheritAttrs:!1,props:Vp,computed:{isTableSimple:function(){return!1},isResponsive:function(){var e=this.responsive;return e===\"\"?!0:e},isStickyHeader:function(){var e=this.stickyHeader;return e=e===\"\"?!0:e,this.isStacked?!1:e},wrapperClasses:function(){var e=this.isResponsive;return[this.isStickyHeader?\"b-table-sticky-header\":\"\",e===!0?\"table-responsive\":e?\"table-responsive-\".concat(this.responsive):\"\"].filter(pe)},wrapperStyles:function(){var e=this.isStickyHeader;return e&&!Mn(e)?{maxHeight:e}:{}},tableClasses:function(){var e=Tt(this),r=e.hover,n=e.tableVariant,i=e.selectableTableClasses,a=e.stackedTableClasses,o=e.tableClass,s=e.computedBusy;return r=this.isTableSimple?r:r&&this.computedItems.length>0&&!s,[o,{\"table-striped\":this.striped,\"table-hover\":r,\"table-dark\":this.dark,\"table-bordered\":this.bordered,\"table-borderless\":this.borderless,\"table-sm\":this.small,border:this.outlined,\"b-table-fixed\":this.fixed,\"b-table-caption-top\":this.captionTop,\"b-table-no-border-collapse\":this.noBorderCollapse},n?\"\".concat(this.dark?\"bg\":\"table\",\"-\").concat(n):\"\",a,i]},tableAttrs:function(){var e=Tt(this),r=e.computedItems,n=e.filteredItems,i=e.computedFields,a=e.selectableTableAttrs,o=e.computedBusy,s=this.isTableSimple?{}:{\"aria-busy\":ce(o),\"aria-colcount\":ce(i.length),\"aria-describedby\":this.bvAttrs[\"aria-describedby\"]||this.$refs.caption?this.captionId:null},l=r&&n&&n.length>r.length?ce(n.length):null;return Rv(Rv(Rv({\"aria-rowcount\":l},this.bvAttrs),{},{id:this.safeId(),role:this.bvAttrs.role||\"table\"},s),a)}},render:function(e){var r=Tt(this),n=r.wrapperClasses,i=r.renderCaption,a=r.renderColgroup,o=r.renderThead,s=r.renderTbody,l=r.renderTfoot,u=[];this.isTableSimple?u.push(this.normalizeSlot()):(u.push(i?i():null),u.push(a?a():null),u.push(o?o():null),u.push(s?s():null),u.push(l?l():null));var f=e(\"table\",{staticClass:\"table b-table\",class:this.tableClasses,attrs:this.tableAttrs,key:\"b-table\"},u.filter(pe));return n.length>0?e(\"div\",{class:n,style:this.wrapperStyles,key:\"wrap\"},[f]):f}});function iE(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function xv(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?iE(Object(r),!0).forEach(function(n){Z6(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):iE(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Z6(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var wy=z({tbodyTransitionHandlers:c(Mt),tbodyTransitionProps:c(Mt)},fD),Mx=I({name:fD,mixins:[Vt,Zi,ve],provide:function(){var e=this;return{getBvTableRowGroup:function(){return e}}},inject:{getBvTable:{default:function(){return function(){return{}}}}},inheritAttrs:!1,props:wy,computed:{bvTable:function(){return this.getBvTable()},isTbody:function(){return!0},isDark:function(){return this.bvTable.dark},isStacked:function(){return this.bvTable.isStacked},isResponsive:function(){return this.bvTable.isResponsive},isStickyHeader:function(){return!1},hasStickyHeader:function(){return!this.isStacked&&this.bvTable.stickyHeader},tableVariant:function(){return this.bvTable.tableVariant},isTransitionGroup:function(){return this.tbodyTransitionProps||this.tbodyTransitionHandlers},tbodyAttrs:function(){return xv({role:\"rowgroup\"},this.bvAttrs)},tbodyProps:function(){var e=this.tbodyTransitionProps;return e?xv(xv({},e),{},{tag:\"tbody\"}):{}}},render:function(e){var r={props:this.tbodyProps,attrs:this.tbodyAttrs};return this.isTransitionGroup?(r.on=this.tbodyTransitionHandlers||{},r.nativeOn=this.bvListeners):r.on=this.bvListeners,e(this.isTransitionGroup?\"transition-group\":\"tbody\",r,this.normalizeSlot())}}),Q6=[\"TD\",\"TH\",\"TR\"],Dg=function(e){if(!e||!e.target)return!1;var r=e.target;if(r.disabled||Q6.indexOf(r.tagName)!==-1)return!1;if(Jr(\".dropdown-menu\",r))return!0;var n=r.tagName===\"LABEL\"?r:Jr(\"label\",r);if(n){var i=bn(n,\"for\"),a=i?Vm(i):gn(\"input, select, textarea\",n);if(a&&!a.disabled)return!0}return Vi(r,S6)},Nx=function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:document,r=N2();return r&&r.toString().trim()!==\"\"&&r.containsNode&&et(e)?r.containsNode(e,!0):!1},eW=z(gx,pD),Ty=I({name:pD,extends:Hs,props:eW,computed:{tag:function(){return\"th\"}}});function aE(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function jl(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?aE(Object(r),!0).forEach(function(n){Ix(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):aE(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Ix(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function tW(t){return aW(t)||iW(t)||nW(t)||rW()}function rW(){throw new TypeError(`Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function nW(t,e){if(!!t){if(typeof t==\"string\")return Ag(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);if(r===\"Object\"&&t.constructor&&(r=t.constructor.name),r===\"Map\"||r===\"Set\")return Array.from(t);if(r===\"Arguments\"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return Ag(t,e)}}function iW(t){if(typeof Symbol<\"u\"&&t[Symbol.iterator]!=null||t[\"@@iterator\"]!=null)return Array.from(t)}function aW(t){if(Array.isArray(t))return Ag(t)}function Ag(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}var Bx={detailsTdClass:c(de),tbodyTrAttr:c(Lj),tbodyTrClass:c([].concat(tW(de),[xr]))},oW=I({mixins:[Ba],props:Bx,methods:{getTdValues:function(e,r,n,i){var a=this.bvParent;if(n){var o=ur(e,r,\"\");return se(n)?n(o,r,e):Ae(n)&&se(a[n])?a[n](o,r,e):n}return i},getThValues:function(e,r,n,i,a){var o=this.bvParent;if(n){var s=ur(e,r,\"\");return se(n)?n(s,r,e,i):Ae(n)&&se(o[n])?o[n](s,r,e,i):n}return a},getFormattedValue:function(e,r){var n=r.key,i=this.getFieldFormatter(n),a=ur(e,n,null);return se(i)&&(a=i(a,n,e)),Ge(a)?\"\":a},toggleDetailsFactory:function(e,r){var n=this;return function(){e&&n.$set(r,iu,!r[iu])}},rowHovered:function(e){this.tbodyRowEventStopped(e)||this.emitTbodyRowEvent(Tj,e)},rowUnhovered:function(e){this.tbodyRowEventStopped(e)||this.emitTbodyRowEvent(Ej,e)},renderTbodyRowCell:function(e,r,n,i){var a=this,o=this.isStacked,s=e.key,l=e.label,u=e.isRowHeader,f=this.$createElement,d=this.hasNormalizedSlot($l),p=this.getFormattedValue(n,e),h=!o&&(this.isResponsive||this.stickyHeader)&&e.stickyColumn,b=h?u?Ty:Hs:u?\"th\":\"td\",y=n[Af]&&n[Af][s]?n[Af][s]:e.variant||null,P={class:[e.class?e.class:\"\",this.getTdValues(n,s,e.tdClass,\"\")],props:{},attrs:jl({\"aria-colindex\":String(r+1)},u?this.getThValues(n,s,e.thAttr,\"row\",{}):this.getTdValues(n,s,e.tdAttr,{})),key:\"row-\".concat(i,\"-cell-\").concat(r,\"-\").concat(s)};h?P.props={stackedHeading:o?l:null,stickyColumn:!0,variant:y}:(P.attrs[\"data-label\"]=o&&!Ge(l)?ce(l):null,P.attrs.role=u?\"rowheader\":\"cell\",P.attrs.scope=u?\"row\":null,y&&P.class.push(\"\".concat(this.dark?\"bg\":\"table\",\"-\").concat(y)));var C={item:n,index:i,field:e,unformatted:ur(n,s,\"\"),value:p,toggleDetails:this.toggleDetailsFactory(d,n),detailsShowing:Boolean(n[iu])};Tt(this).supportsSelectableRows&&(C.rowSelected=this.isRowSelected(i),C.selectRow=function(){return a.selectRow(i)},C.unselectRow=function(){return a.unselectRow(i)});var R=this.$_bodyFieldSlotNameCache[s],D=R?this.normalizeSlot(R,C):ce(p);return this.isStacked&&(D=[f(\"div\",[D])]),f(b,P,[D])},renderTbodyRow:function(e,r){var n=this,i=Tt(this),a=i.computedFields,o=i.striped,s=i.primaryKey,l=i.currentPage,u=i.perPage,f=i.tbodyTrClass,d=i.tbodyTrAttr,p=i.hasSelectableRowClick,h=this.$createElement,b=this.hasNormalizedSlot($l),y=e[iu]&&b,P=this.$listeners[ad]||p,C=[],R=y?this.safeId(\"_details_\".concat(r,\"_\")):null,D=a.map(function(M,F){return n.renderTbodyRowCell(M,F,e,r)}),B=null;l&&u&&u>0&&(B=String((l-1)*u+r+1));var A=ce(ur(e,s))||null,V=A||ce(r),N=A?this.safeId(\"_row_\".concat(A)):null,G=Tt(this).selectableRowClasses?this.selectableRowClasses(r):{},H=Tt(this).selectableRowAttrs?this.selectableRowAttrs(r):{},W=se(f)?f(e,\"row\"):f,j=se(d)?d(e,\"row\"):d;if(C.push(h(qi,Ix({class:[W,G,y?\"b-table-has-details\":\"\"],props:{variant:e[Pg]||null},attrs:jl(jl({id:N},j),{},{tabindex:P?\"0\":null,\"data-pk\":A||null,\"aria-details\":R,\"aria-owns\":R,\"aria-rowindex\":B},H),on:{mouseenter:this.rowHovered,mouseleave:this.rowUnhovered},key:\"__b-table-row-\".concat(V,\"__\"),ref:\"item-rows\"},Pb,!0),D)),y){var E={item:e,index:r,fields:a,toggleDetails:this.toggleDetailsFactory(b,e)};Tt(this).supportsSelectableRows&&(E.rowSelected=this.isRowSelected(r),E.selectRow=function(){return n.selectRow(r)},E.unselectRow=function(){return n.unselectRow(r)});var v=h(Hs,{props:{colspan:a.length},class:this.detailsTdClass},[this.normalizeSlot($l,E)]);o&&C.push(h(\"tr\",{staticClass:\"d-none\",attrs:{\"aria-hidden\":\"true\",role:\"presentation\"},key:\"__b-table-details-stripe__\".concat(V)}));var w=se(this.tbodyTrClass)?this.tbodyTrClass(e,$l):this.tbodyTrClass,$=se(this.tbodyTrAttr)?this.tbodyTrAttr(e,$l):this.tbodyTrAttr;C.push(h(qi,{staticClass:\"b-table-details\",class:[w],props:{variant:e[Pg]||null},attrs:jl(jl({},$),{},{id:R,tabindex:\"-1\"}),key:\"__b-table-details__\".concat(V)},[v]))}else b&&(C.push(h()),o&&C.push(h()));return C}}});function oE(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Mv(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?oE(Object(r),!0).forEach(function(n){sW(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):oE(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function sW(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Nv=function(e){return\"cell(\".concat(e||\"\",\")\")},Sy=ie(Mv(Mv(Mv({},wy),Bx),{},{tbodyClass:c(de)})),kx=I({mixins:[oW],props:Sy,beforeDestroy:function(){this.$_bodyFieldSlotNameCache=null},methods:{getTbodyTrs:function(){var e=this.$refs,r=e.tbody?e.tbody.$el||e.tbody:null,n=(e[\"item-rows\"]||[]).map(function(i){return i.$el||i});return r&&r.children&&r.children.length>0&&n&&n.length>0?Ao(r.children).filter(function(i){return he(n,i)}):[]},getTbodyTrIndex:function(e){if(!et(e))return-1;var r=e.tagName===\"TR\"?e:Jr(\"tr\",e,!0);return r?this.getTbodyTrs().indexOf(r):-1},emitTbodyRowEvent:function(e,r){if(e&&this.hasListener(e)&&r&&r.target){var n=this.getTbodyTrIndex(r.target);if(n>-1){var i=this.computedItems[n];this.$emit(e,i,n,r)}}},tbodyRowEventStopped:function(e){return this.stopIfBusy&&this.stopIfBusy(e)},onTbodyRowKeydown:function(e){var r=e.target,n=e.keyCode;if(!(this.tbodyRowEventStopped(e)||r.tagName!==\"TR\"||!Bb(r)||r.tabIndex!==0)){if(he([Ji,Ti],n))_e(e),this.onTBodyRowClicked(e);else if(he([Zr,Rr,Ra,Aa],n)){var i=this.getTbodyTrIndex(r);if(i>-1){_e(e);var a=this.getTbodyTrs(),o=e.shiftKey;n===Ra||o&&n===Zr?we(a[0]):n===Aa||o&&n===Rr?we(a[a.length-1]):n===Zr&&i>0?we(a[i-1]):n===Rr&&i<a.length-1&&we(a[i+1])}}}},onTBodyRowClicked:function(e){var r=this.$refs,n=r.tbody?r.tbody.$el||r.tbody:null;this.tbodyRowEventStopped(e)||Dg(e)||Nx(n||this.$el)||this.emitTbodyRowEvent(ad,e)},onTbodyRowMiddleMouseRowClicked:function(e){!this.tbodyRowEventStopped(e)&&e.which===2&&this.emitTbodyRowEvent(Sj,e)},onTbodyRowContextmenu:function(e){this.tbodyRowEventStopped(e)||this.emitTbodyRowEvent(_j,e)},onTbodyRowDblClicked:function(e){!this.tbodyRowEventStopped(e)&&!Dg(e)&&this.emitTbodyRowEvent(wj,e)},renderTbody:function(){var e=this,r=Tt(this),n=r.computedItems,i=r.renderBusy,a=r.renderTopRow,o=r.renderEmpty,s=r.renderBottomRow,l=r.hasSelectableRowClick,u=this.$createElement,f=this.hasListener(ad)||l,d=[],p=i?i():null;if(p)d.push(p);else{var h={},b=Nv();b=this.hasNormalizedSlot(b)?b:null,this.computedFields.forEach(function(C){var R=C.key,D=Nv(R),B=Nv(R.toLowerCase());h[R]=e.hasNormalizedSlot(D)?D:e.hasNormalizedSlot(B)?B:b}),this.$_bodyFieldSlotNameCache=h,d.push(a?a():u()),n.forEach(function(C,R){d.push(e.renderTbodyRow(C,R))}),d.push(o?o():u()),d.push(s?s():u())}var y={auxclick:this.onTbodyRowMiddleMouseRowClicked,contextmenu:this.onTbodyRowContextmenu,dblclick:this.onTbodyRowDblClicked};f&&(y.click=this.onTBodyRowClicked,y.keydown=this.onTbodyRowKeydown);var P=u(Mx,{class:this.tbodyClass||null,props:at(wy,this.$props),on:y,ref:\"tbody\"},d);return P}}});function sE(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function lE(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?sE(Object(r),!0).forEach(function(n){lW(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):sE(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function lW(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var uW=z({footVariant:c(g)},dD),Py=I({name:dD,mixins:[Vt,Zi,ve],provide:function(){var e=this;return{getBvTableRowGroup:function(){return e}}},inject:{getBvTable:{default:function(){return function(){return{}}}}},inheritAttrs:!1,props:uW,computed:{bvTable:function(){return this.getBvTable()},isTfoot:function(){return!0},isDark:function(){return this.bvTable.dark},isStacked:function(){return this.bvTable.isStacked},isResponsive:function(){return this.bvTable.isResponsive},isStickyHeader:function(){return!1},hasStickyHeader:function(){return!this.isStacked&&this.bvTable.stickyHeader},tableVariant:function(){return this.bvTable.tableVariant},tfootClasses:function(){return[this.footVariant?\"thead-\".concat(this.footVariant):null]},tfootAttrs:function(){return lE(lE({},this.bvAttrs),{},{role:\"rowgroup\"})}},render:function(e){return e(\"tfoot\",{class:this.tfootClasses,attrs:this.tfootAttrs,on:this.bvListeners},this.normalizeSlot())}}),Ey={footClone:c(_,!1),footRowVariant:c(g),footVariant:c(g),tfootClass:c(de),tfootTrClass:c(de)},Lx=I({props:Ey,methods:{renderTFootCustom:function(){var e=this.$createElement;return this.hasNormalizedSlot(H_)?e(Py,{class:this.tfootClass||null,props:{footVariant:this.footVariant||this.headVariant||null},key:\"bv-tfoot-custom\"},this.normalizeSlot(H_,{items:this.computedItems.slice(),fields:this.computedFields.slice(),columns:this.computedFields.length})):e()},renderTfoot:function(){return this.footClone?this.renderThead(!0):this.renderTFootCustom()}}});function uE(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function cW(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?uE(Object(r),!0).forEach(function(n){fW(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):uE(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function fW(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var dW=z({headVariant:c(g)},hD),Fx=I({name:hD,mixins:[Vt,Zi,ve],provide:function(){var e=this;return{getBvTableRowGroup:function(){return e}}},inject:{getBvTable:{default:function(){return function(){return{}}}}},inheritAttrs:!1,props:dW,computed:{bvTable:function(){return this.getBvTable()},isThead:function(){return!0},isDark:function(){return this.bvTable.dark},isStacked:function(){return this.bvTable.isStacked},isResponsive:function(){return this.bvTable.isResponsive},isStickyHeader:function(){return!this.isStacked&&this.bvTable.stickyHeader},hasStickyHeader:function(){return!this.isStacked&&this.bvTable.stickyHeader},tableVariant:function(){return this.bvTable.tableVariant},theadClasses:function(){return[this.headVariant?\"thead-\".concat(this.headVariant):null]},theadAttrs:function(){return cW({role:\"rowgroup\"},this.bvAttrs)}},render:function(e){return e(\"thead\",{class:this.theadClasses,attrs:this.theadAttrs,on:this.bvListeners},this.normalizeSlot())}});function pW(t){return gW(t)||mW(t)||vW(t)||hW()}function hW(){throw new TypeError(`Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function vW(t,e){if(!!t){if(typeof t==\"string\")return Rg(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);if(r===\"Object\"&&t.constructor&&(r=t.constructor.name),r===\"Map\"||r===\"Set\")return Array.from(t);if(r===\"Arguments\"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return Rg(t,e)}}function mW(t){if(typeof Symbol<\"u\"&&t[Symbol.iterator]!=null||t[\"@@iterator\"]!=null)return Array.from(t)}function gW(t){if(Array.isArray(t))return Rg(t)}function Rg(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}function cE(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function fE(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?cE(Object(r),!0).forEach(function(n){bW(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):cE(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function bW(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Iv=function(e){return\"head(\".concat(e||\"\",\")\")},Bv=function(e){return\"foot(\".concat(e||\"\",\")\")},$y={headRowVariant:c(g),headVariant:c(g),theadClass:c(de),theadTrClass:c(de)},jx=I({props:$y,methods:{fieldClasses:function(e){return[e.class?e.class:\"\",e.thClass?e.thClass:\"\"]},headClicked:function(e,r,n){if(!(this.stopIfBusy&&this.stopIfBusy(e))){{if(Dg(e))return;if(Nx(this.$el))return}_e(e),this.$emit(fu,r.key,r,e,n)}},renderThead:function(){var e=this,r=arguments.length>0&&arguments[0]!==void 0?arguments[0]:!1,n=Tt(this),i=n.computedFields,a=n.isSortable,o=n.isSelectable,s=n.headVariant,l=n.footVariant,u=n.headRowVariant,f=n.footRowVariant,d=this.$createElement;if(this.isStackedAlways||i.length===0)return d();var p=a||this.hasListener(fu),h=o?this.selectAllRows:Nu,b=o?this.clearSelected:Nu,y=function(B,A){var V=B.label,N=B.labelHtml,G=B.variant,H=B.stickyColumn,W=B.key,j=null;!B.label.trim()&&!B.headerTitle&&(j=ff(B.key));var E={};p&&(E.click=function(K){e.headClicked(K,B,r)},E.keydown=function(K){var U=K.keyCode;(U===Ji||U===Ti)&&e.headClicked(K,B,r)});var v=a?e.sortTheadThAttrs(W,B,r):{},w=a?e.sortTheadThClasses(W,B,r):null,$=a?e.sortTheadThLabel(W,B,r):null,M={class:[{\"position-relative\":$},e.fieldClasses(B),w],props:{variant:G,stickyColumn:H},style:B.thStyle||{},attrs:fE(fE({tabindex:p&&B.sortable?\"0\":null,abbr:B.headerAbbr||null,title:B.headerTitle||null,\"aria-colindex\":A+1,\"aria-label\":j},e.getThValues(null,W,B.thAttr,r?\"foot\":\"head\",{})),v),on:E,key:W},F=[Iv(W),Iv(W.toLowerCase()),Iv()];r&&(F=[Bv(W),Bv(W.toLowerCase()),Bv()].concat(pW(F)));var X={label:V,column:W,field:B,isFoot:r,selectAllRows:h,clearSelected:b},Q=e.normalizeSlot(F,X)||d(\"div\",{domProps:dt(N,V)}),q=$?d(\"span\",{staticClass:\"sr-only\"},\" (\".concat($,\")\")):null;return d(Ty,M,[Q,q].filter(pe))},P=i.map(y).filter(pe),C=[];if(r)C.push(d(qi,{class:this.tfootTrClass,props:{variant:Ge(f)?u:f}},P));else{var R={columns:i.length,fields:i,selectAllRows:h,clearSelected:b};C.push(this.normalizeSlot(T2,R)||d()),C.push(d(qi,{class:this.theadTrClass,props:{variant:u}},P))}return d(r?Py:Fx,{class:(r?this.tfootClass:this.theadClass)||null,props:r?{footVariant:l||s||null}:{headVariant:s||null},key:r?\"bv-tfoot\":\"bv-thead\"},C)}}}),yW={},OW=I({methods:{renderTopRow:function(){var e=this.computedFields,r=this.stacked,n=this.tbodyTrClass,i=this.tbodyTrAttr,a=this.$createElement;return!this.hasNormalizedSlot(X_)||r===!0||r===\"\"?a():a(qi,{staticClass:\"b-table-top-row\",class:[se(n)?n(null,\"row-top\"):n],attrs:se(i)?i(null,\"row-top\"):i,key:\"b-top-row\"},[this.normalizeSlot(X_,{columns:e.length,fields:e})])}}});function dE(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Yt(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?dE(Object(r),!0).forEach(function(n){_W(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):dE(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function _W(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var wW=z(ie(Yt(Yt(Yt(Yt(Yt(Yt(Yt(Yt(Yt(Yt(Yt(Yt(Yt(Yt(Yt(Yt(Yt(Yt({},Ke),mx),bx),yy),Ox),wx),Px),Oy),Cx),Dx),Ax),xx),jp),Vp),Sy),Ey),$y),yW)),Do),TW=I({name:Do,mixins:[Vt,gy,Ze,ve,$x,_y,Nd,jx,Lx,kx,Nd,x6,q6,L6,yx,_x,z6,T6,OW,b6,w6,V6],props:wW});function pE(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Di(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?pE(Object(r),!0).forEach(function(n){SW(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):pE(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function SW(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var PW=z(ie(Di(Di(Di(Di(Di(Di(Di(Di(Di({},Ke),yy),Ox),Oy),jp),Vp),Sy),Ey),$y)),lD),EW=I({name:lD,mixins:[Vt,gy,Ze,ve,$x,_y,Nd,jx,Lx,kx,yx,_x],props:PW});function hE(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function kv(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?hE(Object(r),!0).forEach(function(n){$W(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):hE(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function $W(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var CW=z(ie(kv(kv(kv({},Ke),jp),Vp)),uD),Vx=I({name:uD,mixins:[Vt,gy,Ze,ve,_y,Nd],props:CW,computed:{isTableSimple:function(){return!0}}}),DW=ae({components:{BTableLite:EW}}),AW=ae({components:{BTableSimple:Vx,BTbody:Mx,BThead:Fx,BTfoot:Py,BTr:qi,BTd:Hs,BTh:Ty}}),RW=ae({components:{BTable:TW},plugins:{TableLitePlugin:DW,TableSimplePlugin:AW}});function vE(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function xW(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?vE(Object(r),!0).forEach(function(n){MW(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):vE(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function MW(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var mE=function(e){return e>0},NW=z({animation:c(g),columns:c(mr,5,mE),hideHeader:c(_,!1),rows:c(mr,3,mE),showFooter:c(_,!1),tableProps:c(Mt,{})},nD),IW=I({name:nD,functional:!0,props:NW,render:function(e,r){var n=r.data,i=r.props,a=i.animation,o=i.columns,s=e(\"th\",[e(Ad,{props:{animation:a}})]),l=e(\"tr\",du(o,s)),u=e(\"td\",[e(Ad,{props:{width:\"75%\",animation:a}})]),f=e(\"tr\",du(o,u)),d=e(\"tbody\",du(i.rows,f)),p=i.hideHeader?e():e(\"thead\",[l]),h=i.showFooter?e(\"tfoot\",[l]):e();return e(Vx,oe(n,{props:xW({},i.tableProps)}),[p,d,h])}}),BW=z({loading:c(_,!1)},iD),kW=I({name:iD,functional:!0,props:BW,render:function(e,r){var n=r.data,i=r.props,a=r.slots,o=r.scopedSlots,s=a(),l=o||{},u={};return i.loading?e(\"div\",oe(n,{attrs:{role:\"alert\",\"aria-live\":\"polite\",\"aria-busy\":!0},staticClass:\"b-skeleton-wrapper\",key:\"loading\"}),rr(n2,u,l,s)):rr(kt,u,l,s)}}),LW=ae({components:{BSkeleton:Ad,BSkeletonIcon:f6,BSkeletonImg:h6,BSkeletonTable:IW,BSkeletonWrapper:kW}}),FW=ae({components:{BSpinner:tx}}),ls;function gE(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Es(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?gE(Object(r),!0).forEach(function(n){Un(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):gE(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function Un(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Hp=Nt(\"value\",{type:mr}),jW=Hp.mixin,VW=Hp.props,Lv=Hp.prop,bE=Hp.event,Za=function(e){return!e.disabled},HW=I({name:ij,inject:{getBvTabs:{default:function(){return function(){return{}}}}},props:{controls:c(g),id:c(g),noKeyNav:c(_,!1),posInSet:c(mr),setSize:c(mr),tab:c(),tabIndex:c(mr)},computed:{bvTabs:function(){return this.getBvTabs()}},methods:{focus:function(){we(this.$refs.link)},handleEvent:function(e){if(!this.tab.disabled){var r=e.type,n=e.keyCode,i=e.shiftKey;r===\"click\"?(_e(e),this.$emit(Ln,e)):r===\"keydown\"&&n===Ti?(_e(e),this.$emit(Ln,e)):r===\"keydown\"&&!this.noKeyNav&&([Zr,Xn,Ra].indexOf(n)!==-1?(_e(e),i||n===Ra?this.$emit(OD,e):this.$emit($D,e)):[Rr,Yi,Aa].indexOf(n)!==-1&&(_e(e),i||n===Aa?this.$emit(wD,e):this.$emit(PD,e)))}}},render:function(e){var r=this.id,n=this.tabIndex,i=this.setSize,a=this.posInSet,o=this.controls,s=this.handleEvent,l=this.tab,u=l.title,f=l.localActive,d=l.disabled,p=l.titleItemClass,h=l.titleLinkClass,b=l.titleLinkAttributes,y=e(tn,{staticClass:\"nav-link\",class:[{active:f&&!d,disabled:d},h,f?this.bvTabs.activeNavItemClass:null],props:{disabled:d},attrs:Es(Es({},b),{},{id:r,role:\"tab\",tabindex:n,\"aria-selected\":f&&!d?\"true\":\"false\",\"aria-setsize\":i,\"aria-posinset\":a,\"aria-controls\":o}),on:{click:s,keydown:s},ref:\"link\"},[this.tab.normalizeSlot(Wu)||u]);return e(\"li\",{staticClass:\"nav-item\",class:[p],attrs:{role:\"presentation\"}},[y])}}),zW=Pe(py,[\"tabs\",\"isNavBar\",\"cardHeader\"]),UW=z(ie(Es(Es(Es(Es({},Ke),VW),zW),{},{activeNavItemClass:c(de),activeTabClass:c(de),card:c(_,!1),contentClass:c(de),end:c(_,!1),lazy:c(_,!1),navClass:c(de),navWrapperClass:c(de),noFade:c(_,!1),noKeyNav:c(_,!1),noNavStyle:c(_,!1),tag:c(g,\"div\")})),cD),GW=I({name:cD,mixins:[Ze,jW,ve],provide:function(){var e=this;return{getBvTabs:function(){return e}}},props:UW,data:function(){return{currentTab:ee(this[Lv],-1),tabs:[],registeredTabs:[]}},computed:{fade:function(){return!this.noFade},localNavClass:function(){var e=[];return this.card&&this.vertical&&e.push(\"card-header\",\"h-100\",\"border-bottom-0\",\"rounded-0\"),[].concat(e,[this.navClass])}},watch:(ls={},Un(ls,Lv,function(t,e){if(t!==e){t=ee(t,-1),e=ee(e,0);var r=this.tabs[t];r&&!r.disabled?this.activateTab(r):t<e?this.previousTab():this.nextTab()}}),Un(ls,\"currentTab\",function(e){var r=-1;this.tabs.forEach(function(n,i){i===e&&!n.disabled?(n.localActive=!0,r=i):n.localActive=!1}),this.$emit(bE,r)}),Un(ls,\"tabs\",function(e,r){var n=this;je(e.map(function(i){return i[ji]}),r.map(function(i){return i[ji]}))||this.$nextTick(function(){n.$emit(dj,e.slice(),r.slice())})}),Un(ls,\"registeredTabs\",function(){this.updateTabs()}),ls),created:function(){this.$_observer=null},mounted:function(){this.setObserver(!0)},beforeDestroy:function(){this.setObserver(!1),this.tabs=[]},methods:{registerTab:function(e){he(this.registeredTabs,e)||this.registeredTabs.push(e)},unregisterTab:function(e){this.registeredTabs=this.registeredTabs.slice().filter(function(r){return r!==e})},setObserver:function(){var e=this,r=arguments.length>0&&arguments[0]!==void 0?arguments[0]:!0;if(this.$_observer&&this.$_observer.disconnect(),this.$_observer=null,r){var n=function(){e.$nextTick(function(){We(function(){e.updateTabs()})})};this.$_observer=Iu(this.$refs.content,n,{childList:!0,subtree:!1,attributes:!0,attributeFilter:[\"id\"]})}},getTabs:function(){var e=this.registeredTabs,r=[];if(Je&&e.length>0){var n=e.map(function(i){return\"#\".concat(i.safeId())}).join(\", \");r=yn(n,this.$el).map(function(i){return i.id}).filter(pe)}return Rx(e,function(i,a){return r.indexOf(i.safeId())-r.indexOf(a.safeId())})},updateTabs:function(){var e=this.getTabs(),r=e.indexOf(e.slice().reverse().find(function(i){return i.localActive&&!i.disabled}));if(r<0){var n=this.currentTab;n>=e.length?r=e.indexOf(e.slice().reverse().find(Za)):e[n]&&!e[n].disabled&&(r=n)}r<0&&(r=e.indexOf(e.find(Za))),e.forEach(function(i,a){i.localActive=a===r}),this.tabs=e,this.currentTab=r},getButtonForTab:function(e){return(this.$refs.buttons||[]).find(function(r){return r.tab===e})},updateButton:function(e){var r=this.getButtonForTab(e);r&&r.$forceUpdate&&r.$forceUpdate()},activateTab:function(e){var r=this.currentTab,n=this.tabs,i=!1;if(e){var a=n.indexOf(e);if(a!==r&&a>-1&&!e.disabled){var o=new ko(cj,{cancelable:!0,vueTarget:this,componentId:this.safeId()});this.$emit(o.type,a,r,o),o.defaultPrevented||(this.currentTab=a,i=!0)}}return!i&&this[Lv]!==r&&this.$emit(bE,r),i},deactivateTab:function(e){return e?this.activateTab(this.tabs.filter(function(r){return r!==e}).find(Za)):!1},focusButton:function(e){var r=this;this.$nextTick(function(){we(r.getButtonForTab(e))})},emitTabClick:function(e,r){Po(r)&&e&&e.$emit&&!e.disabled&&e.$emit(Ln,r)},clickTab:function(e,r){this.activateTab(e),this.emitTabClick(e,r)},firstTab:function(e){var r=this.tabs.find(Za);this.activateTab(r)&&e&&(this.focusButton(r),this.emitTabClick(r,e))},previousTab:function(e){var r=Fe(this.currentTab,0),n=this.tabs.slice(0,r).reverse().find(Za);this.activateTab(n)&&e&&(this.focusButton(n),this.emitTabClick(n,e))},nextTab:function(e){var r=Fe(this.currentTab,-1),n=this.tabs.slice(r+1).find(Za);this.activateTab(n)&&e&&(this.focusButton(n),this.emitTabClick(n,e))},lastTab:function(e){var r=this.tabs.slice().reverse().find(Za);this.activateTab(r)&&e&&(this.focusButton(r),this.emitTabClick(r,e))}},render:function(e){var r=this,n=this.align,i=this.card,a=this.end,o=this.fill,s=this.firstTab,l=this.justified,u=this.lastTab,f=this.nextTab,d=this.noKeyNav,p=this.noNavStyle,h=this.pills,b=this.previousTab,y=this.small,P=this.tabs,C=this.vertical,R=P.find(function(H){return H.localActive&&!H.disabled}),D=P.find(function(H){return!H.disabled}),B=P.map(function(H,W){var j,E=H.safeId,v=null;return d||(v=-1,(H===R||!R&&H===D)&&(v=null)),e(HW,Un({props:{controls:E?E():null,id:H.controlledBy||(E?E(\"_BV_tab_button_\"):null),noKeyNav:d,posInSet:W+1,setSize:P.length,tab:H,tabIndex:v},on:(j={},Un(j,Ln,function(w){r.clickTab(H,w)}),Un(j,OD,s),Un(j,$D,b),Un(j,PD,f),Un(j,wD,u),j),key:H[ji]||W,ref:\"buttons\"},Pb,!0))}),A=e(JR,{class:this.localNavClass,attrs:{role:\"tablist\",id:this.safeId(\"_BV_tab_controls_\")},props:{fill:o,justified:l,align:n,tabs:!p&&!h,pills:!p&&h,vertical:C,small:y,cardHeader:i&&!C},ref:\"nav\"},[this.normalizeSlot(_2)||e(),B,this.normalizeSlot(O2)||e()]);A=e(\"div\",{class:[{\"card-header\":i&&!C&&!a,\"card-footer\":i&&!C&&a,\"col-auto\":C},this.navWrapperClass],key:\"bv-tabs-nav\"},[A]);var V=this.normalizeSlot()||[],N=e();V.length===0&&(N=e(\"div\",{class:[\"tab-pane\",\"active\",{\"card-body\":i}],key:\"bv-empty-tab\"},this.normalizeSlot(ID)));var G=e(\"div\",{staticClass:\"tab-content\",class:[{col:C},this.contentClass],attrs:{id:this.safeId(\"_BV_tab_container_\")},key:\"bv-content\",ref:\"content\"},[V,N]);return e(this.tag,{staticClass:\"tabs\",class:{row:C,\"no-gutters\":C&&i},attrs:{id:this.safeId()}},[a?G:e(),A,a?e():G])}}),$n,Vl;function yE(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function OE(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?yE(Object(r),!0).forEach(function(n){zr(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):yE(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function zr(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Id=\"active\",_E=Ia+Id,WW=z(ie(OE(OE({},Ke),{},($n={},zr($n,Id,c(_,!1)),zr($n,\"buttonId\",c(g)),zr($n,\"disabled\",c(_,!1)),zr($n,\"lazy\",c(_,!1)),zr($n,\"noBody\",c(_,!1)),zr($n,\"tag\",c(g,\"div\")),zr($n,\"title\",c(g)),zr($n,\"titleItemClass\",c(de)),zr($n,\"titleLinkAttributes\",c(Mt)),zr($n,\"titleLinkClass\",c(de)),$n))),oD),KW=I({name:oD,mixins:[Ze,ve],inject:{getBvTabs:{default:function(){return function(){return{}}}}},props:WW,data:function(){return{localActive:this[Id]&&!this.disabled}},computed:{bvTabs:function(){return this.getBvTabs()},_isTab:function(){return!0},tabClasses:function(){var e=this.localActive,r=this.disabled;return[{active:e,disabled:r,\"card-body\":this.bvTabs.card&&!this.noBody},e?this.bvTabs.activeTabClass:null]},controlledBy:function(){return this.buttonId||this.safeId(\"__BV_tab_button__\")},computedNoFade:function(){return!this.bvTabs.fade},computedLazy:function(){return this.bvTabs.lazy||this.lazy}},watch:(Vl={},zr(Vl,Id,function(t,e){t!==e&&(t?this.activate():this.deactivate()||this.$emit(_E,this.localActive))}),zr(Vl,\"disabled\",function(e,r){if(e!==r){var n=this.bvTabs.firstTab;e&&this.localActive&&n&&(this.localActive=!1,n())}}),zr(Vl,\"localActive\",function(e){this.$emit(_E,e)}),Vl),mounted:function(){this.registerTab()},updated:function(){var e=this.bvTabs.updateButton;e&&this.hasNormalizedSlot(Wu)&&e(this)},beforeDestroy:function(){this.unregisterTab()},methods:{registerTab:function(){var e=this.bvTabs.registerTab;e&&e(this)},unregisterTab:function(){var e=this.bvTabs.unregisterTab;e&&e(this)},activate:function(){var e=this.bvTabs.activateTab;return e&&!this.disabled?e(this):!1},deactivate:function(){var e=this.bvTabs.deactivateTab;return e&&this.localActive?e(this):!1}},render:function(e){var r=this.localActive,n=e(this.tag,{staticClass:\"tab-pane\",class:this.tabClasses,directives:[{name:\"show\",value:r}],attrs:{role:\"tabpanel\",id:this.safeId(),\"aria-hidden\":r?\"false\":\"true\",\"aria-labelledby\":this.controlledBy||null},ref:\"panel\"},[r||!this.computedLazy?this.normalizeSlot():e()]);return e(Io,{props:{mode:\"out-in\",noFade:this.computedNoFade}},[n])}}),YW=ae({components:{BTabs:GW,BTab:KW}}),qW=ae({components:{BTime:MR}});function Rf(t){return typeof Symbol==\"function\"&&typeof Symbol.iterator==\"symbol\"?Rf=function(e){return typeof e}:Rf=function(e){return e&&typeof Symbol==\"function\"&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},Rf(t)}function XW(t){return JW(t)||ZW(t)||QW()}function JW(t){if(Array.isArray(t)){for(var e=0,r=new Array(t.length);e<t.length;e++)r[e]=t[e];return r}}function ZW(t){if(Symbol.iterator in Object(t)||Object.prototype.toString.call(t)===\"[object Arguments]\")return Array.from(t)}function QW(){throw new TypeError(\"Invalid attempt to spread non-iterable instance\")}var Kc=typeof window<\"u\";function e7(t){return Array.isArray(t)||Rf(t)===\"object\"?Object.freeze(t):t}function t7(t){var e=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return t.reduce(function(r,n){var i=n.passengers[0],a=typeof i==\"function\"?i(e):n.passengers;return r.concat(a)},[])}function r7(t,e){return t.map(function(r,n){return[n,r]}).sort(function(r,n){return e(r[1],n[1])||r[0]-n[0]}).map(function(r){return r[1]})}function wE(t,e){return e.reduce(function(r,n){return t.hasOwnProperty(n)&&(r[n]=t[n]),r},{})}var Hx={},n7={},i7={},a7=ye.extend({data:function(){return{transports:Hx,targets:n7,sources:i7,trackInstances:Kc}},methods:{open:function(e){if(!!Kc){var r=e.to,n=e.from,i=e.passengers,a=e.order,o=a===void 0?1/0:a;if(!(!r||!n||!i)){var s={to:r,from:n,passengers:e7(i),order:o},l=Object.keys(this.transports);l.indexOf(r)===-1&&ye.set(this.transports,r,[]);var u=this.$_getTransportIndex(s),f=this.transports[r].slice(0);u===-1?f.push(s):f[u]=s,this.transports[r]=r7(f,function(d,p){return d.order-p.order})}}},close:function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,n=e.to,i=e.from;if(!(!n||!i&&r===!1)&&!!this.transports[n])if(r)this.transports[n]=[];else{var a=this.$_getTransportIndex(e);if(a>=0){var o=this.transports[n].slice(0);o.splice(a,1),this.transports[n]=o}}},registerTarget:function(e,r,n){!Kc||(this.trackInstances&&!n&&this.targets[e]&&console.warn(\"[portal-vue]: Target \".concat(e,\" already exists\")),this.$set(this.targets,e,Object.freeze([r])))},unregisterTarget:function(e){this.$delete(this.targets,e)},registerSource:function(e,r,n){!Kc||(this.trackInstances&&!n&&this.sources[e]&&console.warn(\"[portal-vue]: source \".concat(e,\" already exists\")),this.$set(this.sources,e,Object.freeze([r])))},unregisterSource:function(e){this.$delete(this.sources,e)},hasTarget:function(e){return!!(this.targets[e]&&this.targets[e][0])},hasSource:function(e){return!!(this.sources[e]&&this.sources[e][0])},hasContentFor:function(e){return!!this.transports[e]&&!!this.transports[e].length},$_getTransportIndex:function(e){var r=e.to,n=e.from;for(var i in this.transports[r])if(this.transports[r][i].from===n)return+i;return-1}}}),mn=new a7(Hx),o7=1,zx=ye.extend({name:\"portal\",props:{disabled:{type:Boolean},name:{type:String,default:function(){return String(o7++)}},order:{type:Number,default:0},slim:{type:Boolean},slotProps:{type:Object,default:function(){return{}}},tag:{type:String,default:\"DIV\"},to:{type:String,default:function(){return String(Math.round(Math.random()*1e7))}}},created:function(){var e=this;this.$nextTick(function(){mn.registerSource(e.name,e)})},mounted:function(){this.disabled||this.sendUpdate()},updated:function(){this.disabled?this.clear():this.sendUpdate()},beforeDestroy:function(){mn.unregisterSource(this.name),this.clear()},watch:{to:function(e,r){r&&r!==e&&this.clear(r),this.sendUpdate()}},methods:{clear:function(e){var r={from:this.name,to:e||this.to};mn.close(r)},normalizeSlots:function(){return this.$scopedSlots.default?[this.$scopedSlots.default]:this.$slots.default},normalizeOwnChildren:function(e){return typeof e==\"function\"?e(this.slotProps):e},sendUpdate:function(){var e=this.normalizeSlots();if(e){var r={from:this.name,to:this.to,passengers:XW(e),order:this.order};mn.open(r)}else this.clear()}},render:function(e){var r=this.$slots.default||this.$scopedSlots.default||[],n=this.tag;return r&&this.disabled?r.length<=1&&this.slim?this.normalizeOwnChildren(r)[0]:e(n,[this.normalizeOwnChildren(r)]):this.slim?e():e(n,{class:{\"v-portal\":!0},style:{display:\"none\"},key:\"v-portal-placeholder\"})}}),Ux=ye.extend({name:\"portalTarget\",props:{multiple:{type:Boolean,default:!1},name:{type:String,required:!0},slim:{type:Boolean,default:!1},slotProps:{type:Object,default:function(){return{}}},tag:{type:String,default:\"div\"},transition:{type:[String,Object,Function]}},data:function(){return{transports:mn.transports,firstRender:!0}},created:function(){var e=this;this.$nextTick(function(){mn.registerTarget(e.name,e)})},watch:{ownTransports:function(){this.$emit(\"change\",this.children().length>0)},name:function(e,r){mn.unregisterTarget(r),mn.registerTarget(e,this)}},mounted:function(){var e=this;this.transition&&this.$nextTick(function(){e.firstRender=!1})},beforeDestroy:function(){mn.unregisterTarget(this.name)},computed:{ownTransports:function(){var e=this.transports[this.name]||[];return this.multiple?e:e.length===0?[]:[e[e.length-1]]},passengers:function(){return t7(this.ownTransports,this.slotProps)}},methods:{children:function(){return this.passengers.length!==0?this.passengers:this.$scopedSlots.default?this.$scopedSlots.default(this.slotProps):this.$slots.default||[]},noWrapper:function(){var e=this.slim&&!this.transition;return e&&this.children().length>1&&console.warn(\"[portal-vue]: PortalTarget with `slim` option received more than one child element.\"),e}},render:function(e){var r=this.noWrapper(),n=this.children(),i=this.transition||this.tag;return r?n[0]:this.slim&&!i?e():e(i,{props:{tag:this.transition&&this.tag?this.tag:void 0},class:{\"vue-portal-target\":!0}},n)}}),s7=0,l7=[\"disabled\",\"name\",\"order\",\"slim\",\"slotProps\",\"tag\",\"to\"],u7=[\"multiple\",\"transition\"];ye.extend({name:\"MountingPortal\",inheritAttrs:!1,props:{append:{type:[Boolean,String]},bail:{type:Boolean},mountTo:{type:String,required:!0},disabled:{type:Boolean},name:{type:String,default:function(){return\"mounted_\"+String(s7++)}},order:{type:Number,default:0},slim:{type:Boolean},slotProps:{type:Object,default:function(){return{}}},tag:{type:String,default:\"DIV\"},to:{type:String,default:function(){return String(Math.round(Math.random()*1e7))}},multiple:{type:Boolean,default:!1},targetSlim:{type:Boolean},targetSlotProps:{type:Object,default:function(){return{}}},targetTag:{type:String,default:\"div\"},transition:{type:[String,Object,Function]}},created:function(){if(!(typeof document>\"u\")){var e=document.querySelector(this.mountTo);if(!e){console.error(\"[portal-vue]: Mount Point '\".concat(this.mountTo,\"' not found in document\"));return}var r=this.$props;if(mn.targets[r.name]){r.bail?console.warn(\"[portal-vue]: Target \".concat(r.name,` is already mounted.\n        Aborting because 'bail: true' is set`)):this.portalTarget=mn.targets[r.name];return}var n=r.append;if(n){var i=typeof n==\"string\"?n:\"DIV\",a=document.createElement(i);e.appendChild(a),e=a}var o=wE(this.$props,u7);o.slim=this.targetSlim,o.tag=this.targetTag,o.slotProps=this.targetSlotProps,o.name=this.to,this.portalTarget=new Ux({el:e,parent:this.$parent||this,propsData:o})}},beforeDestroy:function(){var e=this.portalTarget;if(this.append){var r=e.$el;r.parentNode.removeChild(r)}e.$destroy()},render:function(e){if(!this.portalTarget)return console.warn(\"[portal-vue] Target wasn't mounted\"),e();if(!this.$scopedSlots.manual){var r=wE(this.$props,l7);return e(zx,{props:r,attrs:this.$attrs,on:this.$listeners,scopedSlots:this.$scopedSlots},this.$slots.default)}var n=this.$scopedSlots.manual({to:this.to});return Array.isArray(n)&&(n=n[0]),n||e()}});var c7=I({mixins:[ve],data:function(){return{name:\"b-toaster\"}},methods:{onAfterEnter:function(e){var r=this;We(function(){hr(e,\"\".concat(r.name,\"-enter-to\"))})}},render:function(e){return e(\"transition-group\",{props:{tag:\"div\",name:this.name},on:{afterEnter:this.onAfterEnter}},this.normalizeSlot())}}),f7=z({ariaAtomic:c(g),ariaLive:c(g),name:c(g,void 0,!0),role:c(g)},As),Gx=I({name:As,mixins:[Qn],props:f7,data:function(){return{doRender:!1,dead:!1,staticName:this.name}},beforeMount:function(){var e=this.name;this.staticName=e,mn.hasTarget(e)?(jt('A \"<portal-target>\" with name \"'.concat(e,'\" already exists in the document.'),As),this.dead=!0):this.doRender=!0},beforeDestroy:function(){this.doRender&&this.emitOnRoot(bt(As,xb),this.name)},destroyed:function(){var e=this.$el;e&&e.parentNode&&e.parentNode.removeChild(e)},render:function(e){var r=e(\"div\",{class:[\"d-none\",{\"b-dead-toaster\":this.dead}]});if(this.doRender){var n=e(Ux,{staticClass:\"b-toaster-slot\",props:{name:this.staticName,multiple:!0,tag:\"div\",slim:!1,transition:c7}});r=e(\"div\",{staticClass:\"b-toaster\",class:[this.staticName],attrs:{id:this.staticName,role:this.role||null,\"aria-live\":this.ariaLive,\"aria-atomic\":this.ariaAtomic}},[n])}return r}}),us;function TE(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function di(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?TE(Object(r),!0).forEach(function(n){gs(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):TE(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function gs(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var zp=Nt(\"visible\",{type:_,defaultValue:!1,event:en}),d7=zp.mixin,p7=zp.props,Fv=zp.prop,h7=zp.event,SE=1e3,Wx=Zn(ei,[\"href\",\"to\"]),Kx=z(ie(di(di(di(di({},Ke),p7),Wx),{},{appendToast:c(_,!1),autoHideDelay:c(re,5e3),bodyClass:c(de),headerClass:c(de),headerTag:c(g,\"header\"),isStatus:c(_,!1),noAutoHide:c(_,!1),noCloseButton:c(_,!1),noFade:c(_,!1),noHoverPause:c(_,!1),solid:c(_,!1),static:c(_,!1),title:c(g),toastClass:c(de),toaster:c(g,\"b-toaster-top-right\"),variant:c(g)})),Li),Yx=I({name:Li,mixins:[Vt,Ze,d7,Qn,ve,dy],inheritAttrs:!1,props:Kx,data:function(){return{isMounted:!1,doRender:!1,localShow:!1,isTransitioning:!1,isHiding:!1,order:0,dismissStarted:0,resumeDismiss:0}},computed:{toastClasses:function(){var e=this.appendToast,r=this.variant;return gs({\"b-toast-solid\":this.solid,\"b-toast-append\":e,\"b-toast-prepend\":!e},\"b-toast-\".concat(r),r)},slotScope:function(){var e=this.hide;return{hide:e}},computedDuration:function(){return Fe(ee(this.autoHideDelay,0),SE)},computedToaster:function(){return String(this.toaster)},transitionHandlers:function(){return{beforeEnter:this.onBeforeEnter,afterEnter:this.onAfterEnter,beforeLeave:this.onBeforeLeave,afterLeave:this.onAfterLeave}},computedAttrs:function(){return di(di({},this.bvAttrs),{},{id:this.safeId(),tabindex:\"0\"})}},watch:(us={},gs(us,Fv,function(t){this[t?\"show\":\"hide\"]()}),gs(us,\"localShow\",function(e){e!==this[Fv]&&this.$emit(h7,e)}),gs(us,\"toaster\",function(){this.$nextTick(this.ensureToaster)}),gs(us,\"static\",function(e){e&&this.localShow&&this.ensureToaster()}),us),created:function(){this.$_dismissTimer=null},mounted:function(){var e=this;this.isMounted=!0,this.$nextTick(function(){e[Fv]&&We(function(){e.show()})}),this.listenOnRoot(xt(Li,tr),function(r){r===e.safeId()&&e.show()}),this.listenOnRoot(xt(Li,Xr),function(r){(!r||r===e.safeId())&&e.hide()}),this.listenOnRoot(bt(As,xb),function(r){r===e.computedToaster&&e.hide()})},beforeDestroy:function(){this.clearDismissTimer()},methods:{show:function(){var e=this;if(!this.localShow){this.ensureToaster();var r=this.buildEvent(tr);this.emitEvent(r),this.dismissStarted=this.resumeDismiss=0,this.order=Date.now()*(this.appendToast?1:-1),this.isHiding=!1,this.doRender=!0,this.$nextTick(function(){We(function(){e.localShow=!0})})}},hide:function(){var e=this;if(this.localShow){var r=this.buildEvent(Xr);this.emitEvent(r),this.setHoverHandler(!1),this.dismissStarted=this.resumeDismiss=0,this.clearDismissTimer(),this.isHiding=!0,We(function(){e.localShow=!1})}},buildEvent:function(e){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return new ko(e,di(di({cancelable:!1,target:this.$el||null,relatedTarget:null},r),{},{vueTarget:this,componentId:this.safeId()}))},emitEvent:function(e){var r=e.type;this.emitOnRoot(bt(Li,r),e),this.$emit(r,e)},ensureToaster:function(){if(!this.static){var e=this.computedToaster;if(!mn.hasTarget(e)){var r=document.createElement(\"div\");document.body.appendChild(r);var n=ka(this.bvEventRoot,Gx,{propsData:{name:e}});n.$mount(r)}}},startDismissTimer:function(){this.clearDismissTimer(),this.noAutoHide||(this.$_dismissTimer=setTimeout(this.hide,this.resumeDismiss||this.computedDuration),this.dismissStarted=Date.now(),this.resumeDismiss=0)},clearDismissTimer:function(){clearTimeout(this.$_dismissTimer),this.$_dismissTimer=null},setHoverHandler:function(e){var r=this.$refs[\"b-toast\"];qn(e,r,\"mouseenter\",this.onPause,De),qn(e,r,\"mouseleave\",this.onUnPause,De)},onPause:function(){if(!(this.noAutoHide||this.noHoverPause||!this.$_dismissTimer||this.resumeDismiss)){var e=Date.now()-this.dismissStarted;e>0&&(this.clearDismissTimer(),this.resumeDismiss=Fe(this.computedDuration-e,SE))}},onUnPause:function(){if(this.noAutoHide||this.noHoverPause||!this.resumeDismiss){this.resumeDismiss=this.dismissStarted=0;return}this.startDismissTimer()},onLinkClick:function(){var e=this;this.$nextTick(function(){We(function(){e.hide()})})},onBeforeEnter:function(){this.isTransitioning=!0},onAfterEnter:function(){this.isTransitioning=!1;var e=this.buildEvent(Dr);this.emitEvent(e),this.startDismissTimer(),this.setHoverHandler(!0)},onBeforeLeave:function(){this.isTransitioning=!0},onAfterLeave:function(){this.isTransitioning=!1,this.order=0,this.resumeDismiss=this.dismissStarted=0;var e=this.buildEvent(Pt);this.emitEvent(e),this.doRender=!1},makeToast:function(e){var r=this,n=this.title,i=this.slotScope,a=Yu(this),o=[],s=this.normalizeSlot(S2,i);s?o.push(s):n&&o.push(e(\"strong\",{staticClass:\"mr-2\"},n)),this.noCloseButton||o.push(e(xo,{staticClass:\"ml-auto mb-1\",on:{click:function(){r.hide()}}}));var l=e();o.length>0&&(l=e(this.headerTag,{staticClass:\"toast-header\",class:this.headerClass},o));var u=e(a?tn:\"div\",{staticClass:\"toast-body\",class:this.bodyClass,props:a?at(Wx,this):{},on:a?{click:this.onLinkClick}:{}},this.normalizeSlot(kt,i));return e(\"div\",{staticClass:\"toast\",class:this.toastClass,attrs:this.computedAttrs,key:\"toast-\".concat(this[ji]),ref:\"toast\"},[l,u])}},render:function(e){if(!this.doRender||!this.isMounted)return e();var r=this.order,n=this.static,i=this.isHiding,a=this.isStatus,o=\"b-toast-\".concat(this[ji]),s=e(\"div\",{staticClass:\"b-toast\",class:this.toastClasses,attrs:di(di({},n?{}:this.scopedStyleAttrs),{},{id:this.safeId(\"_toast_outer\"),role:i?null:a?\"status\":\"alert\",\"aria-live\":i?null:a?\"polite\":\"assertive\",\"aria-atomic\":i?null:\"true\"}),key:o,ref:\"b-toast\"},[e(Io,{props:{noFade:this.noFade},on:this.transitionHandlers},[this.localShow?this.makeToast(e):e()])]);return e(zx,{props:{name:o,to:this.computedToaster,order:r,slim:!0,disabled:n}},[s])}});function v7(t,e){if(!(t instanceof e))throw new TypeError(\"Cannot call a class as a function\")}function PE(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,\"value\"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}function m7(t,e,r){return e&&PE(t.prototype,e),r&&PE(t,r),Object.defineProperty(t,\"prototype\",{writable:!1}),t}function EE(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function Hl(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?EE(Object(r),!0).forEach(function(n){g7(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):EE(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function g7(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function b7(t){return w7(t)||_7(t)||O7(t)||y7()}function y7(){throw new TypeError(`Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function O7(t,e){if(!!t){if(typeof t==\"string\")return xg(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);if(r===\"Object\"&&t.constructor&&(r=t.constructor.name),r===\"Map\"||r===\"Set\")return Array.from(t);if(r===\"Arguments\"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return xg(t,e)}}function _7(t){if(typeof Symbol<\"u\"&&t[Symbol.iterator]!=null||t[\"@@iterator\"]!=null)return Array.from(t)}function w7(t){if(Array.isArray(t))return xg(t)}function xg(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}var zl=\"$bvToast\",jv=\"_bv__toast\",T7=[\"id\"].concat(b7(ge(Pe(Kx,[\"static\",\"visible\"])))),Vv={toastContent:\"default\",title:\"toast-title\"},$E=function(e){return T7.reduce(function(r,n){return Et(e[n])||(r[n]=e[n]),r},{})},S7=function(e){var r=e.extend({name:aj,extends:Yx,mixins:[Ba],destroyed:function(){var o=this.$el;o&&o.parentNode&&o.parentNode.removeChild(o)},mounted:function(){var o=this,s=function(){o.localShow=!1,o.doRender=!1,o.$nextTick(function(){o.$nextTick(function(){We(function(){o.$destroy()})})})};this.bvParent.$once(Du,s),this.$once(Pt,s),this.listenOnRoot(bt(As,xb),function(l){l===o.toaster&&s()})}}),n=function(o,s){if(!rd(zl)){var l=ka(s,r,{propsData:Hl(Hl(Hl({},$E(vn(Li))),Pe(o,ge(Vv))),{},{static:!1,visible:!0})});ge(Vv).forEach(function(f){var d=o[f];Et(d)||(f===\"title\"&&Ae(d)&&(d=[s.$createElement(\"strong\",{class:\"mr-2\"},d)]),l.$slots[Vv[f]]=Me(d))});var u=document.createElement(\"div\");document.body.appendChild(u),l.$mount(u)}},i=function(){function a(o){v7(this,a),Gu(this,{_vm:o,_root:Oi(o)}),ip(this,{_vm:xn(),_root:xn()})}return m7(a,[{key:\"toast\",value:function(s){var l=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};!s||rd(zl)||n(Hl(Hl({},$E(l)),{},{toastContent:s}),this._vm)}},{key:\"show\",value:function(s){s&&this._root.$emit(xt(Li,tr),s)}},{key:\"hide\",value:function(){var s=arguments.length>0&&arguments[0]!==void 0?arguments[0]:null;this._root.$emit(xt(Li,Xr),s)}}]),a}();e.mixin({beforeCreate:function(){this[jv]=new i(this)}}),$o(e.prototype,zl)||Cb(e.prototype,zl,{get:function(){return(!this||!this[jv])&&jt('\"'.concat(zl,'\" must be accessed from a Vue instance \"this\" context.'),Li),this[jv]}})},P7=ae({plugins:{plugin:S7}}),E7=ae({components:{BToast:Yx,BToaster:Gx},plugins:{BVToastPlugin:P7}});function CE(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function DE(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?CE(Object(r),!0).forEach(function(n){$7(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):CE(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function $7(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var Rn=\"__BV_Tooltip__\",C7=\"hover focus\",AE={focus:!0,hover:!0,click:!0,blur:!0,manual:!0},D7=/^html$/i,A7=/^noninteractive$/i,R7=/^nofade$/i,x7=/^(auto|top(left|right)?|bottom(left|right)?|left(top|bottom)?|right(top|bottom)?)$/i,M7=/^(window|viewport|scrollParent)$/i,N7=/^d\\d+$/i,I7=/^ds\\d+$/i,B7=/^dh\\d+$/i,k7=/^o-?\\d+$/i,L7=/^v-.+$/i,F7=/\\s+/,j7=function(e,r){var n={title:void 0,trigger:\"\",placement:\"top\",fallbackPlacement:\"flip\",container:!1,animation:!0,offset:0,id:null,html:!1,interactive:!0,disabled:!1,delay:vn(io,\"delay\",50),boundary:String(vn(io,\"boundary\",\"scrollParent\")),boundaryPadding:ee(vn(io,\"boundaryPadding\",5),0),variant:vn(io,\"variant\"),customClass:vn(io,\"customClass\")};if(Ae(e.value)||Kn(e.value)||se(e.value)?n.title=e.value:yr(e.value)&&(n=DE(DE({},n),e.value)),Et(n.title)){var i=Nr?r.props:(r.data||{}).attrs;n.title=i&&!Ge(i.title)?i.title:void 0}yr(n.delay)||(n.delay={show:ee(n.delay,0),hide:ee(n.delay,0)}),e.arg&&(n.container=\"#\".concat(e.arg)),ge(e.modifiers).forEach(function(o){if(D7.test(o))n.html=!0;else if(A7.test(o))n.interactive=!1;else if(R7.test(o))n.animation=!1;else if(x7.test(o))n.placement=o;else if(M7.test(o))o=o===\"scrollparent\"?\"scrollParent\":o,n.boundary=o;else if(N7.test(o)){var s=ee(o.slice(1),0);n.delay.show=s,n.delay.hide=s}else I7.test(o)?n.delay.show=ee(o.slice(2),0):B7.test(o)?n.delay.hide=ee(o.slice(2),0):k7.test(o)?n.offset=ee(o.slice(1),0):L7.test(o)&&(n.variant=o.slice(2)||null)});var a={};return Me(n.trigger||\"\").filter(pe).join(\" \").trim().toLowerCase().split(F7).forEach(function(o){AE[o]&&(a[o]=!0)}),ge(e.modifiers).forEach(function(o){o=o.toLowerCase(),AE[o]&&(a[o]=!0)}),n.trigger=ge(a).join(\" \"),n.trigger===\"blur\"&&(n.trigger=\"focus\"),n.trigger||(n.trigger=C7),n},RE=function(e,r,n){if(!!Je){var i=j7(r,n);if(!e[Rn]){var a=gi(n,r);e[Rn]=ka(a,my,{_scopeId:js(a,void 0)}),e[Rn].__bv_prev_data__={},e[Rn].$on(tr,function(){se(i.title)&&e[Rn].updateData({title:i.title(e)})})}var o={title:i.title,triggers:i.trigger,placement:i.placement,fallbackPlacement:i.fallbackPlacement,variant:i.variant,customClass:i.customClass,container:i.container,boundary:i.boundary,delay:i.delay,offset:i.offset,noFade:!i.animation,id:i.id,interactive:i.interactive,disabled:i.disabled,html:i.html},s=e[Rn].__bv_prev_data__;if(e[Rn].__bv_prev_data__=o,!je(o,s)){var l={target:e};ge(o).forEach(function(u){o[u]!==s[u]&&(l[u]=u===\"title\"&&se(o[u])?o[u](e):o[u])}),e[Rn].updateData(l)}}},V7=function(e){e[Rn]&&(e[Rn].$destroy(),e[Rn]=null),delete e[Rn]},H7={bind:function(e,r,n){RE(e,r,n)},componentUpdated:function(e,r,n){Eb(function(){RE(e,r,n)})},unbind:function(e){V7(e)}},qx=ae({directives:{VBTooltip:H7}}),z7=ae({components:{BTooltip:ux},plugins:{VBTooltipPlugin:qx}}),U7=ae({plugins:{AlertPlugin:X2,AspectPlugin:nV,AvatarPlugin:ZV,BadgePlugin:tH,BreadcrumbPlugin:sH,ButtonPlugin:lH,ButtonGroupPlugin:cH,ButtonToolbarPlugin:pH,CalendarPlugin:PH,CardPlugin:UH,CarouselPlugin:i5,CollapsePlugin:kA,DropdownPlugin:ay,EmbedPlugin:Wz,FormPlugin:t3,FormCheckboxPlugin:c3,FormDatepickerPlugin:g3,FormFilePlugin:$3,FormGroupPlugin:B3,FormInputPlugin:H3,FormRadioPlugin:U3,FormRatingPlugin:X3,FormSelectPlugin:u8,FormSpinbuttonPlugin:p8,FormTagsPlugin:E8,FormTextareaPlugin:D8,FormTimepickerPlugin:U8,ImagePlugin:G8,InputGroupPlugin:eU,JumbotronPlugin:aU,LayoutPlugin:cU,LinkPlugin:fU,ListGroupPlugin:bU,MediaPlugin:SU,ModalPlugin:mG,NavPlugin:ex,NavbarPlugin:UG,OverlayPlugin:qG,PaginationPlugin:n4,PaginationNavPlugin:l4,PopoverPlugin:V4,ProgressPlugin:G4,SidebarPlugin:l6,SkeletonPlugin:LW,SpinnerPlugin:FW,TablePlugin:RW,TabsPlugin:YW,TimePlugin:qW,ToastPlugin:E7,TooltipPlugin:z7}}),G7=ae({directives:{VBHover:uR}}),W7=ae({directives:{VBModal:XR}});function xE(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter(function(i){return Object.getOwnPropertyDescriptor(t,i).enumerable})),r.push.apply(r,n)}return r}function ME(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?xE(Object(r),!0).forEach(function(n){K7(t,n,r[n])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):xE(Object(r)).forEach(function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(r,n))})}return t}function K7(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function Y7(t,e){if(!(t instanceof e))throw new TypeError(\"Cannot call a class as a function\")}function NE(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,\"value\"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}function q7(t,e,r){return e&&NE(t.prototype,e),r&&NE(t,r),Object.defineProperty(t,\"prototype\",{writable:!1}),t}var X7=\"v-b-scrollspy\",J7=\"dropdown-item\",Hv=\"active\",Z7=\".nav, .list-group\",zv=\".nav-link\",Uv=\".nav-item\",IE=\".list-group-item\",Q7=\".dropdown, .dropup\",eK=\".dropdown-item\",tK=\".dropdown-toggle\",rK=bt(\"BVScrollspy\",\"activate\"),nK=\"offset\",Gv=\"position\",iK={element:\"body\",offset:10,method:\"auto\",throttle:75},aK={element:\"(string|element|component)\",offset:\"number\",method:\"string\",throttle:\"number\"},BE=[\"webkitTransitionEnd\",\"transitionend\",\"otransitionend\",\"oTransitionEnd\"],oK=function(e){return DF(e).match(/\\s([a-zA-Z]+)/)[1].toLowerCase()},sK=function(e,r,n){for(var i in n)if($o(n,i)){var a=n[i],o=r[i],s=o&&et(o)?\"element\":oK(o);s=o&&o._isVue?\"component\":s,new RegExp(a).test(s)||jt(\"\".concat(e,': Option \"').concat(i,'\" provided type \"').concat(s,'\" but expected type \"').concat(a,'\"'))}},Xx=function(){function t(e,r,n){Y7(this,t),this.$el=e,this.$scroller=null,this.$selector=[zv,IE,eK].join(\",\"),this.$offsets=[],this.$targets=[],this.$activeTarget=null,this.$scrollHeight=0,this.$resizeTimeout=null,this.$scrollerObserver=null,this.$targetsObserver=null,this.$root=n||null,this.$config=null,this.updateConfig(r)}return q7(t,[{key:\"updateConfig\",value:function(r,n){this.$scroller&&(this.unlisten(),this.$scroller=null);var i=ME(ME({},this.constructor.Default),r);if(n&&(this.$root=n),sK(this.constructor.Name,i,this.constructor.DefaultType),this.$config=i,this.$root){var a=this;this.$root.$nextTick(function(){a.listen()})}else this.listen()}},{key:\"dispose\",value:function(){this.unlisten(),clearTimeout(this.$resizeTimeout),this.$resizeTimeout=null,this.$el=null,this.$config=null,this.$scroller=null,this.$selector=null,this.$offsets=null,this.$targets=null,this.$activeTarget=null,this.$scrollHeight=null}},{key:\"listen\",value:function(){var r=this,n=this.getScroller();n&&n.tagName!==\"BODY\"&&it(n,\"scroll\",this,De),it(window,\"scroll\",this,De),it(window,\"resize\",this,De),it(window,\"orientationchange\",this,De),BE.forEach(function(i){it(window,i,r,De)}),this.setObservers(!0),this.handleEvent(\"refresh\")}},{key:\"unlisten\",value:function(){var r=this,n=this.getScroller();this.setObservers(!1),n&&n.tagName!==\"BODY\"&&ft(n,\"scroll\",this,De),ft(window,\"scroll\",this,De),ft(window,\"resize\",this,De),ft(window,\"orientationchange\",this,De),BE.forEach(function(i){ft(window,i,r,De)})}},{key:\"setObservers\",value:function(r){var n=this;this.$scrollerObserver&&this.$scrollerObserver.disconnect(),this.$targetsObserver&&this.$targetsObserver.disconnect(),this.$scrollerObserver=null,this.$targetsObserver=null,r&&(this.$targetsObserver=Iu(this.$el,function(){n.handleEvent(\"mutation\")},{subtree:!0,childList:!0,attributes:!0,attributeFilter:[\"href\"]}),this.$scrollerObserver=Iu(this.getScroller(),function(){n.handleEvent(\"mutation\")},{subtree:!0,childList:!0,characterData:!0,attributes:!0,attributeFilter:[\"id\",\"style\",\"class\"]}))}},{key:\"handleEvent\",value:function(r){var n=Ae(r)?r:r.type,i=this,a=function(){i.$resizeTimeout||(i.$resizeTimeout=setTimeout(function(){i.refresh(),i.process(),i.$resizeTimeout=null},i.$config.throttle))};n===\"scroll\"?(this.$scrollerObserver||this.listen(),this.process()):/(resize|orientationchange|mutation|refresh)/.test(n)&&a()}},{key:\"refresh\",value:function(){var r=this,n=this.getScroller();if(!!n){var i=n!==n.window?Gv:nK,a=this.$config.method===\"auto\"?i:this.$config.method,o=a===Gv?I2:Hm,s=a===Gv?this.getScrollTop():0;return this.$offsets=[],this.$targets=[],this.$scrollHeight=this.getScrollHeight(),yn(this.$selector,this.$el).map(function(l){return bn(l,\"href\")}).filter(function(l){return l&&$_.test(l||\"\")}).map(function(l){var u=l.replace($_,\"$1\").trim();if(!u)return null;var f=gn(u,n);return f&&Yn(f)?{offset:ee(o(f).top,0)+s,target:u}:null}).filter(pe).sort(function(l,u){return l.offset-u.offset}).reduce(function(l,u){return l[u.target]||(r.$offsets.push(u.offset),r.$targets.push(u.target),l[u.target]=!0),l},{}),this}}},{key:\"process\",value:function(){var r=this.getScrollTop()+this.$config.offset,n=this.getScrollHeight(),i=this.$config.offset+n-this.getOffsetHeight();if(this.$scrollHeight!==n&&this.refresh(),r>=i){var a=this.$targets[this.$targets.length-1];this.$activeTarget!==a&&this.activate(a);return}if(this.$activeTarget&&r<this.$offsets[0]&&this.$offsets[0]>0){this.$activeTarget=null,this.clear();return}for(var o=this.$offsets.length;o--;){var s=this.$activeTarget!==this.$targets[o]&&r>=this.$offsets[o]&&(Et(this.$offsets[o+1])||r<this.$offsets[o+1]);s&&this.activate(this.$targets[o])}}},{key:\"getScroller\",value:function(){if(this.$scroller)return this.$scroller;var r=this.$config.element;if(r)et(r.$el)?r=r.$el:Ae(r)&&(r=gn(r));else return null;return r?(this.$scroller=r.tagName===\"BODY\"?window:r,this.$scroller):null}},{key:\"getScrollTop\",value:function(){var r=this.getScroller();return r===window?r.pageYOffset:r.scrollTop}},{key:\"getScrollHeight\",value:function(){return this.getScroller().scrollHeight||Fe(document.body.scrollHeight,document.documentElement.scrollHeight)}},{key:\"getOffsetHeight\",value:function(){var r=this.getScroller();return r===window?window.innerHeight:Ro(r).height}},{key:\"activate\",value:function(r){var n=this;this.$activeTarget=r,this.clear();var i=yn(this.$selector.split(\",\").map(function(a){return\"\".concat(a,'[href$=\"').concat(r,'\"]')}).join(\",\"),this.$el);i.forEach(function(a){if(Ru(a,J7)){var o=Jr(Q7,a);o&&n.setActiveState(gn(tK,o),!0),n.setActiveState(a,!0)}else{n.setActiveState(a,!0),Vi(a.parentElement,Uv)&&n.setActiveState(a.parentElement,!0);for(var s=a;s;){s=Jr(Z7,s);var l=s?s.previousElementSibling:null;l&&Vi(l,\"\".concat(zv,\", \").concat(IE))&&n.setActiveState(l,!0),l&&Vi(l,Uv)&&(n.setActiveState(gn(zv,l),!0),n.setActiveState(l,!0))}}}),i&&i.length>0&&this.$root&&this.$root.$emit(rK,r,i)}},{key:\"clear\",value:function(){var r=this;yn(\"\".concat(this.$selector,\", \").concat(Uv),this.$el).filter(function(n){return Ru(n,Hv)}).forEach(function(n){return r.setActiveState(n,!1)})}},{key:\"setActiveState\",value:function(r,n){!r||(n?$r(r,Hv):hr(r,Hv))}}],[{key:\"Name\",get:function(){return X7}},{key:\"Default\",get:function(){return iK}},{key:\"DefaultType\",get:function(){return aK}}]),t}(),uo=\"__BV_Scrollspy__\",lK=/^\\d+$/,uK=/^(auto|position|offset)$/,cK=function(e){var r={};return e.arg&&(r.element=\"#\".concat(e.arg)),ge(e.modifiers).forEach(function(n){lK.test(n)?r.offset=ee(n,0):uK.test(n)&&(r.method=n)}),Ae(e.value)?r.element=e.value:Kn(e.value)?r.offset=Gm(e.value):St(e.value)&&ge(e.value).filter(function(n){return!!Xx.DefaultType[n]}).forEach(function(n){r[n]=e.value[n]}),r},Yc=function(e,r,n){if(!!Je){var i=cK(r);e[uo]?e[uo].updateConfig(i,Oi(gi(n,r))):e[uo]=new Xx(e,i,Oi(gi(n,r)))}},fK=function(e){e[uo]&&(e[uo].dispose(),e[uo]=null,delete e[uo])},dK={bind:function(e,r,n){Yc(e,r,n)},inserted:function(e,r,n){Yc(e,r,n)},update:function(e,r,n){r.value!==r.oldValue&&Yc(e,r,n)},componentUpdated:function(e,r,n){r.value!==r.oldValue&&Yc(e,r,n)},unbind:function(e){fK(e)}},pK=ae({directives:{VBScrollspy:dK}}),hK=ae({directives:{VBVisible:qb}}),vK=ae({plugins:{VBHoverPlugin:G7,VBModalPlugin:W7,VBPopoverPlugin:fx,VBScrollspyPlugin:pK,VBTogglePlugin:Xb,VBTooltipPlugin:qx,VBVisiblePlugin:hK}});/*!\n * BootstrapVue 2.23.1\n *\n * @link https://bootstrap-vue.org\n * @source https://github.com/bootstrap-vue/bootstrap-vue\n * @copyright (c) 2016-2022 BootstrapVue\n * @license MIT\n * https://github.com/bootstrap-vue/bootstrap-vue/blob/master/LICENSE\n */var mK=\"BootstrapVue\",gK=S$({plugins:{componentsPlugin:U7,directivesPlugin:vK}}),bK={install:gK,NAME:mK};const yK=bK;function Up(t,e,r,n,i,a,o,s){var l=typeof t==\"function\"?t.options:t;e&&(l.render=e,l.staticRenderFns=r,l._compiled=!0),n&&(l.functional=!0),a&&(l._scopeId=\"data-v-\"+a);var u;if(o?(u=function(p){p=p||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,!p&&typeof __VUE_SSR_CONTEXT__<\"u\"&&(p=__VUE_SSR_CONTEXT__),i&&i.call(this,p),p&&p._registeredComponents&&p._registeredComponents.add(o)},l._ssrRegister=u):i&&(u=s?function(){i.call(this,(l.functional?this.parent:this).$root.$options.shadowRoot)}:i),u)if(l.functional){l._injectStyles=u;var f=l.render;l.render=function(h,b){return u.call(b),f(h,b)}}else{var d=l.beforeCreate;l.beforeCreate=d?[].concat(d,u):[u]}return{exports:t,options:l}}const OK={name:\"Navigation\",components:{BIconGithub:yV},computed:{onMetric(){return this.$store.getters.getMetric}},methods:{changeLang(t){localStorage.setItem(\"lang\",t),this.$i18n.locale=t},checkCurrentLang(t){return this.$i18n.locale==t}},data(){return{i18nPrefix:\"_.Navigation.\",brandTitle:\"CAP Dashboard\",languages:[{name:\"English\",code:\"en-us\",active:!0},{name:\"\\u7B80\\u4F53\\u4E2D\\u6587\",code:\"zh-cn\",active:!1}],menus:[{name:\"Published\",path:\"/published\",variant:\"danger\",badge:\"publishedFailed\"},{name:\"Received\",path:\"/received\",variant:\"danger\",badge:\"receivedFailed\"},{name:\"Subscriber\",path:\"/subscriber\",variant:\"info\",badge:\"subscribers\"},{name:\"Nodes\",path:\"/nodes\",variant:\"light\",badge:\"servers\"}]}}};var _K=function(){var e=this,r=e._self._c;return r(\"div\",[r(\"b-navbar\",{attrs:{toggleable:\"lg\",type:\"dark\",sticky:\"\",variant:\"dark\"}},[r(\"b-container\",[r(\"b-navbar-toggle\",{attrs:{target:\"nav-collapse\"}}),r(\"b-collapse\",{attrs:{id:\"nav-collapse\",\"is-nav\":\"\"}},[r(\"b-navbar-brand\",{attrs:{to:\"/\"}},[r(\"svg\",{staticClass:\"d-inline-block align-top\",attrs:{xmlns:\"http://www.w3.org/2000/svg\",width:\"30\",height:\"30\",viewBox:\"0 0 192.13 196.72\"}},[r(\"g\",[r(\"g\",[r(\"path\",{attrs:{d:\"M166.87 100.62a71.54 71.54 0 0 1-70.81 70.8c-38.86.33-70.48-32.43-70.8-70.8-.14-16.28-25.4-16.3-25.26 0a98 98 0 0 0 26.75 66.51c16.88 18 40.66 28 65.06 29.44 24.86 1.46 49.1-8 67.83-24s29.43-39.31 32.07-63.53c.3-2.8.39-5.63.42-8.44.13-16.3-25.12-16.28-25.26 0z\",fill:\"#4a5699\"}}),r(\"path\",{attrs:{d:\"M25.26 96.07a71.54 71.54 0 0 1 70.8-70.81c16.28-.14 16.3-25.4 0-25.26a97.79 97.79 0 0 0-67.45 27.67C10.25 45.46.21 70.65 0 96.07c-.14 16.29 25.12 16.27 25.26 0z\",fill:\"#c45fa0\"}}),r(\"path\",{attrs:{d:\"M73.83 118.81c-10.58-14.11-9-30.09 4.14-41.46 12.31-10.62 30.52-6.6 40.93 6.34 4.33 5.37 13.39 4.48 17.86 0 5.26-5.25 4.31-12.5 0-17.86-17.42-21.65-50.71-25.9-73-9.21C40.58 74 34.26 107.87 52 131.56c4.12 5.5 10.82 8.31 17.28 4.53 5.42-3.18 8.66-11.76 4.53-17.28z\",fill:\"#e5594f\"}}),r(\"path\",{attrs:{d:\"M118.3 82.91c6 8 7.54 14 6.68 23.29.14-1.14.08-.93-.18.62-.26 1.32-.64 2.62-1 3.91a14.07 14.07 0 0 1-1.9 4.44c-2.34 4.43-4.59 6.68-8.84 10.1-5.38 4.32-4.48 13.39 0 17.86 5.25 5.26 12.5 4.31 17.85 0 21.66-17.42 25.91-50.71 9.22-73-4.12-5.5-10.82-8.31-17.28-4.53-5.43 3.18-8.67 11.76-4.53 17.28z\",fill:\"#f39a2b\"}})])])]),e._v(\" \"+e._s(e.$t(e.brandTitle))+\" \")]),r(\"b-navbar-nav\",e._l(e.menus,function(n){return r(\"b-nav-item\",{key:n.name,attrs:{to:n.path,\"active-class\":\"active\"}},[e._v(\" \"+e._s(e.$t(n.name))+\" \"),e.onMetric[n.badge]?r(\"b-badge\",{attrs:{variant:n.variant}},[e._v(\" \"+e._s(e.onMetric[n.badge]))]):e._e()],1)}),1)],1),r(\"b-navbar-nav\",{staticClass:\"ml-auto flex-row\"},[r(\"b-nav-item\",[r(\"b-dropdown\",{attrs:{size:\"sm\",id:\"dlLang\",text:\"secondary\",variant:\"secondary\",text:e.$t(\"LanguageName\")}},e._l(e.languages,function(n){return r(\"b-dropdown-item\",{key:n.code,staticClass:\"text-secondary drop-active\",attrs:{active:e.checkCurrentLang(n.code)},on:{click:function(i){return e.changeLang(n.code)}}},[e._v(e._s(n.name))])}),1)],1),r(\"b-nav-item\",{attrs:{href:\"https://github.com/dotnetcore/CAP\",target:\"_blank\",title:\"Github\"}},[r(\"b-icon-github\",{staticStyle:{width:\"24px\",height:\"24px\"}})],1)],1)],1)],1)],1)},wK=[],TK=Up(OK,_K,wK,!1,null,\"b874239e\",null,null);const SK=TK.exports;var PK=typeof globalThis<\"u\"?globalThis:typeof window<\"u\"?window:typeof global<\"u\"?global:typeof self<\"u\"?self:{};function Jx(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,\"default\")?t.default:t}var Zx={exports:{}},Cy={exports:{}},Qx=function(e,r){return function(){return e.apply(r,arguments)}},EK=Qx,Dy=Object.prototype.toString,Ay=function(t){return function(e){var r=Dy.call(e);return t[r]||(t[r]=r.slice(8,-1).toLowerCase())}}(Object.create(null));function La(t){return t=t.toLowerCase(),function(r){return Ay(r)===t}}function Gp(t){return Array.isArray(t)}function Mg(t){return typeof t>\"u\"}function $K(t){return t!==null&&!Mg(t)&&t.constructor!==null&&!Mg(t.constructor)&&typeof t.constructor.isBuffer==\"function\"&&t.constructor.isBuffer(t)}var eM=La(\"ArrayBuffer\");function CK(t){var e;return typeof ArrayBuffer<\"u\"&&ArrayBuffer.isView?e=ArrayBuffer.isView(t):e=t&&t.buffer&&eM(t.buffer),e}function DK(t){return typeof t==\"string\"}function tM(t){return typeof t==\"number\"}function rM(t){return t!==null&&typeof t==\"object\"}function xf(t){if(Ay(t)!==\"object\")return!1;var e=Object.getPrototypeOf(t);return e===null||e===Object.prototype}function AK(t){return t&&Object.keys(t).length===0&&Object.getPrototypeOf(t)===Object.prototype}var RK=La(\"Date\"),xK=La(\"File\"),MK=La(\"Blob\"),NK=La(\"FileList\");function Ry(t){return Dy.call(t)===\"[object Function]\"}function IK(t){return rM(t)&&Ry(t.pipe)}function BK(t){var e=\"[object FormData]\";return t&&(typeof FormData==\"function\"&&t instanceof FormData||Dy.call(t)===e||Ry(t.toString)&&t.toString()===e)}var kK=La(\"URLSearchParams\");function LK(t){return t.trim?t.trim():t.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,\"\")}function FK(){var t;return typeof navigator<\"u\"&&((t=navigator.product)===\"ReactNative\"||t===\"NativeScript\"||t===\"NS\")?!1:typeof window<\"u\"&&typeof document<\"u\"}function xy(t,e){if(!(t===null||typeof t>\"u\"))if(typeof t!=\"object\"&&(t=[t]),Gp(t))for(var r=0,n=t.length;r<n;r++)e.call(null,t[r],r,t);else for(var i in t)Object.prototype.hasOwnProperty.call(t,i)&&e.call(null,t[i],i,t)}function Ng(){var t={};function e(i,a){xf(t[a])&&xf(i)?t[a]=Ng(t[a],i):xf(i)?t[a]=Ng({},i):Gp(i)?t[a]=i.slice():t[a]=i}for(var r=0,n=arguments.length;r<n;r++)xy(arguments[r],e);return t}function jK(t,e,r){return xy(e,function(i,a){r&&typeof i==\"function\"?t[a]=EK(i,r):t[a]=i}),t}function VK(t){return t.charCodeAt(0)===65279&&(t=t.slice(1)),t}function HK(t,e,r,n){t.prototype=Object.create(e.prototype,n),t.prototype.constructor=t,r&&Object.assign(t.prototype,r)}function zK(t,e,r,n){var i,a,o,s={};if(e=e||{},t==null)return e;do{for(i=Object.getOwnPropertyNames(t),a=i.length;a-- >0;)o=i[a],(!n||n(o,t,e))&&!s[o]&&(e[o]=t[o],s[o]=!0);t=r!==!1&&Object.getPrototypeOf(t)}while(t&&(!r||r(t,e))&&t!==Object.prototype);return e}function UK(t,e,r){t=String(t),(r===void 0||r>t.length)&&(r=t.length),r-=e.length;var n=t.indexOf(e,r);return n!==-1&&n===r}function GK(t){if(!t)return null;if(Gp(t))return t;var e=t.length;if(!tM(e))return null;for(var r=new Array(e);e-- >0;)r[e]=t[e];return r}var WK=function(t){return function(e){return t&&e instanceof t}}(typeof Uint8Array<\"u\"&&Object.getPrototypeOf(Uint8Array));function KK(t,e){for(var r=t&&t[Symbol.iterator],n=r.call(t),i;(i=n.next())&&!i.done;){var a=i.value;e.call(t,a[0],a[1])}}function YK(t,e){for(var r,n=[];(r=t.exec(e))!==null;)n.push(r);return n}var qK=La(\"HTMLFormElement\"),XK=function(e){return function(r,n){return e.call(r,n)}}(Object.prototype.hasOwnProperty),Ht={isArray:Gp,isArrayBuffer:eM,isBuffer:$K,isFormData:BK,isArrayBufferView:CK,isString:DK,isNumber:tM,isObject:rM,isPlainObject:xf,isEmptyObject:AK,isUndefined:Mg,isDate:RK,isFile:xK,isBlob:MK,isFunction:Ry,isStream:IK,isURLSearchParams:kK,isStandardBrowserEnv:FK,forEach:xy,merge:Ng,extend:jK,trim:LK,stripBOM:VK,inherits:HK,toFlatObject:zK,kindOf:Ay,kindOfTest:La,endsWith:UK,toArray:GK,isTypedArray:WK,isFileList:NK,forEachEntry:KK,matchAll:YK,isHTMLForm:qK,hasOwnProperty:XK},nM=Ht;function zs(t,e,r,n,i){Error.call(this),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=new Error().stack,this.message=t,this.name=\"AxiosError\",e&&(this.code=e),r&&(this.config=r),n&&(this.request=n),i&&(this.response=i)}nM.inherits(zs,Error,{toJSON:function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:this.config,code:this.code,status:this.response&&this.response.status?this.response.status:null}}});var iM=zs.prototype,aM={};[\"ERR_BAD_OPTION_VALUE\",\"ERR_BAD_OPTION\",\"ECONNABORTED\",\"ETIMEDOUT\",\"ERR_NETWORK\",\"ERR_FR_TOO_MANY_REDIRECTS\",\"ERR_DEPRECATED\",\"ERR_BAD_RESPONSE\",\"ERR_BAD_REQUEST\",\"ERR_CANCELED\",\"ERR_NOT_SUPPORT\",\"ERR_INVALID_URL\"].forEach(function(t){aM[t]={value:t}});Object.defineProperties(zs,aM);Object.defineProperty(iM,\"isAxiosError\",{value:!0});zs.from=function(t,e,r,n,i,a){var o=Object.create(iM);return nM.toFlatObject(t,o,function(l){return l!==Error.prototype}),zs.call(o,t.message,e,r,n,i),o.cause=t,o.name=t.name,a&&Object.assign(o,a),o};var Fo=zs,oM={exports:{}},JK=typeof self==\"object\"?self.FormData:window.FormData;(function(t){t.exports=JK})(oM);var ot=Ht,ZK=Fo,QK=oM.exports;function Ig(t){return ot.isPlainObject(t)||ot.isArray(t)}function sM(t){return ot.endsWith(t,\"[]\")?t.slice(0,-2):t}function kE(t,e,r){return t?t.concat(e).map(function(i,a){return i=sM(i),!r&&a?\"[\"+i+\"]\":i}).join(r?\".\":\"\"):e}function e9(t){return ot.isArray(t)&&!t.some(Ig)}var t9=ot.toFlatObject(ot,{},null,function(e){return/^is[A-Z]/.test(e)});function r9(t){return t&&ot.isFunction(t.append)&&t[Symbol.toStringTag]===\"FormData\"&&t[Symbol.iterator]}function n9(t,e,r){if(!ot.isObject(t))throw new TypeError(\"target must be an object\");e=e||new(QK||FormData),r=ot.toFlatObject(r,{metaTokens:!0,dots:!1,indexes:!1},!1,function(y,P){return!ot.isUndefined(P[y])});var n=r.metaTokens,i=r.visitor||f,a=r.dots,o=r.indexes,s=r.Blob||typeof Blob<\"u\"&&Blob,l=s&&r9(e);if(!ot.isFunction(i))throw new TypeError(\"visitor must be a function\");function u(b){if(b===null)return\"\";if(ot.isDate(b))return b.toISOString();if(!l&&ot.isBlob(b))throw new ZK(\"Blob is not supported. Use a Buffer instead.\");return ot.isArrayBuffer(b)||ot.isTypedArray(b)?l&&typeof Blob==\"function\"?new Blob([b]):Buffer.from(b):b}function f(b,y,P){var C=b;if(b&&!P&&typeof b==\"object\"){if(ot.endsWith(y,\"{}\"))y=n?y:y.slice(0,-2),b=JSON.stringify(b);else if(ot.isArray(b)&&e9(b)||ot.isFileList(b)||ot.endsWith(y,\"[]\")&&(C=ot.toArray(b)))return y=sM(y),C.forEach(function(D,B){!ot.isUndefined(D)&&e.append(o===!0?kE([y],B,a):o===null?y:y+\"[]\",u(D))}),!1}return Ig(b)?!0:(e.append(kE(P,y,a),u(b)),!1)}var d=[],p=Object.assign(t9,{defaultVisitor:f,convertValue:u,isVisitable:Ig});function h(b,y){if(!ot.isUndefined(b)){if(d.indexOf(b)!==-1)throw Error(\"Circular reference detected in \"+y.join(\".\"));d.push(b),ot.forEach(b,function(C,R){var D=!ot.isUndefined(C)&&i.call(e,C,ot.isString(R)?R.trim():R,y,p);D===!0&&h(C,y?y.concat(R):[R])}),d.pop()}}if(!ot.isObject(t))throw new TypeError(\"data must be an object\");return h(t),e}var Wp=n9,i9=Wp;function LE(t){var e={\"!\":\"%21\",\"'\":\"%27\",\"(\":\"%28\",\")\":\"%29\",\"~\":\"%7E\",\"%20\":\"+\",\"%00\":\"\\0\"};return encodeURIComponent(t).replace(/[!'\\(\\)~]|%20|%00/g,function(n){return e[n]})}function lM(t,e){this._pairs=[],t&&i9(t,this,e)}var uM=lM.prototype;uM.append=function(e,r){this._pairs.push([e,r])};uM.toString=function(e){var r=e?function(n){return e.call(this,n,LE)}:LE;return this._pairs.map(function(i){return r(i[0])+\"=\"+r(i[1])},\"\").join(\"&\")};var cM=lM,a9=Ht,o9=cM;function s9(t){return encodeURIComponent(t).replace(/%3A/gi,\":\").replace(/%24/g,\"$\").replace(/%2C/gi,\",\").replace(/%20/g,\"+\").replace(/%5B/gi,\"[\").replace(/%5D/gi,\"]\")}var fM=function(e,r,n){if(!r)return e;var i=e.indexOf(\"#\");i!==-1&&(e=e.slice(0,i));var a=n&&n.encode||s9,o=n&&n.serialize,s;return o?s=o(r,n):s=a9.isURLSearchParams(r)?r.toString():new o9(r,n).toString(a),s&&(e+=(e.indexOf(\"?\")===-1?\"?\":\"&\")+s),e},l9=Ht;function rc(){this.handlers=[]}rc.prototype.use=function(e,r,n){return this.handlers.push({fulfilled:e,rejected:r,synchronous:n?n.synchronous:!1,runWhen:n?n.runWhen:null}),this.handlers.length-1};rc.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)};rc.prototype.clear=function(){this.handlers&&(this.handlers=[])};rc.prototype.forEach=function(e){l9.forEach(this.handlers,function(n){n!==null&&e(n)})};var u9=rc,c9=Ht,dM=function(e,r){c9.forEach(e,function(i,a){a!==r&&a.toUpperCase()===r.toUpperCase()&&(e[r]=i,delete e[a])})},pM={silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1},Kp={exports:{}},f9=cM,d9=typeof URLSearchParams<\"u\"?URLSearchParams:f9,p9=FormData,h9={isBrowser:!0,classes:{URLSearchParams:d9,FormData:p9,Blob},protocols:[\"http\",\"https\",\"file\",\"blob\",\"url\",\"data\"]};(function(t){t.exports=h9})(Kp);var v9=Ht,m9=Wp,FE=Kp.exports,g9=function(e,r){return m9(e,new FE.classes.URLSearchParams,Object.assign({visitor:function(n,i,a,o){return FE.isNode&&v9.isBuffer(n)?(this.append(i,n.toString(\"base64\")),!1):o.defaultVisitor.apply(this,arguments)}},r))},oa=Ht;function b9(t){return oa.matchAll(/\\w+|\\[(\\w*)]/g,t).map(function(e){return e[0]===\"[]\"?\"\":e[1]||e[0]})}function y9(t){var e={},r=Object.keys(t),n,i=r.length,a;for(n=0;n<i;n++)a=r[n],e[a]=t[a];return e}function O9(t){function e(n,i,a,o){var s=n[o++],l=Number.isFinite(+s),u=o>=n.length;if(s=!s&&oa.isArray(a)?a.length:s,u)return oa.hasOwnProperty(a,s)?a[s]=[a[s],i]:a[s]=i,!l;(!a[s]||!oa.isObject(a[s]))&&(a[s]=[]);var f=e(n,i,a[s],o);return f&&oa.isArray(a[s])&&(a[s]=y9(a[s])),!l}if(oa.isFormData(t)&&oa.isFunction(t.entries)){var r={};return oa.forEachEntry(t,function(n,i){e(b9(n),i,r,0)}),r}return null}var hM=O9,Wv,jE;function _9(){if(jE)return Wv;jE=1;var t=Fo;return Wv=function(r,n,i){var a=i.config.validateStatus;!i.status||!a||a(i.status)?r(i):n(new t(\"Request failed with status code \"+i.status,[t.ERR_BAD_REQUEST,t.ERR_BAD_RESPONSE][Math.floor(i.status/100)-4],i.config,i.request,i))},Wv}var Kv,VE;function w9(){if(VE)return Kv;VE=1;var t=Ht;return Kv=t.isStandardBrowserEnv()?function(){return{write:function(n,i,a,o,s,l){var u=[];u.push(n+\"=\"+encodeURIComponent(i)),t.isNumber(a)&&u.push(\"expires=\"+new Date(a).toGMTString()),t.isString(o)&&u.push(\"path=\"+o),t.isString(s)&&u.push(\"domain=\"+s),l===!0&&u.push(\"secure\"),document.cookie=u.join(\"; \")},read:function(n){var i=document.cookie.match(new RegExp(\"(^|;\\\\s*)(\"+n+\")=([^;]*)\"));return i?decodeURIComponent(i[3]):null},remove:function(n){this.write(n,\"\",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){}}}(),Kv}var T9=function(e){return/^([a-z][a-z\\d+\\-.]*:)?\\/\\//i.test(e)},S9=function(e,r){return r?e.replace(/\\/+$/,\"\")+\"/\"+r.replace(/^\\/+/,\"\"):e},P9=T9,E9=S9,vM=function(e,r){return e&&!P9(r)?E9(e,r):r},Yv,HE;function $9(){if(HE)return Yv;HE=1;var t=Ht,e=[\"age\",\"authorization\",\"content-length\",\"content-type\",\"etag\",\"expires\",\"from\",\"host\",\"if-modified-since\",\"if-unmodified-since\",\"last-modified\",\"location\",\"max-forwards\",\"proxy-authorization\",\"referer\",\"retry-after\",\"user-agent\"];return Yv=function(n){var i={},a,o,s;return n&&t.forEach(n.split(`\n`),function(u){if(s=u.indexOf(\":\"),a=t.trim(u.slice(0,s)).toLowerCase(),o=t.trim(u.slice(s+1)),a){if(i[a]&&e.indexOf(a)>=0)return;a===\"set-cookie\"?i[a]=(i[a]?i[a]:[]).concat([o]):i[a]=i[a]?i[a]+\", \"+o:o}}),i},Yv}var qv,zE;function C9(){if(zE)return qv;zE=1;var t=Ht;return qv=t.isStandardBrowserEnv()?function(){var r=/(msie|trident)/i.test(navigator.userAgent),n=document.createElement(\"a\"),i;function a(o){var s=o;return r&&(n.setAttribute(\"href\",s),s=n.href),n.setAttribute(\"href\",s),{href:n.href,protocol:n.protocol?n.protocol.replace(/:$/,\"\"):\"\",host:n.host,search:n.search?n.search.replace(/^\\?/,\"\"):\"\",hash:n.hash?n.hash.replace(/^#/,\"\"):\"\",hostname:n.hostname,port:n.port,pathname:n.pathname.charAt(0)===\"/\"?n.pathname:\"/\"+n.pathname}}return i=a(window.location.href),function(s){var l=t.isString(s)?a(s):s;return l.protocol===i.protocol&&l.host===i.host}}():function(){return function(){return!0}}(),qv}var Xv,UE;function Yp(){if(UE)return Xv;UE=1;var t=Fo,e=Ht;function r(n,i,a){t.call(this,n==null?\"canceled\":n,t.ERR_CANCELED,i,a),this.name=\"CanceledError\"}return e.inherits(r,t,{__CANCEL__:!0}),Xv=r,Xv}var Jv,GE;function D9(){return GE||(GE=1,Jv=function(e){var r=/^([-+\\w]{1,25})(:?\\/\\/|:)/.exec(e);return r&&r[1]||\"\"}),Jv}var Zv,WE;function KE(){if(WE)return Zv;WE=1;var t=Ht,e=_9(),r=w9(),n=fM,i=vM,a=$9(),o=C9(),s=pM,l=Fo,u=Yp(),f=D9(),d=Kp.exports;return Zv=function(h){return new Promise(function(y,P){var C=h.data,R=h.headers,D=h.responseType,B=h.withXSRFToken,A;function V(){h.cancelToken&&h.cancelToken.unsubscribe(A),h.signal&&h.signal.removeEventListener(\"abort\",A)}t.isFormData(C)&&t.isStandardBrowserEnv()&&delete R[\"Content-Type\"];var N=new XMLHttpRequest;if(h.auth){var G=h.auth.username||\"\",H=h.auth.password?unescape(encodeURIComponent(h.auth.password)):\"\";R.Authorization=\"Basic \"+btoa(G+\":\"+H)}var W=i(h.baseURL,h.url);N.open(h.method.toUpperCase(),n(W,h.params,h.paramsSerializer),!0),N.timeout=h.timeout;function j(){if(!!N){var w=\"getAllResponseHeaders\"in N?a(N.getAllResponseHeaders()):null,$=!D||D===\"text\"||D===\"json\"?N.responseText:N.response,M={data:$,status:N.status,statusText:N.statusText,headers:w,config:h,request:N};e(function(X){y(X),V()},function(X){P(X),V()},M),N=null}}if(\"onloadend\"in N?N.onloadend=j:N.onreadystatechange=function(){!N||N.readyState!==4||N.status===0&&!(N.responseURL&&N.responseURL.indexOf(\"file:\")===0)||setTimeout(j)},N.onabort=function(){!N||(P(new l(\"Request aborted\",l.ECONNABORTED,h,N)),N=null)},N.onerror=function(){P(new l(\"Network Error\",l.ERR_NETWORK,h,N)),N=null},N.ontimeout=function(){var $=h.timeout?\"timeout of \"+h.timeout+\"ms exceeded\":\"timeout exceeded\",M=h.transitional||s;h.timeoutErrorMessage&&($=h.timeoutErrorMessage),P(new l($,M.clarifyTimeoutError?l.ETIMEDOUT:l.ECONNABORTED,h,N)),N=null},t.isStandardBrowserEnv()&&(B&&t.isFunction(B)&&(B=B(h)),B||B!==!1&&o(W))){var E=h.xsrfHeaderName&&h.xsrfCookieName&&r.read(h.xsrfCookieName);E&&(R[h.xsrfHeaderName]=E)}\"setRequestHeader\"in N&&t.forEach(R,function($,M){typeof C>\"u\"&&M.toLowerCase()===\"content-type\"?delete R[M]:N.setRequestHeader(M,$)}),t.isUndefined(h.withCredentials)||(N.withCredentials=!!h.withCredentials),D&&D!==\"json\"&&(N.responseType=h.responseType),typeof h.onDownloadProgress==\"function\"&&N.addEventListener(\"progress\",h.onDownloadProgress),typeof h.onUploadProgress==\"function\"&&N.upload&&N.upload.addEventListener(\"progress\",h.onUploadProgress),(h.cancelToken||h.signal)&&(A=function(w){!N||(P(!w||w.type?new u(null,h,N):w),N.abort(),N=null)},h.cancelToken&&h.cancelToken.subscribe(A),h.signal&&(h.signal.aborted?A():h.signal.addEventListener(\"abort\",A))),!C&&C!==!1&&C!==0&&C!==\"\"&&(C=null);var v=f(W);if(v&&d.protocols.indexOf(v)===-1){P(new l(\"Unsupported protocol \"+v+\":\",l.ERR_BAD_REQUEST,h));return}N.send(C)})},Zv}var Ft=Ht,YE=dM,qE=Fo,A9=pM,R9=Wp,x9=g9,XE=Kp.exports,M9=hM,N9={\"Content-Type\":\"application/x-www-form-urlencoded\"};function JE(t,e){!Ft.isUndefined(t)&&Ft.isUndefined(t[\"Content-Type\"])&&(t[\"Content-Type\"]=e)}function I9(){var t;return(typeof XMLHttpRequest<\"u\"||typeof process<\"u\"&&Object.prototype.toString.call(process)===\"[object process]\")&&(t=KE()),t}function B9(t,e,r){if(Ft.isString(t))try{return(e||JSON.parse)(t),Ft.trim(t)}catch(n){if(n.name!==\"SyntaxError\")throw n}return(r||JSON.stringify)(t)}var qp={transitional:A9,adapter:I9(),transformRequest:[function(e,r){YE(r,\"Accept\"),YE(r,\"Content-Type\");var n=r&&r[\"Content-Type\"]||\"\",i=n.indexOf(\"application/json\")>-1,a=Ft.isObject(e);a&&Ft.isHTMLForm(e)&&(e=new FormData(e));var o=Ft.isFormData(e);if(o)return i?JSON.stringify(M9(e)):e;if(Ft.isArrayBuffer(e)||Ft.isBuffer(e)||Ft.isStream(e)||Ft.isFile(e)||Ft.isBlob(e))return e;if(Ft.isArrayBufferView(e))return e.buffer;if(Ft.isURLSearchParams(e))return JE(r,\"application/x-www-form-urlencoded;charset=utf-8\"),e.toString();var s;if(a){if(n.indexOf(\"application/x-www-form-urlencoded\")!==-1)return x9(e,this.formSerializer).toString();if((s=Ft.isFileList(e))||n.indexOf(\"multipart/form-data\")>-1){var l=this.env&&this.env.FormData;return R9(s?{\"files[]\":e}:e,l&&new l,this.formSerializer)}}return a||i?(JE(r,\"application/json\"),B9(e)):e}],transformResponse:[function(e){var r=this.transitional||qp.transitional,n=r&&r.forcedJSONParsing,i=this.responseType===\"json\";if(e&&Ft.isString(e)&&(n&&!this.responseType||i)){var a=r&&r.silentJSONParsing,o=!a&&i;try{return JSON.parse(e)}catch(s){if(o)throw s.name===\"SyntaxError\"?qE.from(s,qE.ERR_BAD_RESPONSE,this,null,this.response):s}}return e}],timeout:0,xsrfCookieName:\"XSRF-TOKEN\",xsrfHeaderName:\"X-XSRF-TOKEN\",maxContentLength:-1,maxBodyLength:-1,env:{FormData:XE.classes.FormData,Blob:XE.classes.Blob},validateStatus:function(e){return e>=200&&e<300},headers:{common:{Accept:\"application/json, text/plain, */*\"}}};Ft.forEach([\"delete\",\"get\",\"head\"],function(e){qp.headers[e]={}});Ft.forEach([\"post\",\"put\",\"patch\"],function(e){qp.headers[e]=Ft.merge(N9)});var My=qp,k9=Ht,L9=My,F9=function(e,r,n,i){var a=this||L9;return k9.forEach(i,function(s){e=s.call(a,e,r,n)}),e},Qv,ZE;function mM(){return ZE||(ZE=1,Qv=function(e){return!!(e&&e.__CANCEL__)}),Qv}var QE=Ht,em=F9,j9=mM(),V9=My,H9=Yp(),e0=dM;function tm(t){if(t.cancelToken&&t.cancelToken.throwIfRequested(),t.signal&&t.signal.aborted)throw new H9}var z9=function(e){tm(e),e.headers=e.headers||{},e.data=em.call(e,e.data,e.headers,null,e.transformRequest),e0(e.headers,\"Accept\"),e0(e.headers,\"Content-Type\"),e.headers=QE.merge(e.headers.common||{},e.headers[e.method]||{},e.headers),QE.forEach([\"delete\",\"get\",\"head\",\"post\",\"put\",\"patch\",\"common\"],function(i){delete e.headers[i]});var r=e.adapter||V9.adapter;return r(e).then(function(i){return tm(e),i.data=em.call(e,i.data,i.headers,i.status,e.transformResponse),i},function(i){return j9(i)||(tm(e),i&&i.response&&(i.response.data=em.call(e,i.response.data,i.response.headers,i.response.status,e.transformResponse))),Promise.reject(i)})},Sr=Ht,gM=function(e,r){r=r||{};var n={};function i(f,d){return Sr.isPlainObject(f)&&Sr.isPlainObject(d)?Sr.merge(f,d):Sr.isEmptyObject(d)?Sr.merge({},f):Sr.isPlainObject(d)?Sr.merge({},d):Sr.isArray(d)?d.slice():d}function a(f){if(Sr.isUndefined(r[f])){if(!Sr.isUndefined(e[f]))return i(void 0,e[f])}else return i(e[f],r[f])}function o(f){if(!Sr.isUndefined(r[f]))return i(void 0,r[f])}function s(f){if(Sr.isUndefined(r[f])){if(!Sr.isUndefined(e[f]))return i(void 0,e[f])}else return i(void 0,r[f])}function l(f){if(f in r)return i(e[f],r[f]);if(f in e)return i(void 0,e[f])}var u={url:o,method:o,data:o,baseURL:s,transformRequest:s,transformResponse:s,paramsSerializer:s,timeout:s,timeoutMessage:s,withCredentials:s,withXSRFToken:s,adapter:s,responseType:s,xsrfCookieName:s,xsrfHeaderName:s,onUploadProgress:s,onDownloadProgress:s,decompress:s,maxContentLength:s,maxBodyLength:s,beforeRedirect:s,transport:s,httpAgent:s,httpsAgent:s,cancelToken:s,socketPath:s,responseEncoding:s,validateStatus:l};return Sr.forEach(Object.keys(e).concat(Object.keys(r)),function(d){var p=u[d]||a,h=p(d);Sr.isUndefined(h)&&p!==l||(n[d]=h)}),n},rm,t0;function bM(){return t0||(t0=1,rm={version:\"0.28.1\"}),rm}var U9=bM().version,ca=Fo,Ny={};[\"object\",\"boolean\",\"number\",\"function\",\"string\",\"symbol\"].forEach(function(t,e){Ny[t]=function(n){return typeof n===t||\"a\"+(e<1?\"n \":\" \")+t}});var r0={};Ny.transitional=function(e,r,n){function i(a,o){return\"[Axios v\"+U9+\"] Transitional option '\"+a+\"'\"+o+(n?\". \"+n:\"\")}return function(a,o,s){if(e===!1)throw new ca(i(o,\" has been removed\"+(r?\" in \"+r:\"\")),ca.ERR_DEPRECATED);return r&&!r0[o]&&(r0[o]=!0,console.warn(i(o,\" has been deprecated since v\"+r+\" and will be removed in the near future\"))),e?e(a,o,s):!0}};function G9(t,e,r){if(typeof t!=\"object\")throw new ca(\"options must be an object\",ca.ERR_BAD_OPTION_VALUE);for(var n=Object.keys(t),i=n.length;i-- >0;){var a=n[i],o=e[a];if(o){var s=t[a],l=s===void 0||o(s,a,t);if(l!==!0)throw new ca(\"option \"+a+\" must be \"+l,ca.ERR_BAD_OPTION_VALUE);continue}if(r!==!0)throw new ca(\"Unknown option \"+a,ca.ERR_BAD_OPTION)}}var W9={assertOptions:G9,validators:Ny},Iy=Ht,K9=fM,n0=u9,i0=z9,Xp=gM,Y9=vM,Bg=W9,ia=Bg.validators;function Us(t){this.defaults=t,this.interceptors={request:new n0,response:new n0}}Us.prototype.request=function(e,r){typeof e==\"string\"?(r=r||{},r.url=e):r=e||{},r=Xp(this.defaults,r),r.method?r.method=r.method.toLowerCase():this.defaults.method?r.method=this.defaults.method.toLowerCase():r.method=\"get\";var n=r.transitional;n!==void 0&&Bg.assertOptions(n,{silentJSONParsing:ia.transitional(ia.boolean),forcedJSONParsing:ia.transitional(ia.boolean),clarifyTimeoutError:ia.transitional(ia.boolean)},!1);var i=r.paramsSerializer;i!==void 0&&Bg.assertOptions(i,{encode:ia.function,serialize:ia.function},!0),Iy.isFunction(i)&&(r.paramsSerializer={serialize:i});var a=[],o=!0;this.interceptors.request.forEach(function(b){typeof b.runWhen==\"function\"&&b.runWhen(r)===!1||(o=o&&b.synchronous,a.unshift(b.fulfilled,b.rejected))});var s=[];this.interceptors.response.forEach(function(b){s.push(b.fulfilled,b.rejected)});var l;if(!o){var u=[i0,void 0];for(Array.prototype.unshift.apply(u,a),u=u.concat(s),l=Promise.resolve(r);u.length;)l=l.then(u.shift(),u.shift());return l}for(var f=r;a.length;){var d=a.shift(),p=a.shift();try{f=d(f)}catch(h){p(h);break}}try{l=i0(f)}catch(h){return Promise.reject(h)}for(;s.length;)l=l.then(s.shift(),s.shift());return l};Us.prototype.getUri=function(e){e=Xp(this.defaults,e);var r=Y9(e.baseURL,e.url);return K9(r,e.params,e.paramsSerializer)};Iy.forEach([\"delete\",\"get\",\"head\",\"options\"],function(e){Us.prototype[e]=function(r,n){return this.request(Xp(n||{},{method:e,url:r,data:(n||{}).data}))}});Iy.forEach([\"post\",\"put\",\"patch\"],function(e){function r(n){return function(a,o,s){return this.request(Xp(s||{},{method:e,headers:n?{\"Content-Type\":\"multipart/form-data\"}:{},url:a,data:o}))}}Us.prototype[e]=r(),Us.prototype[e+\"Form\"]=r(!0)});var q9=Us,nm,a0;function X9(){if(a0)return nm;a0=1;var t=Yp();function e(r){if(typeof r!=\"function\")throw new TypeError(\"executor must be a function.\");var n;this.promise=new Promise(function(o){n=o});var i=this;this.promise.then(function(a){if(!!i._listeners){for(var o=i._listeners.length;o-- >0;)i._listeners[o](a);i._listeners=null}}),this.promise.then=function(a){var o,s=new Promise(function(l){i.subscribe(l),o=l}).then(a);return s.cancel=function(){i.unsubscribe(o)},s},r(function(o,s,l){i.reason||(i.reason=new t(o,s,l),n(i.reason))})}return e.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},e.prototype.subscribe=function(n){if(this.reason){n(this.reason);return}this._listeners?this._listeners.push(n):this._listeners=[n]},e.prototype.unsubscribe=function(n){if(!!this._listeners){var i=this._listeners.indexOf(n);i!==-1&&this._listeners.splice(i,1)}},e.source=function(){var n,i=new e(function(o){n=o});return{token:i,cancel:n}},nm=e,nm}var im,o0;function J9(){return o0||(o0=1,im=function(e){return function(n){return e.apply(null,n)}}),im}var am,s0;function Z9(){if(s0)return am;s0=1;var t=Ht;return am=function(r){return t.isObject(r)&&r.isAxiosError===!0},am}var kg=Ht,Q9=Qx,Mf=q9,eY=gM,tY=My,rY=hM;function yM(t){var e=new Mf(t),r=Q9(Mf.prototype.request,e);return kg.extend(r,Mf.prototype,e),kg.extend(r,e),r.create=function(i){return yM(eY(t,i))},r}var Mr=yM(tY);Mr.Axios=Mf;Mr.CanceledError=Yp();Mr.CancelToken=X9();Mr.isCancel=mM();Mr.VERSION=bM().version;Mr.toFormData=Wp;Mr.AxiosError=Fo;Mr.Cancel=Mr.CanceledError;Mr.all=function(e){return Promise.all(e)};Mr.spread=J9();Mr.isAxiosError=Z9();Mr.formToJSON=function(t){return rY(kg.isHTMLForm(t)?new FormData(t):t)};Cy.exports=Mr;Cy.exports.default=Mr;(function(t){t.exports=Cy.exports})(Zx);const Xi=Jx(Zx.exports);const nY={data(){return{nodeName:\"\",meta:{}}},async mounted(){this.nodeName=this.getCookie(\"cap.node\"),await Xi.get(\"/meta\").then(t=>{this.meta=t.data})},methods:{getCookie(t){for(var e=t+\"=\",r=decodeURIComponent(document.cookie),n=r.split(\";\"),i=0;i<n.length;i++){for(var a=n[i];a.charAt(0)==\" \";)a=a.substring(1);if(a.indexOf(e)==0)return a.substring(e.length,a.length)}return\"\"}},components:{BBadge:jb}};var iY=function(){var n,i,a,o,s;var e=this,r=e._self._c;return r(\"b-navbar\",{attrs:{fixed:\"bottom\",toggleable:\"lg\",type:\"light\",variant:\"light\"}},[r(\"b-container\",{staticClass:\"d-block\"},[r(\"b-row\",{staticClass:\"align-items-start\"},[e.nodeName?r(\"b-col\",[r(\"BBadge\",{attrs:{variant:\"warning\",pill:\"\"}},[e._v(\" \"+e._s(e.$t(\"SwitchedNode\"))+\": \"+e._s(e.nodeName))])],1):e._e(),r(\"b-col\",[r(\"BBadge\",{attrs:{variant:\"secondary\",pill:\"\"}},[e._v(e._s((i=(n=e.meta.cap)==null?void 0:n.name)!=null?i:\"CAP\")+\": \"+e._s((a=e.meta.cap)==null?void 0:a.version.substring(0,5)))])],1),r(\"b-col\",[r(\"BBadge\",{attrs:{variant:\"secondary\",pill:\"\"}},[e._v(\" \"+e._s(e.$t(\"Storage\"))+\": \"+e._s((o=e.meta.storage)==null?void 0:o.name))])],1),r(\"b-col\",[r(\"BBadge\",{attrs:{variant:\"secondary\",pill:\"\"}},[e._v(\" \"+e._s(e.$t(\"Transport\"))+\": \"+e._s((s=e.meta.broker)==null?void 0:s.name))])],1)],1)],1)],1)},aY=[],oY=Up(nY,iY,aY,!1,null,\"3ca8df4b\",null,null);const sY=oY.exports;const lY={name:\"App\",components:{Navigation:SK,Footer:sY},data(){return{timer:\"\"}},methods:{getData(){window.pollingInterval==\"%(pollingInterval)\"&&(window.pollingInterval=2e3),Xi.get(\"/stats\").then(t=>{this.$store.dispatch(\"pollingMertic\",t.data),setTimeout(()=>{this.getData()},window.pollingInterval)})}},mounted(){Xi.interceptors.response.use(t=>(t.status===500&&this.$bvToast.toast(\"request failed\",{title:\"Request Error\",variant:\"danger\",autoHideDelay:1e3,appendToast:!0,solid:!0}),t)),this.getData()},beforeDestroy(){clearInterval(this.timer)}};Date.prototype.format=function(t){var e={\"M+\":this.getMonth()+1,\"d+\":this.getDate(),\"h+\":this.getHours(),\"m+\":this.getMinutes(),\"s+\":this.getSeconds(),\"q+\":Math.floor((this.getMonth()+3)/3),S:this.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(this.getFullYear()+\"\").substr(4-RegExp.$1.length)));for(var r in e)new RegExp(\"(\"+r+\")\").test(t)&&(t=t.replace(RegExp.$1,RegExp.$1.length==1?e[r]:(\"00\"+e[r]).substr((\"\"+e[r]).length)));return t};var uY=function(){var e=this,r=e._self._c;return r(\"div\",{attrs:{id:\"app\"}},[r(\"Navigation\"),r(\"b-container\",{staticClass:\"mt-4\"},[r(\"router-view\")],1),r(\"Footer\")],1)},cY=[],fY=Up(lY,uY,cY,!1,null,null,null,null);const dY=fY.exports,pY=\"modulepreload\",hY=function(t,e){return new URL(t,e).href},l0={},qc=function(e,r,n){if(!r||r.length===0)return e();const i=document.getElementsByTagName(\"link\");return Promise.all(r.map(a=>{if(a=hY(a,n),a in l0)return;l0[a]=!0;const o=a.endsWith(\".css\"),s=o?'[rel=\"stylesheet\"]':\"\";if(!!n)for(let f=i.length-1;f>=0;f--){const d=i[f];if(d.href===a&&(!o||d.rel===\"stylesheet\"))return}else if(document.querySelector(`link[href=\"${a}\"]${s}`))return;const u=document.createElement(\"link\");if(u.rel=o?\"stylesheet\":pY,o||(u.as=\"script\",u.crossOrigin=\"\"),u.href=a,document.head.appendChild(u),o)return new Promise((f,d)=>{u.addEventListener(\"load\",f),u.addEventListener(\"error\",()=>d(new Error(`Unable to preload CSS for ${a}`)))})})).then(()=>e())};/*!\n  * vue-router v3.6.5\n  * (c) 2022 Evan You\n  * @license MIT\n  */function Gn(t,e){for(var r in e)t[r]=e[r];return t}var vY=/[!'()*]/g,mY=function(t){return\"%\"+t.charCodeAt(0).toString(16)},gY=/%2C/g,cs=function(t){return encodeURIComponent(t).replace(vY,mY).replace(gY,\",\")};function Lg(t){try{return decodeURIComponent(t)}catch{}return t}function bY(t,e,r){e===void 0&&(e={});var n=r||yY,i;try{i=n(t||\"\")}catch{i={}}for(var a in e){var o=e[a];i[a]=Array.isArray(o)?o.map(u0):u0(o)}return i}var u0=function(t){return t==null||typeof t==\"object\"?t:String(t)};function yY(t){var e={};return t=t.trim().replace(/^(\\?|#|&)/,\"\"),t&&t.split(\"&\").forEach(function(r){var n=r.replace(/\\+/g,\" \").split(\"=\"),i=Lg(n.shift()),a=n.length>0?Lg(n.join(\"=\")):null;e[i]===void 0?e[i]=a:Array.isArray(e[i])?e[i].push(a):e[i]=[e[i],a]}),e}function OY(t){var e=t?Object.keys(t).map(function(r){var n=t[r];if(n===void 0)return\"\";if(n===null)return cs(r);if(Array.isArray(n)){var i=[];return n.forEach(function(a){a!==void 0&&(a===null?i.push(cs(r)):i.push(cs(r)+\"=\"+cs(a)))}),i.join(\"&\")}return cs(r)+\"=\"+cs(n)}).filter(function(r){return r.length>0}).join(\"&\"):null;return e?\"?\"+e:\"\"}var Bd=/\\/?$/;function kd(t,e,r,n){var i=n&&n.options.stringifyQuery,a=e.query||{};try{a=Fg(a)}catch{}var o={name:e.name||t&&t.name,meta:t&&t.meta||{},path:e.path||\"/\",hash:e.hash||\"\",query:a,params:e.params||{},fullPath:c0(e,i),matched:t?_Y(t):[]};return r&&(o.redirectedFrom=c0(r,i)),Object.freeze(o)}function Fg(t){if(Array.isArray(t))return t.map(Fg);if(t&&typeof t==\"object\"){var e={};for(var r in t)e[r]=Fg(t[r]);return e}else return t}var Fa=kd(null,{path:\"/\"});function _Y(t){for(var e=[];t;)e.unshift(t),t=t.parent;return e}function c0(t,e){var r=t.path,n=t.query;n===void 0&&(n={});var i=t.hash;i===void 0&&(i=\"\");var a=e||OY;return(r||\"/\")+a(n)+i}function OM(t,e,r){return e===Fa?t===e:e?t.path&&e.path?t.path.replace(Bd,\"\")===e.path.replace(Bd,\"\")&&(r||t.hash===e.hash&&Nf(t.query,e.query)):t.name&&e.name?t.name===e.name&&(r||t.hash===e.hash&&Nf(t.query,e.query)&&Nf(t.params,e.params)):!1:!1}function Nf(t,e){if(t===void 0&&(t={}),e===void 0&&(e={}),!t||!e)return t===e;var r=Object.keys(t).sort(),n=Object.keys(e).sort();return r.length!==n.length?!1:r.every(function(i,a){var o=t[i],s=n[a];if(s!==i)return!1;var l=e[i];return o==null||l==null?o===l:typeof o==\"object\"&&typeof l==\"object\"?Nf(o,l):String(o)===String(l)})}function wY(t,e){return t.path.replace(Bd,\"/\").indexOf(e.path.replace(Bd,\"/\"))===0&&(!e.hash||t.hash===e.hash)&&TY(t.query,e.query)}function TY(t,e){for(var r in e)if(!(r in t))return!1;return!0}function _M(t){for(var e=0;e<t.matched.length;e++){var r=t.matched[e];for(var n in r.instances){var i=r.instances[n],a=r.enteredCbs[n];if(!(!i||!a)){delete r.enteredCbs[n];for(var o=0;o<a.length;o++)i._isBeingDestroyed||a[o](i)}}}}var SY={name:\"RouterView\",functional:!0,props:{name:{type:String,default:\"default\"}},render:function(e,r){var n=r.props,i=r.children,a=r.parent,o=r.data;o.routerView=!0;for(var s=a.$createElement,l=n.name,u=a.$route,f=a._routerViewCache||(a._routerViewCache={}),d=0,p=!1;a&&a._routerRoot!==a;){var h=a.$vnode?a.$vnode.data:{};h.routerView&&d++,h.keepAlive&&a._directInactive&&a._inactive&&(p=!0),a=a.$parent}if(o.routerViewDepth=d,p){var b=f[l],y=b&&b.component;return y?(b.configProps&&f0(y,o,b.route,b.configProps),s(y,o,i)):s()}var P=u.matched[d],C=P&&P.components[l];if(!P||!C)return f[l]=null,s();f[l]={component:C},o.registerRouteInstance=function(D,B){var A=P.instances[l];(B&&A!==D||!B&&A===D)&&(P.instances[l]=B)},(o.hook||(o.hook={})).prepatch=function(D,B){P.instances[l]=B.componentInstance},o.hook.init=function(D){D.data.keepAlive&&D.componentInstance&&D.componentInstance!==P.instances[l]&&(P.instances[l]=D.componentInstance),_M(u)};var R=P.props&&P.props[l];return R&&(Gn(f[l],{route:u,configProps:R}),f0(C,o,u,R)),s(C,o,i)}};function f0(t,e,r,n){var i=e.props=PY(r,n);if(i){i=e.props=Gn({},i);var a=e.attrs=e.attrs||{};for(var o in i)(!t.props||!(o in t.props))&&(a[o]=i[o],delete i[o])}}function PY(t,e){switch(typeof e){case\"undefined\":return;case\"object\":return e;case\"function\":return e(t);case\"boolean\":return e?t.params:void 0}}function wM(t,e,r){var n=t.charAt(0);if(n===\"/\")return t;if(n===\"?\"||n===\"#\")return e+t;var i=e.split(\"/\");(!r||!i[i.length-1])&&i.pop();for(var a=t.replace(/^\\//,\"\").split(\"/\"),o=0;o<a.length;o++){var s=a[o];s===\"..\"?i.pop():s!==\".\"&&i.push(s)}return i[0]!==\"\"&&i.unshift(\"\"),i.join(\"/\")}function EY(t){var e=\"\",r=\"\",n=t.indexOf(\"#\");n>=0&&(e=t.slice(n),t=t.slice(0,n));var i=t.indexOf(\"?\");return i>=0&&(r=t.slice(i+1),t=t.slice(0,i)),{path:t,query:r,hash:e}}function _a(t){return t.replace(/\\/(?:\\s*\\/)+/g,\"/\")}var Ld=Array.isArray||function(t){return Object.prototype.toString.call(t)==\"[object Array]\"},nl=PM,$Y=By,CY=xY,DY=TM,AY=SM,RY=new RegExp([\"(\\\\\\\\.)\",\"([\\\\/.])?(?:(?:\\\\:(\\\\w+)(?:\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))?|\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))([+*?])?|(\\\\*))\"].join(\"|\"),\"g\");function By(t,e){for(var r=[],n=0,i=0,a=\"\",o=e&&e.delimiter||\"/\",s;(s=RY.exec(t))!=null;){var l=s[0],u=s[1],f=s.index;if(a+=t.slice(i,f),i=f+l.length,u){a+=u[1];continue}var d=t[i],p=s[2],h=s[3],b=s[4],y=s[5],P=s[6],C=s[7];a&&(r.push(a),a=\"\");var R=p!=null&&d!=null&&d!==p,D=P===\"+\"||P===\"*\",B=P===\"?\"||P===\"*\",A=s[2]||o,V=b||y;r.push({name:h||n++,prefix:p||\"\",delimiter:A,optional:B,repeat:D,partial:R,asterisk:!!C,pattern:V?IY(V):C?\".*\":\"[^\"+If(A)+\"]+?\"})}return i<t.length&&(a+=t.substr(i)),a&&r.push(a),r}function xY(t,e){return TM(By(t,e),e)}function MY(t){return encodeURI(t).replace(/[\\/?#]/g,function(e){return\"%\"+e.charCodeAt(0).toString(16).toUpperCase()})}function NY(t){return encodeURI(t).replace(/[?#]/g,function(e){return\"%\"+e.charCodeAt(0).toString(16).toUpperCase()})}function TM(t,e){for(var r=new Array(t.length),n=0;n<t.length;n++)typeof t[n]==\"object\"&&(r[n]=new RegExp(\"^(?:\"+t[n].pattern+\")$\",Ly(e)));return function(i,a){for(var o=\"\",s=i||{},l=a||{},u=l.pretty?MY:encodeURIComponent,f=0;f<t.length;f++){var d=t[f];if(typeof d==\"string\"){o+=d;continue}var p=s[d.name],h;if(p==null)if(d.optional){d.partial&&(o+=d.prefix);continue}else throw new TypeError('Expected \"'+d.name+'\" to be defined');if(Ld(p)){if(!d.repeat)throw new TypeError('Expected \"'+d.name+'\" to not repeat, but received `'+JSON.stringify(p)+\"`\");if(p.length===0){if(d.optional)continue;throw new TypeError('Expected \"'+d.name+'\" to not be empty')}for(var b=0;b<p.length;b++){if(h=u(p[b]),!r[f].test(h))throw new TypeError('Expected all \"'+d.name+'\" to match \"'+d.pattern+'\", but received `'+JSON.stringify(h)+\"`\");o+=(b===0?d.prefix:d.delimiter)+h}continue}if(h=d.asterisk?NY(p):u(p),!r[f].test(h))throw new TypeError('Expected \"'+d.name+'\" to match \"'+d.pattern+'\", but received \"'+h+'\"');o+=d.prefix+h}return o}}function If(t){return t.replace(/([.+*?=^!:${}()[\\]|\\/\\\\])/g,\"\\\\$1\")}function IY(t){return t.replace(/([=!:$\\/()])/g,\"\\\\$1\")}function ky(t,e){return t.keys=e,t}function Ly(t){return t&&t.sensitive?\"\":\"i\"}function BY(t,e){var r=t.source.match(/\\((?!\\?)/g);if(r)for(var n=0;n<r.length;n++)e.push({name:n,prefix:null,delimiter:null,optional:!1,repeat:!1,partial:!1,asterisk:!1,pattern:null});return ky(t,e)}function kY(t,e,r){for(var n=[],i=0;i<t.length;i++)n.push(PM(t[i],e,r).source);var a=new RegExp(\"(?:\"+n.join(\"|\")+\")\",Ly(r));return ky(a,e)}function LY(t,e,r){return SM(By(t,r),e,r)}function SM(t,e,r){Ld(e)||(r=e||r,e=[]),r=r||{};for(var n=r.strict,i=r.end!==!1,a=\"\",o=0;o<t.length;o++){var s=t[o];if(typeof s==\"string\")a+=If(s);else{var l=If(s.prefix),u=\"(?:\"+s.pattern+\")\";e.push(s),s.repeat&&(u+=\"(?:\"+l+u+\")*\"),s.optional?s.partial?u=l+\"(\"+u+\")?\":u=\"(?:\"+l+\"(\"+u+\"))?\":u=l+\"(\"+u+\")\",a+=u}}var f=If(r.delimiter||\"/\"),d=a.slice(-f.length)===f;return n||(a=(d?a.slice(0,-f.length):a)+\"(?:\"+f+\"(?=$))?\"),i?a+=\"$\":a+=n&&d?\"\":\"(?=\"+f+\"|$)\",ky(new RegExp(\"^\"+a,Ly(r)),e)}function PM(t,e,r){return Ld(e)||(r=e||r,e=[]),r=r||{},t instanceof RegExp?BY(t,e):Ld(t)?kY(t,e,r):LY(t,e,r)}nl.parse=$Y;nl.compile=CY;nl.tokensToFunction=DY;nl.tokensToRegExp=AY;var d0=Object.create(null);function Bf(t,e,r){e=e||{};try{var n=d0[t]||(d0[t]=nl.compile(t));return typeof e.pathMatch==\"string\"&&(e[0]=e.pathMatch),n(e,{pretty:!0})}catch{return\"\"}finally{delete e[0]}}function Fy(t,e,r,n){var i=typeof t==\"string\"?{path:t}:t;if(i._normalized)return i;if(i.name){i=Gn({},t);var a=i.params;return a&&typeof a==\"object\"&&(i.params=Gn({},a)),i}if(!i.path&&i.params&&e){i=Gn({},i),i._normalized=!0;var o=Gn(Gn({},e.params),i.params);if(e.name)i.name=e.name,i.params=o;else if(e.matched.length){var s=e.matched[e.matched.length-1].path;i.path=Bf(s,o,\"path \"+e.path)}return i}var l=EY(i.path||\"\"),u=e&&e.path||\"/\",f=l.path?wM(l.path,u,r||i.append):u,d=bY(l.query,i.query,n&&n.options.parseQuery),p=i.hash||l.hash;return p&&p.charAt(0)!==\"#\"&&(p=\"#\"+p),{_normalized:!0,path:f,query:d,hash:p}}var FY=[String,Object],jY=[String,Array],p0=function(){},VY={name:\"RouterLink\",props:{to:{type:FY,required:!0},tag:{type:String,default:\"a\"},custom:Boolean,exact:Boolean,exactPath:Boolean,append:Boolean,replace:Boolean,activeClass:String,exactActiveClass:String,ariaCurrentValue:{type:String,default:\"page\"},event:{type:jY,default:\"click\"}},render:function(e){var r=this,n=this.$router,i=this.$route,a=n.resolve(this.to,i,this.append),o=a.location,s=a.route,l=a.href,u={},f=n.options.linkActiveClass,d=n.options.linkExactActiveClass,p=f==null?\"router-link-active\":f,h=d==null?\"router-link-exact-active\":d,b=this.activeClass==null?p:this.activeClass,y=this.exactActiveClass==null?h:this.exactActiveClass,P=s.redirectedFrom?kd(null,Fy(s.redirectedFrom),null,n):s;u[y]=OM(i,P,this.exactPath),u[b]=this.exact||this.exactPath?u[y]:wY(i,P);var C=u[y]?this.ariaCurrentValue:null,R=function(E){h0(E)&&(r.replace?n.replace(o,p0):n.push(o,p0))},D={click:h0};Array.isArray(this.event)?this.event.forEach(function(E){D[E]=R}):D[this.event]=R;var B={class:u},A=!this.$scopedSlots.$hasNormal&&this.$scopedSlots.default&&this.$scopedSlots.default({href:l,route:s,navigate:R,isActive:u[b],isExactActive:u[y]});if(A){if(A.length===1)return A[0];if(A.length>1||!A.length)return A.length===0?e():e(\"span\",{},A)}if(this.tag===\"a\")B.on=D,B.attrs={href:l,\"aria-current\":C};else{var V=EM(this.$slots.default);if(V){V.isStatic=!1;var N=V.data=Gn({},V.data);N.on=N.on||{};for(var G in N.on){var H=N.on[G];G in D&&(N.on[G]=Array.isArray(H)?H:[H])}for(var W in D)W in N.on?N.on[W].push(D[W]):N.on[W]=R;var j=V.data.attrs=Gn({},V.data.attrs);j.href=l,j[\"aria-current\"]=C}else B.on=D}return e(this.tag,B,this.$slots.default)}};function h0(t){if(!(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)&&!t.defaultPrevented&&!(t.button!==void 0&&t.button!==0)){if(t.currentTarget&&t.currentTarget.getAttribute){var e=t.currentTarget.getAttribute(\"target\");if(/\\b_blank\\b/i.test(e))return}return t.preventDefault&&t.preventDefault(),!0}}function EM(t){if(t){for(var e,r=0;r<t.length;r++)if(e=t[r],e.tag===\"a\"||e.children&&(e=EM(e.children)))return e}}var Fd;function jg(t){if(!(jg.installed&&Fd===t)){jg.installed=!0,Fd=t;var e=function(i){return i!==void 0},r=function(i,a){var o=i.$options._parentVnode;e(o)&&e(o=o.data)&&e(o=o.registerRouteInstance)&&o(i,a)};t.mixin({beforeCreate:function(){e(this.$options.router)?(this._routerRoot=this,this._router=this.$options.router,this._router.init(this),t.util.defineReactive(this,\"_route\",this._router.history.current)):this._routerRoot=this.$parent&&this.$parent._routerRoot||this,r(this,this)},destroyed:function(){r(this)}}),Object.defineProperty(t.prototype,\"$router\",{get:function(){return this._routerRoot._router}}),Object.defineProperty(t.prototype,\"$route\",{get:function(){return this._routerRoot._route}}),t.component(\"RouterView\",SY),t.component(\"RouterLink\",VY);var n=t.config.optionMergeStrategies;n.beforeRouteEnter=n.beforeRouteLeave=n.beforeRouteUpdate=n.created}}var nc=typeof window<\"u\";function Xc(t,e,r,n,i){var a=e||[],o=r||Object.create(null),s=n||Object.create(null);t.forEach(function(f){Vg(a,o,s,f,i)});for(var l=0,u=a.length;l<u;l++)a[l]===\"*\"&&(a.push(a.splice(l,1)[0]),u--,l--);return{pathList:a,pathMap:o,nameMap:s}}function Vg(t,e,r,n,i,a){var o=n.path,s=n.name,l=n.pathToRegexpOptions||{},u=zY(o,i,l.strict);typeof n.caseSensitive==\"boolean\"&&(l.sensitive=n.caseSensitive);var f={path:u,regex:HY(u,l),components:n.components||{default:n.component},alias:n.alias?typeof n.alias==\"string\"?[n.alias]:n.alias:[],instances:{},enteredCbs:{},name:s,parent:i,matchAs:a,redirect:n.redirect,beforeEnter:n.beforeEnter,meta:n.meta||{},props:n.props==null?{}:n.components?n.props:{default:n.props}};if(n.children&&n.children.forEach(function(y){var P=a?_a(a+\"/\"+y.path):void 0;Vg(t,e,r,y,f,P)}),e[f.path]||(t.push(f.path),e[f.path]=f),n.alias!==void 0)for(var d=Array.isArray(n.alias)?n.alias:[n.alias],p=0;p<d.length;++p){var h=d[p],b={path:h,children:n.children};Vg(t,e,r,b,i,f.path||\"/\")}s&&(r[s]||(r[s]=f))}function HY(t,e){var r=nl(t,[],e);return r}function zY(t,e,r){return r||(t=t.replace(/\\/$/,\"\")),t[0]===\"/\"||e==null?t:_a(e.path+\"/\"+t)}function UY(t,e){var r=Xc(t),n=r.pathList,i=r.pathMap,a=r.nameMap;function o(h){Xc(h,n,i,a)}function s(h,b){var y=typeof h!=\"object\"?a[h]:void 0;Xc([b||h],n,i,a,y),y&&y.alias.length&&Xc(y.alias.map(function(P){return{path:P,children:[b]}}),n,i,a,y)}function l(){return n.map(function(h){return i[h]})}function u(h,b,y){var P=Fy(h,b,!1,e),C=P.name;if(C){var R=a[C];if(!R)return p(null,P);var D=R.regex.keys.filter(function(G){return!G.optional}).map(function(G){return G.name});if(typeof P.params!=\"object\"&&(P.params={}),b&&typeof b.params==\"object\")for(var B in b.params)!(B in P.params)&&D.indexOf(B)>-1&&(P.params[B]=b.params[B]);return P.path=Bf(R.path,P.params),p(R,P,y)}else if(P.path){P.params={};for(var A=0;A<n.length;A++){var V=n[A],N=i[V];if(GY(N.regex,P.path,P.params))return p(N,P,y)}}return p(null,P)}function f(h,b){var y=h.redirect,P=typeof y==\"function\"?y(kd(h,b,null,e)):y;if(typeof P==\"string\"&&(P={path:P}),!P||typeof P!=\"object\")return p(null,b);var C=P,R=C.name,D=C.path,B=b.query,A=b.hash,V=b.params;if(B=C.hasOwnProperty(\"query\")?C.query:B,A=C.hasOwnProperty(\"hash\")?C.hash:A,V=C.hasOwnProperty(\"params\")?C.params:V,R)return a[R],u({_normalized:!0,name:R,query:B,hash:A,params:V},void 0,b);if(D){var N=WY(D,h),G=Bf(N,V);return u({_normalized:!0,path:G,query:B,hash:A},void 0,b)}else return p(null,b)}function d(h,b,y){var P=Bf(y,b.params),C=u({_normalized:!0,path:P});if(C){var R=C.matched,D=R[R.length-1];return b.params=C.params,p(D,b)}return p(null,b)}function p(h,b,y){return h&&h.redirect?f(h,y||b):h&&h.matchAs?d(h,b,h.matchAs):kd(h,b,y,e)}return{match:u,addRoute:s,getRoutes:l,addRoutes:o}}function GY(t,e,r){var n=e.match(t);if(n){if(!r)return!0}else return!1;for(var i=1,a=n.length;i<a;++i){var o=t.keys[i-1];o&&(r[o.name||\"pathMatch\"]=typeof n[i]==\"string\"?Lg(n[i]):n[i])}return!0}function WY(t,e){return wM(t,e.parent?e.parent.path:\"/\",!0)}var KY=nc&&window.performance&&window.performance.now?window.performance:Date;function $M(){return KY.now().toFixed(3)}var CM=$M();function Jp(){return CM}function DM(t){return CM=t}var AM=Object.create(null);function RM(){\"scrollRestoration\"in window.history&&(window.history.scrollRestoration=\"manual\");var t=window.location.protocol+\"//\"+window.location.host,e=window.location.href.replace(t,\"\"),r=Gn({},window.history.state);return r.key=Jp(),window.history.replaceState(r,\"\",e),window.addEventListener(\"popstate\",v0),function(){window.removeEventListener(\"popstate\",v0)}}function wa(t,e,r,n){if(!!t.app){var i=t.options.scrollBehavior;!i||t.app.$nextTick(function(){var a=YY(),o=i.call(t,e,r,n?a:null);!o||(typeof o.then==\"function\"?o.then(function(s){b0(s,a)}).catch(function(s){}):b0(o,a))})}}function xM(){var t=Jp();t&&(AM[t]={x:window.pageXOffset,y:window.pageYOffset})}function v0(t){xM(),t.state&&t.state.key&&DM(t.state.key)}function YY(){var t=Jp();if(t)return AM[t]}function qY(t,e){var r=document.documentElement,n=r.getBoundingClientRect(),i=t.getBoundingClientRect();return{x:i.left-n.left-e.x,y:i.top-n.top-e.y}}function m0(t){return Gs(t.x)||Gs(t.y)}function g0(t){return{x:Gs(t.x)?t.x:window.pageXOffset,y:Gs(t.y)?t.y:window.pageYOffset}}function XY(t){return{x:Gs(t.x)?t.x:0,y:Gs(t.y)?t.y:0}}function Gs(t){return typeof t==\"number\"}var JY=/^#\\d/;function b0(t,e){var r=typeof t==\"object\";if(r&&typeof t.selector==\"string\"){var n=JY.test(t.selector)?document.getElementById(t.selector.slice(1)):document.querySelector(t.selector);if(n){var i=t.offset&&typeof t.offset==\"object\"?t.offset:{};i=XY(i),e=qY(n,i)}else m0(t)&&(e=g0(t))}else r&&m0(t)&&(e=g0(t));e&&(\"scrollBehavior\"in document.documentElement.style?window.scrollTo({left:e.x,top:e.y,behavior:t.behavior}):window.scrollTo(e.x,e.y))}var Ta=nc&&function(){var t=window.navigator.userAgent;return(t.indexOf(\"Android 2.\")!==-1||t.indexOf(\"Android 4.0\")!==-1)&&t.indexOf(\"Mobile Safari\")!==-1&&t.indexOf(\"Chrome\")===-1&&t.indexOf(\"Windows Phone\")===-1?!1:window.history&&typeof window.history.pushState==\"function\"}();function jd(t,e){xM();var r=window.history;try{if(e){var n=Gn({},r.state);n.key=Jp(),r.replaceState(n,\"\",t)}else r.pushState({key:DM($M())},\"\",t)}catch{window.location[e?\"replace\":\"assign\"](t)}}function Hg(t){jd(t,!0)}var jo={redirected:2,aborted:4,cancelled:8,duplicated:16};function ZY(t,e){return Zp(t,e,jo.redirected,'Redirected when going from \"'+t.fullPath+'\" to \"'+rq(e)+'\" via a navigation guard.')}function QY(t,e){var r=Zp(t,e,jo.duplicated,'Avoided redundant navigation to current location: \"'+t.fullPath+'\".');return r.name=\"NavigationDuplicated\",r}function y0(t,e){return Zp(t,e,jo.cancelled,'Navigation cancelled from \"'+t.fullPath+'\" to \"'+e.fullPath+'\" with a new navigation.')}function eq(t,e){return Zp(t,e,jo.aborted,'Navigation aborted from \"'+t.fullPath+'\" to \"'+e.fullPath+'\" via a navigation guard.')}function Zp(t,e,r,n){var i=new Error(n);return i._isRouter=!0,i.from=t,i.to=e,i.type=r,i}var tq=[\"params\",\"query\",\"hash\"];function rq(t){if(typeof t==\"string\")return t;if(\"path\"in t)return t.path;var e={};return tq.forEach(function(r){r in t&&(e[r]=t[r])}),JSON.stringify(e,null,2)}function Vd(t){return Object.prototype.toString.call(t).indexOf(\"Error\")>-1}function Qp(t,e){return Vd(t)&&t._isRouter&&(e==null||t.type===e)}function O0(t,e,r){var n=function(i){i>=t.length?r():t[i]?e(t[i],function(){n(i+1)}):n(i+1)};n(0)}function nq(t){return function(e,r,n){var i=!1,a=0,o=null;MM(t,function(s,l,u,f){if(typeof s==\"function\"&&s.cid===void 0){i=!0,a++;var d=_0(function(y){aq(y)&&(y=y.default),s.resolved=typeof y==\"function\"?y:Fd.extend(y),u.components[f]=y,a--,a<=0&&n()}),p=_0(function(y){var P=\"Failed to resolve async component \"+f+\": \"+y;o||(o=Vd(y)?y:new Error(P),n(o))}),h;try{h=s(d,p)}catch(y){p(y)}if(h)if(typeof h.then==\"function\")h.then(d,p);else{var b=h.component;b&&typeof b.then==\"function\"&&b.then(d,p)}}}),i||n()}}function MM(t,e){return NM(t.map(function(r){return Object.keys(r.components).map(function(n){return e(r.components[n],r.instances[n],r,n)})}))}function NM(t){return Array.prototype.concat.apply([],t)}var iq=typeof Symbol==\"function\"&&typeof Symbol.toStringTag==\"symbol\";function aq(t){return t.__esModule||iq&&t[Symbol.toStringTag]===\"Module\"}function _0(t){var e=!1;return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];if(!e)return e=!0,t.apply(this,r)}}var ii=function(e,r){this.router=e,this.base=oq(r),this.current=Fa,this.pending=null,this.ready=!1,this.readyCbs=[],this.readyErrorCbs=[],this.errorCbs=[],this.listeners=[]};ii.prototype.listen=function(e){this.cb=e};ii.prototype.onReady=function(e,r){this.ready?e():(this.readyCbs.push(e),r&&this.readyErrorCbs.push(r))};ii.prototype.onError=function(e){this.errorCbs.push(e)};ii.prototype.transitionTo=function(e,r,n){var i=this,a;try{a=this.router.match(e,this.current)}catch(s){throw this.errorCbs.forEach(function(l){l(s)}),s}var o=this.current;this.confirmTransition(a,function(){i.updateRoute(a),r&&r(a),i.ensureURL(),i.router.afterHooks.forEach(function(s){s&&s(a,o)}),i.ready||(i.ready=!0,i.readyCbs.forEach(function(s){s(a)}))},function(s){n&&n(s),s&&!i.ready&&(!Qp(s,jo.redirected)||o!==Fa)&&(i.ready=!0,i.readyErrorCbs.forEach(function(l){l(s)}))})};ii.prototype.confirmTransition=function(e,r,n){var i=this,a=this.current;this.pending=e;var o=function(y){!Qp(y)&&Vd(y)&&(i.errorCbs.length?i.errorCbs.forEach(function(P){P(y)}):console.error(y)),n&&n(y)},s=e.matched.length-1,l=a.matched.length-1;if(OM(e,a)&&s===l&&e.matched[s]===a.matched[l])return this.ensureURL(),e.hash&&wa(this.router,a,e,!1),o(QY(a,e));var u=sq(this.current.matched,e.matched),f=u.updated,d=u.deactivated,p=u.activated,h=[].concat(uq(d),this.router.beforeHooks,cq(f),p.map(function(y){return y.beforeEnter}),nq(p)),b=function(y,P){if(i.pending!==e)return o(y0(a,e));try{y(e,a,function(C){C===!1?(i.ensureURL(!0),o(eq(a,e))):Vd(C)?(i.ensureURL(!0),o(C)):typeof C==\"string\"||typeof C==\"object\"&&(typeof C.path==\"string\"||typeof C.name==\"string\")?(o(ZY(a,e)),typeof C==\"object\"&&C.replace?i.replace(C):i.push(C)):P(C)})}catch(C){o(C)}};O0(h,b,function(){var y=fq(p),P=y.concat(i.router.resolveHooks);O0(P,b,function(){if(i.pending!==e)return o(y0(a,e));i.pending=null,r(e),i.router.app&&i.router.app.$nextTick(function(){_M(e)})})})};ii.prototype.updateRoute=function(e){this.current=e,this.cb&&this.cb(e)};ii.prototype.setupListeners=function(){};ii.prototype.teardown=function(){this.listeners.forEach(function(e){e()}),this.listeners=[],this.current=Fa,this.pending=null};function oq(t){if(!t)if(nc){var e=document.querySelector(\"base\");t=e&&e.getAttribute(\"href\")||\"/\",t=t.replace(/^https?:\\/\\/[^\\/]+/,\"\")}else t=\"/\";return t.charAt(0)!==\"/\"&&(t=\"/\"+t),t.replace(/\\/$/,\"\")}function sq(t,e){var r,n=Math.max(t.length,e.length);for(r=0;r<n&&t[r]===e[r];r++);return{updated:e.slice(0,r),activated:e.slice(r),deactivated:t.slice(r)}}function jy(t,e,r,n){var i=MM(t,function(a,o,s,l){var u=lq(a,e);if(u)return Array.isArray(u)?u.map(function(f){return r(f,o,s,l)}):r(u,o,s,l)});return NM(n?i.reverse():i)}function lq(t,e){return typeof t!=\"function\"&&(t=Fd.extend(t)),t.options[e]}function uq(t){return jy(t,\"beforeRouteLeave\",IM,!0)}function cq(t){return jy(t,\"beforeRouteUpdate\",IM)}function IM(t,e){if(e)return function(){return t.apply(e,arguments)}}function fq(t){return jy(t,\"beforeRouteEnter\",function(e,r,n,i){return dq(e,n,i)})}function dq(t,e,r){return function(i,a,o){return t(i,a,function(s){typeof s==\"function\"&&(e.enteredCbs[r]||(e.enteredCbs[r]=[]),e.enteredCbs[r].push(s)),o(s)})}}var BM=function(t){function e(r,n){t.call(this,r,n),this._startLocation=au(this.base)}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.setupListeners=function(){var n=this;if(!(this.listeners.length>0)){var i=this.router,a=i.options.scrollBehavior,o=Ta&&a;o&&this.listeners.push(RM());var s=function(){var l=n.current,u=au(n.base);n.current===Fa&&u===n._startLocation||n.transitionTo(u,function(f){o&&wa(i,f,l,!0)})};window.addEventListener(\"popstate\",s),this.listeners.push(function(){window.removeEventListener(\"popstate\",s)})}},e.prototype.go=function(n){window.history.go(n)},e.prototype.push=function(n,i,a){var o=this,s=this,l=s.current;this.transitionTo(n,function(u){jd(_a(o.base+u.fullPath)),wa(o.router,u,l,!1),i&&i(u)},a)},e.prototype.replace=function(n,i,a){var o=this,s=this,l=s.current;this.transitionTo(n,function(u){Hg(_a(o.base+u.fullPath)),wa(o.router,u,l,!1),i&&i(u)},a)},e.prototype.ensureURL=function(n){if(au(this.base)!==this.current.fullPath){var i=_a(this.base+this.current.fullPath);n?jd(i):Hg(i)}},e.prototype.getCurrentLocation=function(){return au(this.base)},e}(ii);function au(t){var e=window.location.pathname,r=e.toLowerCase(),n=t.toLowerCase();return t&&(r===n||r.indexOf(_a(n+\"/\"))===0)&&(e=e.slice(t.length)),(e||\"/\")+window.location.search+window.location.hash}var kM=function(t){function e(r,n,i){t.call(this,r,n),!(i&&pq(this.base))&&w0()}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.setupListeners=function(){var n=this;if(!(this.listeners.length>0)){var i=this.router,a=i.options.scrollBehavior,o=Ta&&a;o&&this.listeners.push(RM());var s=function(){var u=n.current;!w0()||n.transitionTo(kf(),function(f){o&&wa(n.router,f,u,!0),Ta||Lf(f.fullPath)})},l=Ta?\"popstate\":\"hashchange\";window.addEventListener(l,s),this.listeners.push(function(){window.removeEventListener(l,s)})}},e.prototype.push=function(n,i,a){var o=this,s=this,l=s.current;this.transitionTo(n,function(u){T0(u.fullPath),wa(o.router,u,l,!1),i&&i(u)},a)},e.prototype.replace=function(n,i,a){var o=this,s=this,l=s.current;this.transitionTo(n,function(u){Lf(u.fullPath),wa(o.router,u,l,!1),i&&i(u)},a)},e.prototype.go=function(n){window.history.go(n)},e.prototype.ensureURL=function(n){var i=this.current.fullPath;kf()!==i&&(n?T0(i):Lf(i))},e.prototype.getCurrentLocation=function(){return kf()},e}(ii);function pq(t){var e=au(t);if(!/^\\/#/.test(e))return window.location.replace(_a(t+\"/#\"+e)),!0}function w0(){var t=kf();return t.charAt(0)===\"/\"?!0:(Lf(\"/\"+t),!1)}function kf(){var t=window.location.href,e=t.indexOf(\"#\");return e<0?\"\":(t=t.slice(e+1),t)}function zg(t){var e=window.location.href,r=e.indexOf(\"#\"),n=r>=0?e.slice(0,r):e;return n+\"#\"+t}function T0(t){Ta?jd(zg(t)):window.location.hash=t}function Lf(t){Ta?Hg(zg(t)):window.location.replace(zg(t))}var hq=function(t){function e(r,n){t.call(this,r,n),this.stack=[],this.index=-1}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.push=function(n,i,a){var o=this;this.transitionTo(n,function(s){o.stack=o.stack.slice(0,o.index+1).concat(s),o.index++,i&&i(s)},a)},e.prototype.replace=function(n,i,a){var o=this;this.transitionTo(n,function(s){o.stack=o.stack.slice(0,o.index).concat(s),i&&i(s)},a)},e.prototype.go=function(n){var i=this,a=this.index+n;if(!(a<0||a>=this.stack.length)){var o=this.stack[a];this.confirmTransition(o,function(){var s=i.current;i.index=a,i.updateRoute(o),i.router.afterHooks.forEach(function(l){l&&l(o,s)})},function(s){Qp(s,jo.duplicated)&&(i.index=a)})}},e.prototype.getCurrentLocation=function(){var n=this.stack[this.stack.length-1];return n?n.fullPath:\"/\"},e.prototype.ensureURL=function(){},e}(ii),ht=function(e){e===void 0&&(e={}),this.app=null,this.apps=[],this.options=e,this.beforeHooks=[],this.resolveHooks=[],this.afterHooks=[],this.matcher=UY(e.routes||[],this);var r=e.mode||\"hash\";switch(this.fallback=r===\"history\"&&!Ta&&e.fallback!==!1,this.fallback&&(r=\"hash\"),nc||(r=\"abstract\"),this.mode=r,r){case\"history\":this.history=new BM(this,e.base);break;case\"hash\":this.history=new kM(this,e.base,this.fallback);break;case\"abstract\":this.history=new hq(this,e.base);break}},LM={currentRoute:{configurable:!0}};ht.prototype.match=function(e,r,n){return this.matcher.match(e,r,n)};LM.currentRoute.get=function(){return this.history&&this.history.current};ht.prototype.init=function(e){var r=this;if(this.apps.push(e),e.$once(\"hook:destroyed\",function(){var o=r.apps.indexOf(e);o>-1&&r.apps.splice(o,1),r.app===e&&(r.app=r.apps[0]||null),r.app||r.history.teardown()}),!this.app){this.app=e;var n=this.history;if(n instanceof BM||n instanceof kM){var i=function(o){var s=n.current,l=r.options.scrollBehavior,u=Ta&&l;u&&\"fullPath\"in o&&wa(r,o,s,!1)},a=function(o){n.setupListeners(),i(o)};n.transitionTo(n.getCurrentLocation(),a,a)}n.listen(function(o){r.apps.forEach(function(s){s._route=o})})}};ht.prototype.beforeEach=function(e){return Vy(this.beforeHooks,e)};ht.prototype.beforeResolve=function(e){return Vy(this.resolveHooks,e)};ht.prototype.afterEach=function(e){return Vy(this.afterHooks,e)};ht.prototype.onReady=function(e,r){this.history.onReady(e,r)};ht.prototype.onError=function(e){this.history.onError(e)};ht.prototype.push=function(e,r,n){var i=this;if(!r&&!n&&typeof Promise<\"u\")return new Promise(function(a,o){i.history.push(e,a,o)});this.history.push(e,r,n)};ht.prototype.replace=function(e,r,n){var i=this;if(!r&&!n&&typeof Promise<\"u\")return new Promise(function(a,o){i.history.replace(e,a,o)});this.history.replace(e,r,n)};ht.prototype.go=function(e){this.history.go(e)};ht.prototype.back=function(){this.go(-1)};ht.prototype.forward=function(){this.go(1)};ht.prototype.getMatchedComponents=function(e){var r=e?e.matched?e:this.resolve(e).route:this.currentRoute;return r?[].concat.apply([],r.matched.map(function(n){return Object.keys(n.components).map(function(i){return n.components[i]})})):[]};ht.prototype.resolve=function(e,r,n){r=r||this.history.current;var i=Fy(e,r,n,this),a=this.match(i,r),o=a.redirectedFrom||a.fullPath,s=this.history.base,l=vq(s,o,this.mode);return{location:i,route:a,href:l,normalizedTo:i,resolved:a}};ht.prototype.getRoutes=function(){return this.matcher.getRoutes()};ht.prototype.addRoute=function(e,r){this.matcher.addRoute(e,r),this.history.current!==Fa&&this.history.transitionTo(this.history.getCurrentLocation())};ht.prototype.addRoutes=function(e){this.matcher.addRoutes(e),this.history.current!==Fa&&this.history.transitionTo(this.history.getCurrentLocation())};Object.defineProperties(ht.prototype,LM);var FM=ht;function Vy(t,e){return t.push(e),function(){var r=t.indexOf(e);r>-1&&t.splice(r,1)}}function vq(t,e,r){var n=r===\"hash\"?\"#\"+e:e;return t?_a(t+\"/\"+n):n}ht.install=jg;ht.version=\"3.6.5\";ht.isNavigationFailure=Qp;ht.NavigationFailureType=jo;ht.START_LOCATION=Fa;nc&&window.Vue&&window.Vue.use(ht);const mq=!0,Lt=\"u-\",gq=\"uplot\",bq=Lt+\"hz\",yq=Lt+\"vt\",Oq=Lt+\"title\",_q=Lt+\"wrap\",wq=Lt+\"under\",Tq=Lt+\"over\",Sq=Lt+\"axis\",oo=Lt+\"off\",Pq=Lt+\"select\",Eq=Lt+\"cursor-x\",$q=Lt+\"cursor-y\",Cq=Lt+\"cursor-pt\",Dq=Lt+\"legend\",Aq=Lt+\"live\",Rq=Lt+\"inline\",xq=Lt+\"thead\",Mq=Lt+\"series\",Nq=Lt+\"marker\",S0=Lt+\"label\",Iq=Lt+\"value\",ou=\"width\",su=\"height\",Ul=\"top\",P0=\"bottom\",fs=\"left\",om=\"right\",Hy=\"#000\",E0=Hy+\"0\",$0=\"mousemove\",C0=\"mousedown\",sm=\"mouseup\",D0=\"mouseenter\",A0=\"mouseleave\",R0=\"dblclick\",Bq=\"resize\",kq=\"scroll\",x0=\"change\",Hd=\"dppxchange\",il=typeof window<\"u\",Ug=il?document:null,Rs=il?window:null,Lq=il?navigator:null;let ze,Jc;function Gg(){let t=devicePixelRatio;ze!=t&&(ze=t,Jc&&Kg(x0,Jc,Gg),Jc=matchMedia(`(min-resolution: ${ze-.001}dppx) and (max-resolution: ${ze+.001}dppx)`),mo(x0,Jc,Gg),Rs.dispatchEvent(new CustomEvent(Hd)))}function cn(t,e){if(e!=null){let r=t.classList;!r.contains(e)&&r.add(e)}}function Wg(t,e){let r=t.classList;r.contains(e)&&r.remove(e)}function mt(t,e,r){t.style[e]=r+\"px\"}function Ai(t,e,r,n){let i=Ug.createElement(t);return e!=null&&cn(i,e),r!=null&&r.insertBefore(i,n),i}function Dn(t,e){return Ai(\"div\",t,e)}const M0=new WeakMap;function ds(t,e,r,n,i){let a=\"translate(\"+e+\"px,\"+r+\"px)\",o=M0.get(t);a!=o&&(t.style.transform=a,M0.set(t,a),e<0||r<0||e>n||r>i?cn(t,oo):Wg(t,oo))}const N0=new WeakMap;function Fq(t,e,r){let n=e+r,i=N0.get(t);n!=i&&(N0.set(t,n),t.style.background=e,t.style.borderColor=r)}const I0=new WeakMap;function jq(t,e,r,n){let i=e+\"\"+r,a=I0.get(t);i!=a&&(I0.set(t,i),t.style.height=r+\"px\",t.style.width=e+\"px\",t.style.marginLeft=n?-e/2+\"px\":0,t.style.marginTop=n?-r/2+\"px\":0)}const zy={passive:!0},jM={...zy,capture:!0};function mo(t,e,r,n){e.addEventListener(t,r,n?jM:zy)}function Kg(t,e,r,n){e.removeEventListener(t,r,n?jM:zy)}il&&Gg();function sa(t,e,r,n){let i;r=r||0,n=n||e.length-1;let a=n<=2147483647;for(;n-r>1;)i=a?r+n>>1:kn((r+n)/2),e[i]<t?r=i:n=i;return t-e[r]<=e[n]-t?r:n}function Ws(t,e,r,n){for(let i=n==1?e:r;i>=e&&i<=r;i+=n)if(t[i]!=null)return i;return-1}function Vq(t,e,r,n){let i=Le,a=-Le;if(n==1)i=t[e],a=t[r];else if(n==-1)i=t[r],a=t[e];else for(let o=e;o<=r;o++)t[o]!=null&&(i=Wr(i,t[o]),a=Zt(a,t[o]));return[i,a]}function Hq(t,e,r){let n=Le,i=-Le;for(let a=e;a<=r;a++)t[a]>0&&(n=Wr(n,t[a]),i=Zt(i,t[a]));return[n==Le?1:n,i==-Le?10:i]}function eh(t,e,r,n){let i=L0(t),a=L0(e),o=r==10?Hi:VM;t==e&&(i==-1?(t*=r,e/=r):(t/=r,e*=r));let s=i==1?kn:Ud,l=a==1?Ud:kn,u=s(o(vr(t))),f=l(o(vr(e))),d=Ks(r,u),p=Ks(r,f);return u<0&&(d=lt(d,-u)),f<0&&(p=lt(p,-f)),n?(t=d*i,e=p*a):(t=zM(t,d),e=go(e,p)),[t,e]}function Uy(t,e,r,n){let i=eh(t,e,r,n);return t==0&&(i[0]=0),e==0&&(i[1]=0),i}const Gy=.1,B0={mode:3,pad:Gy},yu={pad:0,soft:null,mode:0},zq={min:yu,max:yu};function zd(t,e,r,n){return rh(r)?k0(t,e,r):(yu.pad=r,yu.soft=n?0:null,yu.mode=n?3:0,k0(t,e,zq))}function Ue(t,e){return t==null?e:t}function Uq(t,e,r){for(e=Ue(e,0),r=Ue(r,t.length-1);e<=r;){if(t[e]!=null)return!0;e++}return!1}function k0(t,e,r){let n=r.min,i=r.max,a=Ue(n.pad,0),o=Ue(i.pad,0),s=Ue(n.hard,-Le),l=Ue(i.hard,Le),u=Ue(n.soft,Le),f=Ue(i.soft,-Le),d=Ue(n.mode,0),p=Ue(i.mode,0),h=e-t,b=Hi(h),y=Zt(vr(t),vr(e)),P=Hi(y),C=vr(P-b);(h<1e-9||C>10)&&(h=0,(t==0||e==0)&&(h=1e-9,d==2&&u!=Le&&(a=0),p==2&&f!=-Le&&(o=0)));let R=h||y||1e3,D=Hi(R),B=Ks(10,kn(D)),A=R*(h==0?t==0?.1:1:a),V=lt(zM(t-A,B/10),9),N=t>=u&&(d==1||d==3&&V<=u||d==2&&V>=u)?u:Le,G=Zt(s,V<N&&t>=N?N:Wr(N,V)),H=R*(h==0?e==0?.1:1:o),W=lt(go(e+H,B/10),9),j=e<=f&&(p==1||p==3&&W>=f||p==2&&W<=f)?f:-Le,E=Wr(l,W>j&&e<=j?j:Zt(j,W));return G==E&&G==0&&(E=100),[G,E]}const Gq=new Intl.NumberFormat(il?Lq.language:\"en-US\"),Wy=t=>Gq.format(t),Tn=Math,Ff=Tn.PI,vr=Tn.abs,kn=Tn.floor,qt=Tn.round,Ud=Tn.ceil,Wr=Tn.min,Zt=Tn.max,Ks=Tn.pow,L0=Tn.sign,Hi=Tn.log10,VM=Tn.log2,Wq=(t,e=1)=>Tn.sinh(t)*e,lm=(t,e=1)=>Tn.asinh(t/e),Le=1/0;function F0(t){return(Hi((t^t>>31)-(t>>31))|0)+1}function ro(t,e){return qt(t/e)*e}function j0(t,e,r){return Wr(Zt(t,e),r)}function Ve(t){return typeof t==\"function\"?t:()=>t}const Kq=()=>{},Yq=t=>t,HM=(t,e)=>e,qq=t=>null,V0=t=>!0,H0=(t,e)=>t==e;function go(t,e){return Ud(t/e)*e}function zM(t,e){return kn(t/e)*e}function lt(t,e=0){if(Jq(t))return t;let r=10**e,n=t*r*(1+Number.EPSILON);return qt(n)/r}const th=new Map;function Xq(t){return((\"\"+t).split(\".\")[1]||\"\").length}function Lu(t,e,r,n){let i=[],a=n.map(Xq);for(let o=e;o<r;o++){let s=vr(o),l=lt(Ks(t,o),s);for(let u=0;u<n.length;u++){let f=n[u]*l,d=(f>=0&&o>=0?0:s)+(o>=a[u]?0:a[u]),p=lt(f,d);i.push(p),th.set(p,d)}}return i}const Ou={},UM=[],Ys=[null,null],so=Array.isArray,Jq=Number.isInteger;function z0(t){return typeof t==\"string\"}function rh(t){let e=!1;if(t!=null){let r=t.constructor;e=r==null||r==Object}return e}function U0(t){return t!=null&&typeof t==\"object\"}const Zq=Object.getPrototypeOf(Uint8Array);function bo(t,e=rh){let r;if(so(t)){let n=t.find(i=>i!=null);if(so(n)||e(n)){r=Array(t.length);for(let i=0;i<t.length;i++)r[i]=bo(t[i],e)}else r=t.slice()}else if(t instanceof Zq)r=t.slice();else if(e(t)){r={};for(let n in t)r[n]=bo(t[n],e)}else r=t;return r}function Bt(t){let e=arguments;for(let r=1;r<e.length;r++){let n=e[r];for(let i in n)rh(t[i])?Bt(t[i],bo(n[i])):t[i]=bo(n[i])}return t}const Qq=0,eX=1,tX=2;function rX(t,e,r){for(let n=0,i,a=-1;n<e.length;n++){let o=e[n];if(o>a){for(i=o-1;i>=0&&t[i]==null;)t[i--]=null;for(i=o+1;i<r&&t[i]==null;)t[a=i++]=null}}}function nX(t,e){let r=new Set;for(let o=0;o<t.length;o++){let l=t[o][0],u=l.length;for(let f=0;f<u;f++)r.add(l[f])}let n=[Array.from(r).sort((o,s)=>o-s)],i=n[0].length,a=new Map;for(let o=0;o<i;o++)a.set(n[0][o],o);for(let o=0;o<t.length;o++){let s=t[o],l=s[0];for(let u=1;u<s.length;u++){let f=s[u],d=Array(i).fill(void 0),p=e?e[o][u]:eX,h=[];for(let b=0;b<f.length;b++){let y=f[b],P=a.get(l[b]);y===null?p!=Qq&&(d[P]=y,p==tX&&h.push(P)):d[P]=y}rX(d,h,i),n.push(d)}}return n}const iX=typeof queueMicrotask>\"u\"?t=>Promise.resolve().then(t):queueMicrotask,GM=[\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"],WM=[\"Sunday\",\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\"];function KM(t){return t.slice(0,3)}const aX=WM.map(KM),oX=GM.map(KM),sX={MMMM:GM,MMM:oX,WWWW:WM,WWW:aX};function Gl(t){return(t<10?\"0\":\"\")+t}function lX(t){return(t<10?\"00\":t<100?\"0\":\"\")+t}const uX={YYYY:t=>t.getFullYear(),YY:t=>(t.getFullYear()+\"\").slice(2),MMMM:(t,e)=>e.MMMM[t.getMonth()],MMM:(t,e)=>e.MMM[t.getMonth()],MM:t=>Gl(t.getMonth()+1),M:t=>t.getMonth()+1,DD:t=>Gl(t.getDate()),D:t=>t.getDate(),WWWW:(t,e)=>e.WWWW[t.getDay()],WWW:(t,e)=>e.WWW[t.getDay()],HH:t=>Gl(t.getHours()),H:t=>t.getHours(),h:t=>{let e=t.getHours();return e==0?12:e>12?e-12:e},AA:t=>t.getHours()>=12?\"PM\":\"AM\",aa:t=>t.getHours()>=12?\"pm\":\"am\",a:t=>t.getHours()>=12?\"p\":\"a\",mm:t=>Gl(t.getMinutes()),m:t=>t.getMinutes(),ss:t=>Gl(t.getSeconds()),s:t=>t.getSeconds(),fff:t=>lX(t.getMilliseconds())};function Ky(t,e){e=e||sX;let r=[],n=/\\{([a-z]+)\\}|[^{]+/gi,i;for(;i=n.exec(t);)r.push(i[0][0]==\"{\"?uX[i[1]]:i[0]);return a=>{let o=\"\";for(let s=0;s<r.length;s++)o+=typeof r[s]==\"string\"?r[s]:r[s](a,e);return o}}const cX=new Intl.DateTimeFormat().resolvedOptions().timeZone;function fX(t,e){let r;return e==\"UTC\"||e==\"Etc/UTC\"?r=new Date(+t+t.getTimezoneOffset()*6e4):e==cX?r=t:(r=new Date(t.toLocaleString(\"en-US\",{timeZone:e})),r.setMilliseconds(t.getMilliseconds())),r}const YM=t=>t%1==0,Gd=[1,2,2.5,5],dX=Lu(10,-16,0,Gd),qM=Lu(10,0,16,Gd),pX=qM.filter(YM),hX=dX.concat(qM),Yy=`\n`,XM=\"{YYYY}\",G0=Yy+XM,JM=\"{M}/{D}\",lu=Yy+JM,Zc=lu+\"/{YY}\",ZM=\"{aa}\",vX=\"{h}:{mm}\",bs=vX+ZM,W0=Yy+bs,K0=\":{ss}\",Xe=null;function QM(t){let e=t*1e3,r=e*60,n=r*60,i=n*24,a=i*30,o=i*365,l=(t==1?Lu(10,0,3,Gd).filter(YM):Lu(10,-3,0,Gd)).concat([e,e*5,e*10,e*15,e*30,r,r*5,r*10,r*15,r*30,n,n*2,n*3,n*4,n*6,n*8,n*12,i,i*2,i*3,i*4,i*5,i*6,i*7,i*8,i*9,i*10,i*15,a,a*2,a*3,a*4,a*6,o,o*2,o*5,o*10,o*25,o*50,o*100]);const u=[[o,XM,Xe,Xe,Xe,Xe,Xe,Xe,1],[i*28,\"{MMM}\",G0,Xe,Xe,Xe,Xe,Xe,1],[i,JM,G0,Xe,Xe,Xe,Xe,Xe,1],[n,\"{h}\"+ZM,Zc,Xe,lu,Xe,Xe,Xe,1],[r,bs,Zc,Xe,lu,Xe,Xe,Xe,1],[e,K0,Zc+\" \"+bs,Xe,lu+\" \"+bs,Xe,W0,Xe,1],[t,K0+\".{fff}\",Zc+\" \"+bs,Xe,lu+\" \"+bs,Xe,W0,Xe,1]];function f(d){return(p,h,b,y,P,C)=>{let R=[],D=P>=o,B=P>=a&&P<o,A=d(b),V=lt(A*t,3),N=um(A.getFullYear(),D?0:A.getMonth(),B||D?1:A.getDate()),G=lt(N*t,3);if(B||D){let H=B?P/a:0,W=D?P/o:0,j=V==G?V:lt(um(N.getFullYear()+W,N.getMonth()+H,1)*t,3),E=new Date(qt(j/t)),v=E.getFullYear(),w=E.getMonth();for(let $=0;j<=y;$++){let M=um(v+W*$,w+H*$,1),F=M-d(lt(M*t,3));j=lt((+M+F)*t,3),j<=y&&R.push(j)}}else{let H=P>=i?i:P,W=kn(b)-kn(V),j=G+W+go(V-G,H);R.push(j);let E=d(j),v=E.getHours()+E.getMinutes()/r+E.getSeconds()/n,w=P/n,$=p.axes[h]._space,M=C/$;for(;j=lt(j+P,t==1?0:3),!(j>y);)if(w>1){let F=kn(lt(v+w,6))%24,q=d(j).getHours()-F;q>1&&(q=-1),j-=q*n,v=(v+w)%24;let K=R[R.length-1];lt((j-K)/P,3)*M>=.7&&R.push(j)}else R.push(j)}return R}}return[l,u,f]}const[mX,gX,bX]=QM(1),[yX,OX,_X]=QM(.001);Lu(2,-53,53,[1]);function Y0(t,e){return t.map(r=>r.map((n,i)=>i==0||i==8||n==null?n:e(i==1||r[8]==0?n:r[1]+n)))}function q0(t,e){return(r,n,i,a,o)=>{let s=e.find(b=>o>=b[0])||e[e.length-1],l,u,f,d,p,h;return n.map(b=>{let y=t(b),P=y.getFullYear(),C=y.getMonth(),R=y.getDate(),D=y.getHours(),B=y.getMinutes(),A=y.getSeconds(),V=P!=l&&s[2]||C!=u&&s[3]||R!=f&&s[4]||D!=d&&s[5]||B!=p&&s[6]||A!=h&&s[7]||s[1];return l=P,u=C,f=R,d=D,p=B,h=A,V(y)})}}function wX(t,e){let r=Ky(e);return(n,i,a,o,s)=>i.map(l=>r(t(l)))}function um(t,e,r){return new Date(t,e,r)}function X0(t,e){return e(t)}const TX=\"{YYYY}-{MM}-{DD} {h}:{mm}{aa}\";function J0(t,e){return(r,n)=>e(t(n))}function SX(t,e){let r=t.series[e];return r.width?r.stroke(t,e):r.points.width?r.points.stroke(t,e):null}function PX(t,e){return t.series[e].fill(t,e)}const EX={show:!0,live:!0,isolate:!1,mount:Kq,markers:{show:!0,width:2,stroke:SX,fill:PX,dash:\"solid\"},idx:null,idxs:null,values:[]};function $X(t,e){let r=t.cursor.points,n=Dn(),i=r.size(t,e);mt(n,ou,i),mt(n,su,i);let a=i/-2;mt(n,\"marginLeft\",a),mt(n,\"marginTop\",a);let o=r.width(t,e,i);return o&&mt(n,\"borderWidth\",o),n}function CX(t,e){let r=t.series[e].points;return r._fill||r._stroke}function DX(t,e){let r=t.series[e].points;return r._stroke||r._fill}function AX(t,e){let r=t.series[e].points;return iN(r.width,1)}function RX(t,e,r){return r}const cm=[0,0];function xX(t,e,r){return cm[0]=e,cm[1]=r,cm}function Qc(t,e,r){return n=>{n.button==0&&r(n)}}function fm(t,e,r){return r}const MX={show:!0,x:!0,y:!0,lock:!1,move:xX,points:{show:$X,size:AX,width:0,stroke:DX,fill:CX},bind:{mousedown:Qc,mouseup:Qc,click:Qc,dblclick:Qc,mousemove:fm,mouseleave:fm,mouseenter:fm},drag:{setScale:!0,x:!0,y:!1,dist:0,uni:null,_x:!1,_y:!1},focus:{prox:-1},left:-10,top:-10,idx:null,dataIdx:RX,idxs:null},eN={show:!0,stroke:\"rgba(0,0,0,0.07)\",width:2},qy=Bt({},eN,{filter:HM}),tN=Bt({},qy,{size:10}),rN=Bt({},eN,{show:!1}),Xy='12px system-ui, -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"',nN=\"bold \"+Xy,NX=1.5,Z0={show:!0,scale:\"x\",stroke:Hy,space:50,gap:5,size:50,labelGap:0,labelSize:30,labelFont:nN,side:2,grid:qy,ticks:tN,border:rN,font:Xy,rotate:0},IX=\"Value\",BX=\"Time\",Q0={show:!0,scale:\"x\",auto:!1,sorted:1,min:Le,max:-Le,idxs:[]};function kX(t,e,r,n,i){return e.map(a=>a==null?\"\":Wy(a))}function LX(t,e,r,n,i,a,o){let s=[],l=th.get(i)||0;r=o?r:lt(go(r,i),l);for(let u=r;u<=n;u=lt(u+i,l))s.push(Object.is(u,-0)?0:u);return s}function Yg(t,e,r,n,i,a,o){const s=[],l=t.scales[t.axes[e].scale].log,u=l==10?Hi:VM,f=kn(u(r));i=Ks(l,f),f<0&&(i=lt(i,-f));let d=r;do s.push(d),d=lt(d+i,th.get(i)),d>=i*l&&(i=d);while(d<=n);return s}function FX(t,e,r,n,i,a,o){let l=t.scales[t.axes[e].scale].asinh,u=n>l?Yg(t,e,Zt(l,r),n,i):[l],f=n>=0&&r<=0?[0]:[];return(r<-l?Yg(t,e,Zt(l,-n),-r,i):[l]).reverse().map(p=>-p).concat(f,u)}const jX=/./,VX=/[12357]/,HX=/[125]/,zX=/1/;function UX(t,e,r,n,i){let a=t.axes[r],o=a.scale,s=t.scales[o];if(s.distr==3&&s.log==2)return e;let l=t.valToPos,u=a._space,f=l(10,o),d=l(9,o)-f>=u?jX:l(7,o)-f>=u?VX:l(5,o)-f>=u?HX:zX;return e.map(p=>s.distr==4&&p==0||d.test(p)?p:null)}function GX(t,e){return e==null?\"\":Wy(e)}const e1={show:!0,scale:\"y\",stroke:Hy,space:30,gap:5,size:50,labelGap:0,labelSize:30,labelFont:nN,side:3,grid:qy,ticks:tN,border:rN,font:Xy,rotate:0};function iN(t,e){let r=3+(t||1)*2;return lt(r*e,3)}function WX(t,e){let{scale:r,idxs:n}=t.series[0],i=t._data[0],a=t.valToPos(i[n[0]],r,!0),o=t.valToPos(i[n[1]],r,!0),s=vr(o-a),l=t.series[e],u=s/(l.points.space*ze);return n[1]-n[0]<=u}const t1={scale:null,auto:!0,sorted:0,min:Le,max:-Le},aN=(t,e,r,n,i)=>i,r1={show:!0,auto:!0,sorted:0,gaps:aN,alpha:1,facets:[Bt({},t1,{scale:\"x\"}),Bt({},t1,{scale:\"y\"})]},n1={scale:\"y\",auto:!0,sorted:0,show:!0,spanGaps:!1,gaps:aN,alpha:1,points:{show:WX,filter:null},values:null,min:Le,max:-Le,idxs:[],path:null,clip:null};function KX(t,e,r,n,i){return r/10}const oN={time:mq,auto:!0,distr:1,log:10,asinh:1,min:null,max:null,dir:1,ori:0},YX=Bt({},oN,{time:!1,ori:1}),i1={};function sN(t,e){let r=i1[t];return r||(r={key:t,plots:[],sub(n){r.plots.push(n)},unsub(n){r.plots=r.plots.filter(i=>i!=n)},pub(n,i,a,o,s,l,u){for(let f=0;f<r.plots.length;f++)r.plots[f]!=i&&r.plots[f].pub(n,i,a,o,s,l,u)}},t!=null&&(i1[t]=r)),r}const Mo=1<<0,Wd=1<<1;function Vo(t,e,r){const n=t.mode,i=t.series[e],a=n==2?t._data[e]:t._data,o=t.scales,s=t.bbox;let l=a[0],u=n==2?a[1]:a[e],f=n==2?o[i.facets[0].scale]:o[t.series[0].scale],d=n==2?o[i.facets[1].scale]:o[i.scale],p=s.left,h=s.top,b=s.width,y=s.height,P=t.valToPosH,C=t.valToPosV;return f.ori==0?r(i,l,u,f,d,P,C,p,h,b,y,ah,al,sh,uN,fN):r(i,l,u,f,d,C,P,h,p,y,b,oh,ol,Zy,cN,dN)}function nh(t,e){let r=0,n=0,i=Ue(t.bands,UM);for(let a=0;a<i.length;a++){let o=i[a];o.series[0]==e?r=o.dir:o.series[1]==e&&(o.dir==1?n|=1:n|=2)}return[r,n==1?-1:n==2?1:n==3?2:0]}function qX(t,e,r,n,i){let a=t.mode,o=t.series[e],s=a==2?o.facets[1].scale:o.scale,l=t.scales[s];return i==-1?l.min:i==1?l.max:l.distr==3?l.dir==1?l.min:l.max:0}function zi(t,e,r,n,i,a){return Vo(t,e,(o,s,l,u,f,d,p,h,b,y,P)=>{let C=o.pxRound;const R=u.dir*(u.ori==0?1:-1),D=u.ori==0?al:ol;let B,A;R==1?(B=r,A=n):(B=n,A=r);let V=C(d(s[B],u,y,h)),N=C(p(l[B],f,P,b)),G=C(d(s[A],u,y,h)),H=C(p(a==1?f.max:f.min,f,P,b)),W=new Path2D(i);return D(W,G,H),D(W,V,H),D(W,V,N),W})}function ih(t,e,r,n,i,a){let o=null;if(t.length>0){o=new Path2D;const s=e==0?sh:Zy;let l=r;for(let f=0;f<t.length;f++){let d=t[f];if(d[1]>d[0]){let p=d[0]-l;p>0&&s(o,l,n,p,n+a),l=d[1]}}let u=r+i-l;u>0&&s(o,l,n,u,n+a)}return o}function XX(t,e,r){let n=t[t.length-1];n&&n[0]==e?n[1]=r:t.push([e,r])}function Jy(t,e,r,n,i,a,o){let s=[];for(let l=i==1?r:n;l>=r&&l<=n;l+=i)if(e[l]===null){let f=l,d=l;if(i==1)for(;++l<=n&&e[l]===null;)d=l;else for(;--l>=r&&e[l]===null;)d=l;let p=a(t[f]),h=d==f?p:a(t[d]);p=o<=0?a(t[f-i]):p,h=o>=0?a(t[d+i]):h,h>=p&&s.push([p,h])}return s}function a1(t){return t==0?Yq:t==1?qt:e=>ro(e,t)}function lN(t){let e=t==0?ah:oh,r=t==0?(i,a,o,s,l,u)=>{i.arcTo(a,o,s,l,u)}:(i,a,o,s,l,u)=>{i.arcTo(o,a,l,s,u)},n=t==0?(i,a,o,s,l)=>{i.rect(a,o,s,l)}:(i,a,o,s,l)=>{i.rect(o,a,l,s)};return(i,a,o,s,l,u=0)=>{u==0?n(i,a,o,s,l):(u=Wr(u,s/2,l/2),e(i,a+u,o),r(i,a+s,o,a+s,o+l,u),r(i,a+s,o+l,a,o+l,u),r(i,a,o+l,a,o,u),r(i,a,o,a+s,o,u),i.closePath())}}const ah=(t,e,r)=>{t.moveTo(e,r)},oh=(t,e,r)=>{t.moveTo(r,e)},al=(t,e,r)=>{t.lineTo(e,r)},ol=(t,e,r)=>{t.lineTo(r,e)},sh=lN(0),Zy=lN(1),uN=(t,e,r,n,i,a)=>{t.arc(e,r,n,i,a)},cN=(t,e,r,n,i,a)=>{t.arc(r,e,n,i,a)},fN=(t,e,r,n,i,a,o)=>{t.bezierCurveTo(e,r,n,i,a,o)},dN=(t,e,r,n,i,a,o)=>{t.bezierCurveTo(r,e,i,n,o,a)};function pN(t){return(e,r,n,i,a)=>Vo(e,r,(o,s,l,u,f,d,p,h,b,y,P)=>{let{pxRound:C,points:R}=o,D,B;u.ori==0?(D=ah,B=uN):(D=oh,B=cN);const A=lt(R.width*ze,3);let V=(R.size-R.width)/2*ze,N=lt(V*2,3),G=new Path2D,H=new Path2D,{left:W,top:j,width:E,height:v}=e.bbox;sh(H,W-N,j-N,E+N*2,v+N*2);const w=$=>{if(l[$]!=null){let M=C(d(s[$],u,y,h)),F=C(p(l[$],f,P,b));D(G,M+V,F),B(G,M,F,V,0,Ff*2)}};if(a)a.forEach(w);else for(let $=n;$<=i;$++)w($);return{stroke:A>0?G:null,fill:G,clip:H,flags:Mo|Wd}})}function hN(t){return(e,r,n,i,a,o)=>{n!=i&&(a!=n&&o!=n&&t(e,r,n),a!=i&&o!=i&&t(e,r,i),t(e,r,o))}}const JX=hN(al),ZX=hN(ol);function vN(t){const e=Ue(t==null?void 0:t.alignGaps,0);return(r,n,i,a)=>Vo(r,n,(o,s,l,u,f,d,p,h,b,y,P)=>{let C=o.pxRound,R=K=>C(d(K,u,y,h)),D=K=>C(p(K,f,P,b)),B,A;u.ori==0?(B=al,A=JX):(B=ol,A=ZX);const V=u.dir*(u.ori==0?1:-1),N={stroke:new Path2D,fill:null,clip:null,band:null,gaps:null,flags:Mo},G=N.stroke;let H=Le,W=-Le,j,E,v,w=R(s[V==1?i:a]),$=Ws(l,i,a,1*V),M=Ws(l,i,a,-1*V),F=R(s[$]),X=R(s[M]);for(let K=V==1?i:a;K>=i&&K<=a;K+=V){let U=R(s[K]);U==w?l[K]!=null&&(E=D(l[K]),H==Le&&(B(G,U,E),j=E),H=Wr(E,H),W=Zt(E,W)):(H!=Le&&(A(G,w,H,W,j,E),v=w),l[K]!=null?(E=D(l[K]),B(G,U,E),H=W=j=E):(H=Le,W=-Le),w=U)}H!=Le&&H!=W&&v!=w&&A(G,w,H,W,j,E);let[Q,q]=nh(r,n);if(o.fill!=null||Q!=0){let K=N.fill=new Path2D(G),U=o.fillTo(r,n,o.min,o.max,Q),le=D(U);B(K,X,le),B(K,F,le)}if(!o.spanGaps){let K=[];K.push(...Jy(s,l,i,a,V,R,e)),N.gaps=K=o.gaps(r,n,i,a,K),N.clip=ih(K,u.ori,h,b,y,P)}return q!=0&&(N.band=q==2?[zi(r,n,i,a,G,-1),zi(r,n,i,a,G,1)]:zi(r,n,i,a,G,q)),N})}function QX(t){const e=Ue(t.align,1),r=Ue(t.ascDesc,!1),n=Ue(t.alignGaps,0),i=Ue(t.extend,!1);return(a,o,s,l)=>Vo(a,o,(u,f,d,p,h,b,y,P,C,R,D)=>{let B=u.pxRound,{left:A,width:V}=a.bbox,N=q=>B(b(q,p,R,P)),G=q=>B(y(q,h,D,C)),H=p.ori==0?al:ol;const W={stroke:new Path2D,fill:null,clip:null,band:null,gaps:null,flags:Mo},j=W.stroke,E=p.dir*(p.ori==0?1:-1);s=Ws(d,s,l,1),l=Ws(d,s,l,-1);let v=G(d[E==1?s:l]),w=N(f[E==1?s:l]),$=w,M=w;i&&e==-1&&(M=A,H(j,M,v)),H(j,w,v);for(let q=E==1?s:l;q>=s&&q<=l;q+=E){let K=d[q];if(K==null)continue;let U=N(f[q]),le=G(K);e==1?H(j,U,v):H(j,$,le),H(j,U,le),v=le,$=U}let F=$;i&&e==1&&(F=A+V,H(j,F,v));let[X,Q]=nh(a,o);if(u.fill!=null||X!=0){let q=W.fill=new Path2D(j),K=u.fillTo(a,o,u.min,u.max,X),U=G(K);H(q,F,U),H(q,M,U)}if(!u.spanGaps){let q=[];q.push(...Jy(f,d,s,l,E,N,n));let K=u.width*ze/2,U=r||e==1?K:-K,le=r||e==-1?-K:K;q.forEach(be=>{be[0]+=U,be[1]+=le}),W.gaps=q=u.gaps(a,o,s,l,q),W.clip=ih(q,p.ori,P,C,R,D)}return Q!=0&&(W.band=Q==2?[zi(a,o,s,l,j,-1),zi(a,o,s,l,j,1)]:zi(a,o,s,l,j,Q)),W})}function eJ(t){t=t||Ou;const e=Ue(t.size,[.6,Le,1]),r=t.align||0,n=(t.gap||0)*ze,i=Ue(t.radius,0),a=1-e[0],o=Ue(e[1],Le)*ze,s=Ue(e[2],1)*ze,l=Ue(t.disp,Ou),u=Ue(t.each,p=>{}),{fill:f,stroke:d}=l;return(p,h,b,y)=>Vo(p,h,(P,C,R,D,B,A,V,N,G,H,W)=>{let j=P.pxRound;const E=D.dir*(D.ori==0?1:-1),v=B.dir*(B.ori==1?1:-1);let w=D.ori==0?sh:Zy,$=D.ori==0?u:(Ye,wr,nn,$e,Be,Ct,zt)=>{u(Ye,wr,nn,Be,$e,zt,Ct)},[M,F]=nh(p,h),X=B.distr==3?M==1?B.max:B.min:0,Q=V(X,B,W,G),q,K,U=j(P.width*ze),le=!1,be=null,me=null,Ie=null,Te=null;f!=null&&(U==0||d!=null)&&(le=!0,be=f.values(p,h,b,y),me=new Map,new Set(be).forEach(Ye=>{Ye!=null&&me.set(Ye,new Path2D)}),U>0&&(Ie=d.values(p,h,b,y),Te=new Map,new Set(Ie).forEach(Ye=>{Ye!=null&&Te.set(Ye,new Path2D)})));let{x0:$t,size:Re}=l;if($t!=null&&Re!=null){C=$t.values(p,h,b,y),$t.unit==2&&(C=C.map(wr=>p.posToVal(N+wr*H,D.key,!0)));let Ye=Re.values(p,h,b,y);Re.unit==2?K=Ye[0]*H:K=A(Ye[0],D,H,N)-A(0,D,H,N),K=j(K-U),q=E==1?-U/2:K+U/2}else{let Ye=H;if(C.length>1){let nn=null;for(let $e=0,Be=1/0;$e<C.length;$e++)if(R[$e]!==void 0){if(nn!=null){let Ct=vr(C[$e]-C[nn]);Ct<Be&&(Be=Ct,Ye=vr(A(C[$e],D,H,N)-A(C[nn],D,H,N)))}nn=$e}}let wr=Ye*a;K=j(Wr(o,Zt(s,Ye-wr))-U-n),q=(r==0?K/2:r==E?0:K)-r*E*n/2}const Qe={stroke:null,fill:null,clip:null,band:null,gaps:null,flags:Mo|Wd};let Ir;F!=0&&(Qe.band=new Path2D,Ir=j(V(F==1?B.max:B.min,B,W,G)));const Pn=le?null:new Path2D,ul=Qe.band;let{y0:zo,y1:Pi}=l,En=null;zo!=null&&Pi!=null&&(R=Pi.values(p,h,b,y),En=zo.values(p,h,b,y));for(let Ye=E==1?b:y;Ye>=b&&Ye<=y;Ye+=E){let wr=R[Ye];if(wr===void 0)continue;let nn=D.distr!=2||l!=null?C[Ye]:Ye,$e=A(nn,D,H,N),Be=V(Ue(wr,X),B,W,G);En!=null&&wr!=null&&(Q=V(En[Ye],B,W,G));let Ct=j($e-q),zt=j(Zt(Be,Q)),Ut=j(Wr(Be,Q)),Br=zt-Ut,jn=i*K;wr!=null&&(le?(U>0&&Ie[Ye]!=null&&w(Te.get(Ie[Ye]),Ct,Ut+kn(U/2),K,Zt(0,Br-U),jn),be[Ye]!=null&&w(me.get(be[Ye]),Ct,Ut+kn(U/2),K,Zt(0,Br-U),jn)):w(Pn,Ct,Ut+kn(U/2),K,Zt(0,Br-U),jn),$(p,h,Ye,Ct-U/2,Ut,K+U,Br)),F!=0&&(v*F==1?(zt=Ut,Ut=Ir):(Ut=zt,zt=Ir),Br=zt-Ut,w(ul,Ct-U/2,Ut,K+U,Zt(0,Br),0))}return U>0&&(Qe.stroke=le?Te:Pn),Qe.fill=le?me:Pn,Qe})}function tJ(t,e){const r=Ue(e==null?void 0:e.alignGaps,0);return(n,i,a,o)=>Vo(n,i,(s,l,u,f,d,p,h,b,y,P,C)=>{let R=s.pxRound,D=F=>R(p(F,f,P,b)),B=F=>R(h(F,d,C,y)),A,V,N;f.ori==0?(A=ah,N=al,V=fN):(A=oh,N=ol,V=dN);const G=f.dir*(f.ori==0?1:-1);a=Ws(u,a,o,1),o=Ws(u,a,o,-1);let H=D(l[G==1?a:o]),W=H,j=[],E=[];for(let F=G==1?a:o;F>=a&&F<=o;F+=G)if(u[F]!=null){let Q=l[F],q=D(Q);j.push(W=q),E.push(B(u[F]))}const v={stroke:t(j,E,A,N,V,R),fill:null,clip:null,band:null,gaps:null,flags:Mo},w=v.stroke;let[$,M]=nh(n,i);if(s.fill!=null||$!=0){let F=v.fill=new Path2D(w),X=s.fillTo(n,i,s.min,s.max,$),Q=B(X);N(F,W,Q),N(F,H,Q)}if(!s.spanGaps){let F=[];F.push(...Jy(l,u,a,o,G,D,r)),v.gaps=F=s.gaps(n,i,a,o,F),v.clip=ih(F,f.ori,b,y,P,C)}return M!=0&&(v.band=M==2?[zi(n,i,a,o,w,-1),zi(n,i,a,o,w,1)]:zi(n,i,a,o,w,M)),v})}function rJ(t){return tJ(nJ,t)}function nJ(t,e,r,n,i,a){const o=t.length;if(o<2)return null;const s=new Path2D;if(r(s,t[0],e[0]),o==2)n(s,t[1],e[1]);else{let l=Array(o),u=Array(o-1),f=Array(o-1),d=Array(o-1);for(let p=0;p<o-1;p++)f[p]=e[p+1]-e[p],d[p]=t[p+1]-t[p],u[p]=f[p]/d[p];l[0]=u[0];for(let p=1;p<o-1;p++)u[p]===0||u[p-1]===0||u[p-1]>0!=u[p]>0?l[p]=0:(l[p]=3*(d[p-1]+d[p])/((2*d[p]+d[p-1])/u[p-1]+(d[p]+2*d[p-1])/u[p]),isFinite(l[p])||(l[p]=0));l[o-1]=u[o-2];for(let p=0;p<o-1;p++)i(s,t[p]+d[p]/3,e[p]+l[p]*d[p]/3,t[p+1]-d[p]/3,e[p+1]-l[p+1]*d[p]/3,t[p+1],e[p+1])}return s}const qg=new Set;function o1(){for(let t of qg)t.syncRect(!0)}il&&(mo(Bq,Rs,o1),mo(kq,Rs,o1,!0),mo(Hd,Rs,()=>{cr.pxRatio=ze}));const iJ=vN(),aJ=pN();function s1(t,e,r,n){return(n?[t[0],t[1]].concat(t.slice(2)):[t[0]].concat(t.slice(1))).map((a,o)=>Xg(a,o,e,r))}function oJ(t,e){return t.map((r,n)=>n==0?null:Bt({},e,r))}function Xg(t,e,r,n){return Bt({},e==0?r:n,t)}function mN(t,e,r){return e==null?Ys:[e,r]}const sJ=mN;function lJ(t,e,r){return e==null?Ys:zd(e,r,Gy,!0)}function gN(t,e,r,n){return e==null?Ys:eh(e,r,t.scales[n].log,!1)}const uJ=gN;function bN(t,e,r,n){return e==null?Ys:Uy(e,r,t.scales[n].log,!1)}const cJ=bN;function fJ(t,e,r,n,i){let a=Zt(F0(t),F0(e)),o=e-t,s=sa(i/n*o,r);do{let l=r[s],u=n*l/o;if(u>=i&&a+(l<5?th.get(l):0)<=17)return[l,u]}while(++s<r.length);return[0,0]}function l1(t){let e,r;return t=t.replace(/(\\d+)px/,(n,i)=>(e=qt((r=+i)*ze))+\"px\"),[t,e,r]}function dJ(t){t.show&&[t.font,t.labelFont].forEach(e=>{let r=lt(e[2]*ze,1);e[0]=e[0].replace(/[0-9.]+px/,r+\"px\"),e[1]=r})}function cr(t,e,r){const n={mode:Ue(t.mode,1)},i=n.mode;function a(m,O){return((O.distr==3?Hi(m>0?m:O.clamp(n,m,O.min,O.max,O.key)):O.distr==4?lm(m,O.asinh):m)-O._min)/(O._max-O._min)}function o(m,O,T,S){let x=a(m,O);return S+T*(O.dir==-1?1-x:x)}function s(m,O,T,S){let x=a(m,O);return S+T*(O.dir==-1?x:1-x)}function l(m,O,T,S){return O.ori==0?o(m,O,T,S):s(m,O,T,S)}n.valToPosH=o,n.valToPosV=s;let u=!1;n.status=0;const f=n.root=Dn(gq);if(t.id!=null&&(f.id=t.id),cn(f,t.class),t.title){let m=Dn(Oq,f);m.textContent=t.title}const d=Ai(\"canvas\"),p=n.ctx=d.getContext(\"2d\"),h=Dn(_q,f),b=n.under=Dn(wq,h);h.appendChild(d);const y=n.over=Dn(Tq,h);t=bo(t);const P=+Ue(t.pxAlign,1),C=a1(P);(t.plugins||[]).forEach(m=>{m.opts&&(t=m.opts(n,t)||t)});const R=t.ms||.001,D=n.series=i==1?s1(t.series||[],Q0,n1,!1):oJ(t.series||[null],r1),B=n.axes=s1(t.axes||[],Z0,e1,!0),A=n.scales={},V=n.bands=t.bands||[];V.forEach(m=>{m.fill=Ve(m.fill||null),m.dir=Ue(m.dir,-1)});const N=i==2?D[1].facets[0].scale:D[0].scale,G={axes:tI,series:XN},H=(t.drawOrder||[\"axes\",\"series\"]).map(m=>G[m]);function W(m){let O=A[m];if(O==null){let T=(t.scales||Ou)[m]||Ou;if(T.from!=null)W(T.from),A[m]=Bt({},A[T.from],T,{key:m});else{O=A[m]=Bt({},m==N?oN:YX,T),O.key=m;let S=O.time,x=O.range,k=so(x);if((m!=N||i==2&&!S)&&(k&&(x[0]==null||x[1]==null)&&(x={min:x[0]==null?B0:{mode:1,hard:x[0],soft:x[0]},max:x[1]==null?B0:{mode:1,hard:x[1],soft:x[1]}},k=!1),!k&&rh(x))){let Y=x;x=(J,te,fe)=>te==null?Ys:zd(te,fe,Y)}O.range=Ve(x||(S?sJ:m==N?O.distr==3?uJ:O.distr==4?cJ:mN:O.distr==3?gN:O.distr==4?bN:lJ)),O.auto=Ve(k?!1:O.auto),O.clamp=Ve(O.clamp||KX),O._min=O._max=null}}}W(\"x\"),W(\"y\"),i==1&&D.forEach(m=>{W(m.scale)}),B.forEach(m=>{W(m.scale)});for(let m in t.scales)W(m);const j=A[N],E=j.distr;let v,w;j.ori==0?(cn(f,bq),v=o,w=s):(cn(f,yq),v=s,w=o);const $={};for(let m in A){let O=A[m];(O.min!=null||O.max!=null)&&($[m]={min:O.min,max:O.max},O.min=O.max=null)}const M=t.tzDate||(m=>new Date(qt(m/R))),F=t.fmtDate||Ky,X=R==1?bX(M):_X(M),Q=q0(M,Y0(R==1?gX:OX,F)),q=J0(M,X0(TX,F)),K=[],U=n.legend=Bt({},EX,t.legend),le=U.show,be=U.markers;U.idxs=K,be.width=Ve(be.width),be.dash=Ve(be.dash),be.stroke=Ve(be.stroke),be.fill=Ve(be.fill);let me,Ie=[],Te=[],$t,Re=!1,Qe={};if(U.live){const m=D[1]?D[1].values:null;Re=m!=null,$t=Re?m(n,1,0):{_:0};for(let O in $t)Qe[O]=\"--\"}if(le)if(me=Ai(\"table\",Dq,f),U.mount(n,me),Re){let m=Ai(\"tr\",xq,me);Ai(\"th\",null,m);for(var Ir in $t)Ai(\"th\",S0,m).textContent=Ir}else cn(me,Rq),U.live&&cn(me,Aq);const Pn={show:!0},ul={show:!1};function zo(m,O){if(O==0&&(Re||!U.live||i==2))return Ys;let T=[],S=Ai(\"tr\",Mq,me,me.childNodes[O]);cn(S,m.class),m.show||cn(S,oo);let x=Ai(\"th\",null,S);if(be.show){let J=Dn(Nq,x);if(O>0){let te=be.width(n,O);te&&(J.style.border=te+\"px \"+be.dash(n,O)+\" \"+be.stroke(n,O)),J.style.background=be.fill(n,O)}}let k=Dn(S0,x);k.textContent=m.label,O>0&&(be.show||(k.style.color=m.width>0?be.stroke(n,O):be.fill(n,O)),En(\"click\",x,J=>{if(Se._lock)return;let te=D.indexOf(m);if((J.ctrlKey||J.metaKey)!=U.isolate){let fe=D.some((Z,ue)=>ue>0&&ue!=te&&Z.show);D.forEach((Z,ue)=>{ue>0&&oi(ue,fe?ue==te?Pn:ul:Pn,!0,sr.setSeries)})}else oi(te,{show:!m.show},!0,sr.setSeries)}),sc&&En(D0,x,J=>{Se._lock||oi(D.indexOf(m),Yo,!0,sr.setSeries)}));for(var Y in $t){let J=Ai(\"td\",Iq,S);J.textContent=\"--\",T.push(J)}return[S,T]}const Pi=new Map;function En(m,O,T){const S=Pi.get(O)||{},x=Se.bind[m](n,O,T);x&&(mo(m,O,S[m]=x),Pi.set(O,S))}function Ye(m,O,T){const S=Pi.get(O)||{};for(let x in S)(m==null||x==m)&&(Kg(x,O,S[x]),delete S[x]);m==null&&Pi.delete(O)}let wr=0,nn=0,$e=0,Be=0,Ct=0,zt=0,Ut=0,Br=0,jn=0,Va=0;n.bbox={};let hh=!1,ac=!1,Uo=!1,Go=!1,vh=!1,Vn=!1;function mh(m,O,T){(T||m!=n.width||O!=n.height)&&iO(m,O),dl(!1),Uo=!0,ac=!0,Se.left>=0&&(Go=Vn=!0),za()}function iO(m,O){n.width=wr=$e=m,n.height=nn=Be=O,Ct=zt=0,HN(),zN();let T=n.bbox;Ut=T.left=ro(Ct*ze,.5),Br=T.top=ro(zt*ze,.5),jn=T.width=ro($e*ze,.5),Va=T.height=ro(Be*ze,.5)}const FN=3;function jN(){let m=!1,O=0;for(;!m;){O++;let T=QN(O),S=eI(O);m=O==FN||T&&S,m||(iO(n.width,n.height),ac=!0)}}function VN({width:m,height:O}){mh(m,O)}n.setSize=VN;function HN(){let m=!1,O=!1,T=!1,S=!1;B.forEach((x,k)=>{if(x.show&&x._show){let{side:Y,_size:J}=x,te=Y%2,fe=x.label!=null?x.labelSize:0,Z=J+fe;Z>0&&(te?($e-=Z,Y==3?(Ct+=Z,S=!0):T=!0):(Be-=Z,Y==0?(zt+=Z,m=!0):O=!0))}}),Ha[0]=m,Ha[1]=T,Ha[2]=O,Ha[3]=S,$e-=ea[1]+ea[3],Ct+=ea[3],Be-=ea[2]+ea[0],zt+=ea[0]}function zN(){let m=Ct+$e,O=zt+Be,T=Ct,S=zt;function x(k,Y){switch(k){case 1:return m+=Y,m-Y;case 2:return O+=Y,O-Y;case 3:return T-=Y,T+Y;case 0:return S-=Y,S+Y}}B.forEach((k,Y)=>{if(k.show&&k._show){let J=k.side;k._pos=x(J,k._size),k.label!=null&&(k._lpos=x(J,k.labelSize))}})}const Se=n.cursor=Bt({},MX,{drag:{y:i==2}},t.cursor);{Se.idxs=K,Se._lock=!1;let m=Se.points;m.show=Ve(m.show),m.size=Ve(m.size),m.stroke=Ve(m.stroke),m.width=Ve(m.width),m.fill=Ve(m.fill)}const oc=n.focus=Bt({},t.focus||{alpha:.3},Se.focus),sc=oc.prox>=0;let kr=[null];function UN(m,O){if(O>0){let T=Se.points.show(n,O);if(T)return cn(T,Cq),cn(T,m.class),ds(T,-10,-10,$e,Be),y.insertBefore(T,kr[O]),T}}function aO(m,O){if(i==1||O>0){let T=i==1&&A[m.scale].time,S=m.value;m.value=T?z0(S)?J0(M,X0(S,F)):S||q:S||GX,m.label=m.label||(T?BX:IX)}if(O>0){m.width=m.width==null?1:m.width,m.paths=m.paths||iJ||qq,m.fillTo=Ve(m.fillTo||qX),m.pxAlign=+Ue(m.pxAlign,P),m.pxRound=a1(m.pxAlign),m.stroke=Ve(m.stroke||null),m.fill=Ve(m.fill||null),m._stroke=m._fill=m._paths=m._focus=null;let T=iN(m.width,1),S=m.points=Bt({},{size:T,width:Zt(1,T*.2),stroke:m.stroke,space:T*2,paths:aJ,_stroke:null,_fill:null},m.points);S.show=Ve(S.show),S.filter=Ve(S.filter),S.fill=Ve(S.fill),S.stroke=Ve(S.stroke),S.paths=Ve(S.paths),S.pxAlign=m.pxAlign}if(le){let T=zo(m,O);Ie.splice(O,0,T[0]),Te.splice(O,0,T[1]),U.values.push(null)}if(Se.show){K.splice(O,0,null);let T=UN(m,O);T&&kr.splice(O,0,T)}or(\"addSeries\",O)}function GN(m,O){O=O==null?D.length:O,m=i==1?Xg(m,O,Q0,n1):Xg(m,O,null,r1),D.splice(O,0,m),aO(D[O],O)}n.addSeries=GN;function WN(m){if(D.splice(m,1),le){U.values.splice(m,1),Te.splice(m,1);let O=Ie.splice(m,1)[0];Ye(null,O.firstChild),O.remove()}Se.show&&(K.splice(m,1),kr.length>1&&kr.splice(m,1)[0].remove()),or(\"delSeries\",m)}n.delSeries=WN;const Ha=[!1,!1,!1,!1];function KN(m,O){if(m._show=m.show,m.show){let T=m.side%2,S=A[m.scale];S==null&&(m.scale=T?D[1].scale:N,S=A[m.scale]);let x=S.time;m.size=Ve(m.size),m.space=Ve(m.space),m.rotate=Ve(m.rotate),m.incrs=Ve(m.incrs||(S.distr==2?pX:x?R==1?mX:yX:hX)),m.splits=Ve(m.splits||(x&&S.distr==1?X:S.distr==3?Yg:S.distr==4?FX:LX)),m.stroke=Ve(m.stroke),m.grid.stroke=Ve(m.grid.stroke),m.ticks.stroke=Ve(m.ticks.stroke),m.border.stroke=Ve(m.border.stroke);let k=m.values;m.values=so(k)&&!so(k[0])?Ve(k):x?so(k)?q0(M,Y0(k,F)):z0(k)?wX(M,k):k||Q:k||kX,m.filter=Ve(m.filter||(S.distr>=3&&S.log==10?UX:HM)),m.font=l1(m.font),m.labelFont=l1(m.labelFont),m._size=m.size(n,null,O,0),m._space=m._rotate=m._incrs=m._found=m._splits=m._values=null,m._size>0&&(Ha[O]=!0,m._el=Dn(Sq,h))}}function cl(m,O,T,S){let[x,k,Y,J]=T,te=O%2,fe=0;return te==0&&(J||k)&&(fe=O==0&&!x||O==2&&!Y?qt(Z0.size/3):0),te==1&&(x||Y)&&(fe=O==1&&!k||O==3&&!J?qt(e1.size/2):0),fe}const oO=n.padding=(t.padding||[cl,cl,cl,cl]).map(m=>Ve(Ue(m,cl))),ea=n._padding=oO.map((m,O)=>m(n,O,Ha,0));let Gt,ir=null,ar=null;const lc=i==1?D[0].idxs:null;let Hn=null,uc=!1;function sO(m,O){if(e=m==null?[]:bo(m,U0),i==2){Gt=0;for(let T=1;T<D.length;T++)Gt+=e[T][0].length;n.data=e=m}else if(e[0]==null&&(e[0]=[]),n.data=e.slice(),Hn=e[0],Gt=Hn.length,E==2){e[0]=Array(Gt);for(let T=0;T<Gt;T++)e[0][T]=T}if(n._data=e,dl(!0),or(\"setData\"),E==2&&(Uo=!0),O!==!1){let T=j;T.auto(n,uc)?gh():Ko(N,T.min,T.max),Go=Se.left>=0,Vn=!0,za()}}n.setData=sO;function gh(){uc=!0;let m,O;i==1&&(Gt>0?(ir=lc[0]=0,ar=lc[1]=Gt-1,m=e[0][ir],O=e[0][ar],E==2?(m=ir,O=ar):Gt==1&&(E==3?[m,O]=eh(m,m,j.log,!1):E==4?[m,O]=Uy(m,m,j.log,!1):j.time?O=m+qt(86400/R):[m,O]=zd(m,O,Gy,!0))):(ir=lc[0]=m=null,ar=lc[1]=O=null)),Ko(N,m,O)}let cc,Wo,bh,yh,Oh,_h,wh,Th,Sh,fl;function lO(m,O,T,S,x,k){m!=null||(m=E0),T!=null||(T=UM),S!=null||(S=\"butt\"),x!=null||(x=E0),k!=null||(k=\"round\"),m!=cc&&(p.strokeStyle=cc=m),x!=Wo&&(p.fillStyle=Wo=x),O!=bh&&(p.lineWidth=bh=O),k!=Oh&&(p.lineJoin=Oh=k),S!=_h&&(p.lineCap=_h=S),T!=yh&&p.setLineDash(yh=T)}function uO(m,O,T,S){O!=Wo&&(p.fillStyle=Wo=O),m!=wh&&(p.font=wh=m),T!=Th&&(p.textAlign=Th=T),S!=Sh&&(p.textBaseline=Sh=S)}function Ph(m,O,T,S,x=0){if(S.length>0&&m.auto(n,uc)&&(O==null||O.min==null)){let k=Ue(ir,0),Y=Ue(ar,S.length-1),J=T.min==null?m.distr==3?Hq(S,k,Y):Vq(S,k,Y,x):[T.min,T.max];m.min=Wr(m.min,T.min=J[0]),m.max=Zt(m.max,T.max=J[1])}}function YN(){let m=bo(A,U0);for(let S in m){let x=m[S],k=$[S];if(k!=null&&k.min!=null)Bt(x,k),S==N&&dl(!0);else if(S!=N||i==2)if(Gt==0&&x.from==null){let Y=x.range(n,null,null,S);x.min=Y[0],x.max=Y[1]}else x.min=Le,x.max=-Le}if(Gt>0){D.forEach((S,x)=>{if(i==1){let k=S.scale,Y=m[k],J=$[k];if(x==0){let te=Y.range(n,Y.min,Y.max,k);Y.min=te[0],Y.max=te[1],ir=sa(Y.min,e[0]),ar=sa(Y.max,e[0]),e[0][ir]<Y.min&&ir++,e[0][ar]>Y.max&&ar--,S.min=Hn[ir],S.max=Hn[ar]}else S.show&&S.auto&&Ph(Y,J,S,e[x],S.sorted);S.idxs[0]=ir,S.idxs[1]=ar}else if(x>0&&S.show&&S.auto){let[k,Y]=S.facets,J=k.scale,te=Y.scale,[fe,Z]=e[x];Ph(m[J],$[J],k,fe,k.sorted),Ph(m[te],$[te],Y,Z,Y.sorted),S.min=Y.min,S.max=Y.max}});for(let S in m){let x=m[S],k=$[S];if(x.from==null&&(k==null||k.min==null)){let Y=x.range(n,x.min==Le?null:x.min,x.max==-Le?null:x.max,S);x.min=Y[0],x.max=Y[1]}}}for(let S in m){let x=m[S];if(x.from!=null){let k=m[x.from];if(k.min==null)x.min=x.max=null;else{let Y=x.range(n,k.min,k.max,S);x.min=Y[0],x.max=Y[1]}}}let O={},T=!1;for(let S in m){let x=m[S],k=A[S];if(k.min!=x.min||k.max!=x.max){k.min=x.min,k.max=x.max;let Y=k.distr;k._min=Y==3?Hi(k.min):Y==4?lm(k.min,k.asinh):k.min,k._max=Y==3?Hi(k.max):Y==4?lm(k.max,k.asinh):k.max,O[S]=T=!0}}if(T){D.forEach((S,x)=>{i==2?x>0&&O.y&&(S._paths=null):O[S.scale]&&(S._paths=null)});for(let S in O)Uo=!0,or(\"setScale\",S);Se.show&&Se.left>=0&&(Go=Vn=!0)}for(let S in $)$[S]=null}function qN(m){let O=j0(ir-1,0,Gt-1),T=j0(ar+1,0,Gt-1);for(;m[O]==null&&O>0;)O--;for(;m[T]==null&&T<Gt-1;)T++;return[O,T]}function XN(){Gt>0&&(D.forEach((m,O)=>{if(O>0&&m.show&&m._paths==null){let T=i==2?[0,e[O][0].length-1]:qN(e[O]);m._paths=m.paths(n,O,T[0],T[1])}}),D.forEach((m,O)=>{if(O>0&&m.show){fl!=m.alpha&&(p.globalAlpha=fl=m.alpha),cO(O,!1),m._paths&&fO(O,!1);{cO(O,!0);let T=m._paths?m._paths.gaps:null,S=m.points.show(n,O,ir,ar,T),x=m.points.filter(n,O,S,T);(S||x)&&(m.points._paths=m.points.paths(n,O,ir,ar,x),fO(O,!0))}fl!=1&&(p.globalAlpha=fl=1),or(\"drawSeries\",O)}}))}function cO(m,O){let T=O?D[m].points:D[m];T._stroke=T.stroke(n,m),T._fill=T.fill(n,m)}function fO(m,O){let T=O?D[m].points:D[m],S=T._stroke,x=T._fill,{stroke:k,fill:Y,clip:J,flags:te}=T._paths,fe=null,Z=lt(T.width*ze,3),ue=Z%2/2;O&&x==null&&(x=Z>0?\"#fff\":S);let Ce=T.pxAlign==1;if(Ce&&p.translate(ue,ue),!O){let Dt=Ut,xe=Br,ct=jn,ke=Va,qe=Z*ze/2;T.min==0&&(ke+=qe),T.max==0&&(xe-=qe,ke+=qe),fe=new Path2D,fe.rect(Dt,xe,ct,ke)}O?Eh(S,Z,T.dash,T.cap,x,k,Y,te,J):JN(m,S,Z,T.dash,T.cap,x,k,Y,te,fe,J),Ce&&p.translate(-ue,-ue)}function JN(m,O,T,S,x,k,Y,J,te,fe,Z){let ue=!1;V.forEach((Ce,Dt)=>{if(Ce.series[0]==m){let xe=D[Ce.series[1]],ct=e[Ce.series[1]],ke=(xe._paths||Ou).band;so(ke)&&(ke=Ce.dir==1?ke[0]:ke[1]);let qe,It=null;xe.show&&ke&&Uq(ct,ir,ar)?(It=Ce.fill(n,Dt)||k,qe=xe._paths.clip):ke=null,Eh(O,T,S,x,It,Y,J,te,fe,Z,qe,ke),ue=!0}}),ue||Eh(O,T,S,x,k,Y,J,te,fe,Z)}const dO=Mo|Wd;function Eh(m,O,T,S,x,k,Y,J,te,fe,Z,ue){lO(m,O,T,S,x),(te||fe||ue)&&(p.save(),te&&p.clip(te),fe&&p.clip(fe)),ue?(J&dO)==dO?(p.clip(ue),Z&&p.clip(Z),dc(x,Y),fc(m,k,O)):J&Wd?(dc(x,Y),p.clip(ue),fc(m,k,O)):J&Mo&&(p.save(),p.clip(ue),Z&&p.clip(Z),dc(x,Y),p.restore(),fc(m,k,O)):(dc(x,Y),fc(m,k,O)),(te||fe||ue)&&p.restore()}function fc(m,O,T){T>0&&(O instanceof Map?O.forEach((S,x)=>{p.strokeStyle=cc=x,p.stroke(S)}):O!=null&&m&&p.stroke(O))}function dc(m,O){O instanceof Map?O.forEach((T,S)=>{p.fillStyle=Wo=S,p.fill(T)}):O!=null&&m&&p.fill(O)}function ZN(m,O,T,S){let x=B[m],k;if(S<=0)k=[0,0];else{let Y=x._space=x.space(n,m,O,T,S),J=x._incrs=x.incrs(n,m,O,T,S,Y);k=fJ(O,T,J,S,Y)}return x._found=k}function $h(m,O,T,S,x,k,Y,J,te,fe){let Z=Y%2/2;P==1&&p.translate(Z,Z),lO(J,Y,te,fe,J),p.beginPath();let ue,Ce,Dt,xe,ct=x+(S==0||S==3?-k:k);T==0?(Ce=x,xe=ct):(ue=x,Dt=ct);for(let ke=0;ke<m.length;ke++)O[ke]!=null&&(T==0?ue=Dt=m[ke]:Ce=xe=m[ke],p.moveTo(ue,Ce),p.lineTo(Dt,xe));p.stroke(),P==1&&p.translate(-Z,-Z)}function QN(m){let O=!0;return B.forEach((T,S)=>{if(!T.show)return;let x=A[T.scale];if(x.min==null){T._show&&(O=!1,T._show=!1,dl(!1));return}else T._show||(O=!1,T._show=!0,dl(!1));let k=T.side,Y=k%2,{min:J,max:te}=x,[fe,Z]=ZN(S,J,te,Y==0?$e:Be);if(Z==0)return;let ue=x.distr==2,Ce=T._splits=T.splits(n,S,J,te,fe,Z,ue),Dt=x.distr==2?Ce.map(qe=>Hn[qe]):Ce,xe=x.distr==2?Hn[Ce[1]]-Hn[Ce[0]]:fe,ct=T._values=T.values(n,T.filter(n,Dt,S,Z,xe),S,Z,xe);T._rotate=k==2?T.rotate(n,ct,S,Z):0;let ke=T._size;T._size=Ud(T.size(n,ct,S,m)),ke!=null&&T._size!=ke&&(O=!1)}),O}function eI(m){let O=!0;return oO.forEach((T,S)=>{let x=T(n,S,Ha,m);x!=ea[S]&&(O=!1),ea[S]=x}),O}function tI(){for(let m=0;m<B.length;m++){let O=B[m];if(!O.show||!O._show)continue;let T=O.side,S=T%2,x,k,Y=O.stroke(n,m),J=T==0||T==3?-1:1;if(O.label){let zn=O.labelGap*J,$i=qt((O._lpos+zn)*ze);uO(O.labelFont[0],Y,\"center\",T==2?Ul:P0),p.save(),S==1?(x=k=0,p.translate($i,qt(Br+Va/2)),p.rotate((T==3?-Ff:Ff)/2)):(x=qt(Ut+jn/2),k=$i),p.fillText(O.label,x,k),p.restore()}let[te,fe]=O._found;if(fe==0)continue;let Z=A[O.scale],ue=S==0?jn:Va,Ce=S==0?Ut:Br,Dt=qt(O.gap*ze),xe=O._splits,ct=Z.distr==2?xe.map(zn=>Hn[zn]):xe,ke=Z.distr==2?Hn[xe[1]]-Hn[xe[0]]:te,qe=O.ticks,It=O.border,Fr=qe.show?qt(qe.size*ze):0,vt=O._rotate*-Ff/180,pr=C(O._pos*ze),jr=(Fr+Dt)*J,Tr=pr+jr;k=S==0?Tr:0,x=S==1?Tr:0;let an=O.font[0],ta=O.align==1?fs:O.align==2?om:vt>0?fs:vt<0?om:S==0?\"center\":T==3?om:fs,ra=vt||S==1?\"middle\":T==2?Ul:P0;uO(an,Y,ta,ra);let CO=O.font[1]*NX,yc=xe.map(zn=>C(l(zn,Z,ue,Ce))),DO=O._values;for(let zn=0;zn<DO.length;zn++){let $i=DO[zn];if($i!=null){S==0?x=yc[zn]:k=yc[zn],$i=\"\"+$i;let AO=$i.indexOf(`\n`)==-1?[$i]:$i.split(/\\n/gm);for(let _l=0;_l<AO.length;_l++){let RO=AO[_l];vt?(p.save(),p.translate(x,k+_l*CO),p.rotate(vt),p.fillText(RO,0,0),p.restore()):p.fillText(RO,x,k+_l*CO)}}}qe.show&&$h(yc,qe.filter(n,ct,m,fe,ke),S,T,pr,Fr,lt(qe.width*ze,3),qe.stroke(n,m),qe.dash,qe.cap);let Jo=O.grid;Jo.show&&$h(yc,Jo.filter(n,ct,m,fe,ke),S,S==0?2:1,S==0?Br:Ut,S==0?Va:jn,lt(Jo.width*ze,3),Jo.stroke(n,m),Jo.dash,Jo.cap),It.show&&$h([pr],[1],S==0?1:0,S==0?1:2,S==1?Br:Ut,S==1?Va:jn,lt(It.width*ze,3),It.stroke(n,m),It.dash,It.cap)}or(\"drawAxes\")}function dl(m){D.forEach((O,T)=>{T>0&&(O._paths=null,m&&(i==1?(O.min=null,O.max=null):O.facets.forEach(S=>{S.min=null,S.max=null})))})}let Ch=!1;function za(){Ch||(iX(rI),Ch=!0)}function rI(){hh&&(YN(),hh=!1),Uo&&(jN(),Uo=!1),ac&&(mt(b,fs,Ct),mt(b,Ul,zt),mt(b,ou,$e),mt(b,su,Be),mt(y,fs,Ct),mt(y,Ul,zt),mt(y,ou,$e),mt(y,su,Be),mt(h,ou,wr),mt(h,su,nn),d.width=qt(wr*ze),d.height=qt(nn*ze),B.forEach(({_el:m,_show:O,_size:T,_pos:S,side:x})=>{if(m!=null)if(O){let k=x===3||x===0?T:0,Y=x%2==1;mt(m,Y?\"left\":\"top\",S-k),mt(m,Y?\"width\":\"height\",T),mt(m,Y?\"top\":\"left\",Y?zt:Ct),mt(m,Y?\"height\":\"width\",Y?Be:$e),Wg(m,oo)}else cn(m,oo)}),cc=Wo=bh=Oh=_h=wh=Th=Sh=yh=null,fl=1,gc(!0),or(\"setSize\"),ac=!1),wr>0&&nn>0&&(p.clearRect(0,0,d.width,d.height),or(\"drawClear\"),H.forEach(m=>m()),or(\"draw\")),Lr.show&&vh&&(vc(Lr),vh=!1),Se.show&&Go&&(Ga(null,!0,!1),Go=!1),u||(u=!0,n.status=1,or(\"ready\")),uc=!1,Ch=!1}n.redraw=(m,O)=>{Uo=O||!1,m!==!1?Ko(N,j.min,j.max):za()};function Dh(m,O){let T=A[m];if(T.from==null){if(Gt==0){let S=T.range(n,O.min,O.max,m);O.min=S[0],O.max=S[1]}if(O.min>O.max){let S=O.min;O.min=O.max,O.max=S}if(Gt>1&&O.min!=null&&O.max!=null&&O.max-O.min<1e-16)return;m==N&&T.distr==2&&Gt>0&&(O.min=sa(O.min,e[0]),O.max=sa(O.max,e[0]),O.min==O.max&&O.max++),$[m]=O,hh=!0,za()}}n.setScale=Dh;let Ah,Rh,pc,hc,pO,hO,pl,hl,vO,mO,yt,Ot,Ua=!1;const dr=Se.drag;let Wt=dr.x,Kt=dr.y;Se.show&&(Se.x&&(Ah=Dn(Eq,y)),Se.y&&(Rh=Dn($q,y)),j.ori==0?(pc=Ah,hc=Rh):(pc=Rh,hc=Ah),yt=Se.left,Ot=Se.top);const Lr=n.select=Bt({show:!0,over:!0,left:0,width:0,top:0,height:0},t.select),vl=Lr.show?Dn(Pq,Lr.over?y:b):null;function vc(m,O){if(Lr.show){for(let T in m)Lr[T]=m[T],T in wO&&mt(vl,T,m[T]);O!==!1&&or(\"setSelect\")}}n.setSelect=vc;function nI(m,O){let T=D[m],S=le?Ie[m]:null;T.show?S&&Wg(S,oo):(S&&cn(S,oo),kr.length>1&&ds(kr[m],-10,-10,$e,Be))}function Ko(m,O,T){Dh(m,{min:O,max:T})}function oi(m,O,T,S){O.focus!=null&&lI(m),O.show!=null&&D.forEach((x,k)=>{k>0&&(m==k||m==null)&&(x.show=O.show,nI(k,O.show),Ko(i==2?x.facets[1].scale:x.scale,null,null),za())}),T!==!1&&or(\"setSeries\",m,O),S&&Ol(\"setSeries\",n,m,O)}n.setSeries=oi;function iI(m,O){Bt(V[m],O)}function aI(m,O){m.fill=Ve(m.fill||null),m.dir=Ue(m.dir,-1),O=O==null?V.length:O,V.splice(O,0,m)}function oI(m){m==null?V.length=0:V.splice(m,1)}n.addBand=aI,n.setBand=iI,n.delBand=oI;function sI(m,O){D[m].alpha=O,Se.show&&kr[m]&&(kr[m].style.opacity=O),le&&Ie[m]&&(Ie[m].style.opacity=O)}let ml,mc,gl;const Yo={focus:!0};function lI(m){if(m!=gl){let O=m==null,T=oc.alpha!=1;D.forEach((S,x)=>{let k=O||x==0||x==m;S._focus=O?null:k,T&&sI(x,k?1:oc.alpha)}),gl=m,T&&za()}}le&&sc&&mo(A0,me,m=>{Se._lock||gl!=null&&oi(null,Yo,!0,sr.setSeries)});function Ei(m,O,T){let S=A[O];T&&(m=m/ze-(S.ori==1?zt:Ct));let x=$e;S.ori==1&&(x=Be,m=x-m),S.dir==-1&&(m=x-m);let k=S._min,Y=S._max,J=m/x,te=k+(Y-k)*J,fe=S.distr;return fe==3?Ks(10,te):fe==4?Wq(te,S.asinh):te}function uI(m,O){let T=Ei(m,N,O);return sa(T,e[0],ir,ar)}n.valToIdx=m=>sa(m,e[0]),n.posToIdx=uI,n.posToVal=Ei,n.valToPos=(m,O,T)=>A[O].ori==0?o(m,A[O],T?jn:$e,T?Ut:0):s(m,A[O],T?Va:Be,T?Br:0);function cI(m){m(n),za()}n.batch=cI,n.setCursor=(m,O,T)=>{yt=m.left,Ot=m.top,Ga(null,O,T)};function gO(m,O){mt(vl,fs,Lr.left=m),mt(vl,ou,Lr.width=O)}function bO(m,O){mt(vl,Ul,Lr.top=m),mt(vl,su,Lr.height=O)}let bl=j.ori==0?gO:bO,yl=j.ori==1?gO:bO;function fI(){if(le&&U.live)for(let m=i==2?1:0;m<D.length;m++){if(m==0&&Re)continue;let O=U.values[m],T=0;for(let S in O)Te[m][T++].firstChild.nodeValue=O[S]}}function yO(m,O){if(m!=null){let T=m.idx;U.idx=T,D.forEach((S,x)=>{(x>0||!Re)&&OO(x,T)})}le&&U.live&&fI(),Vn=!1,O!==!1&&or(\"setLegend\")}n.setLegend=yO;function OO(m,O){let T;if(O==null)T=Qe;else{let S=D[m],x=m==0&&E==2?Hn:e[m];T=Re?S.values(n,m,O):{_:S.value(n,x[O],m,O)}}U.values[m]=T}function Ga(m,O,T){vO=yt,mO=Ot,[yt,Ot]=Se.move(n,yt,Ot),Se.show&&(pc&&ds(pc,qt(yt),0,$e,Be),hc&&ds(hc,0,qt(Ot),$e,Be));let S,x=ir>ar;ml=Le;let k=j.ori==0?$e:Be,Y=j.ori==1?$e:Be;if(yt<0||Gt==0||x){S=null;for(let J=0;J<D.length;J++)J>0&&kr.length>1&&ds(kr[J],-10,-10,$e,Be);if(sc&&oi(null,Yo,!0,m==null&&sr.setSeries),U.live){K.fill(null),Vn=!0;for(let J=0;J<D.length;J++)U.values[J]=Qe}}else{let J,te,fe;i==1&&(J=j.ori==0?yt:Ot,te=Ei(J,N),S=sa(te,e[0],ir,ar),fe=go(v(e[0][S],j,k,0),.5));for(let Z=i==2?1:0;Z<D.length;Z++){let ue=D[Z],Ce=K[Z],Dt=i==1?e[Z][Ce]:e[Z][1][Ce],xe=Se.dataIdx(n,Z,S,te),ct=i==1?e[Z][xe]:e[Z][1][xe];Vn=Vn||ct!=Dt||xe!=Ce,K[Z]=xe;let ke=xe==S?fe:go(v(i==1?e[0][xe]:e[Z][0][xe],j,k,0),.5);if(Z>0&&ue.show){let qe=ct==null?-10:go(w(ct,i==1?A[ue.scale]:A[ue.facets[1].scale],Y,0),.5);if(qe>0&&i==1){let vt=vr(qe-Ot);vt<=ml&&(ml=vt,mc=Z)}let It,Fr;if(j.ori==0?(It=ke,Fr=qe):(It=qe,Fr=ke),Vn&&kr.length>1){Fq(kr[Z],Se.points.fill(n,Z),Se.points.stroke(n,Z));let vt,pr,jr,Tr,an=!0,ta=Se.points.bbox;if(ta!=null){an=!1;let ra=ta(n,Z);jr=ra.left,Tr=ra.top,vt=ra.width,pr=ra.height}else jr=It,Tr=Fr,vt=pr=Se.points.size(n,Z);jq(kr[Z],vt,pr,an),ds(kr[Z],jr,Tr,$e,Be)}}if(U.live){if(!Vn||Z==0&&Re)continue;OO(Z,xe)}}}if(Se.idx=S,Se.left=yt,Se.top=Ot,Vn&&(U.idx=S,yO()),Lr.show&&Ua)if(m!=null){let[J,te]=sr.scales,[fe,Z]=sr.match,[ue,Ce]=m.cursor.sync.scales,Dt=m.cursor.drag;if(Wt=Dt._x,Kt=Dt._y,Wt||Kt){let{left:xe,top:ct,width:ke,height:qe}=m.select,It=m.scales[J].ori,Fr=m.posToVal,vt,pr,jr,Tr,an,ta=J!=null&&fe(J,ue),ra=te!=null&&Z(te,Ce);ta&&Wt?(It==0?(vt=xe,pr=ke):(vt=ct,pr=qe),jr=A[J],Tr=v(Fr(vt,ue),jr,k,0),an=v(Fr(vt+pr,ue),jr,k,0),bl(Wr(Tr,an),vr(an-Tr))):bl(0,k),ra&&Kt?(It==1?(vt=xe,pr=ke):(vt=ct,pr=qe),jr=A[te],Tr=w(Fr(vt,Ce),jr,Y,0),an=w(Fr(vt+pr,Ce),jr,Y,0),yl(Wr(Tr,an),vr(an-Tr))):yl(0,Y)}else Mh()}else{let J=vr(vO-pO),te=vr(mO-hO);if(j.ori==1){let Ce=J;J=te,te=Ce}Wt=dr.x&&J>=dr.dist,Kt=dr.y&&te>=dr.dist;let fe=dr.uni;fe!=null?Wt&&Kt&&(Wt=J>=fe,Kt=te>=fe,!Wt&&!Kt&&(te>J?Kt=!0:Wt=!0)):dr.x&&dr.y&&(Wt||Kt)&&(Wt=Kt=!0);let Z,ue;Wt&&(j.ori==0?(Z=pl,ue=yt):(Z=hl,ue=Ot),bl(Wr(Z,ue),vr(ue-Z)),Kt||yl(0,Y)),Kt&&(j.ori==1?(Z=pl,ue=yt):(Z=hl,ue=Ot),yl(Wr(Z,ue),vr(ue-Z)),Wt||bl(0,k)),!Wt&&!Kt&&(bl(0,0),yl(0,0))}if(dr._x=Wt,dr._y=Kt,m==null){if(T){if($O!=null){let[J,te]=sr.scales;sr.values[0]=J!=null?Ei(j.ori==0?yt:Ot,J):null,sr.values[1]=te!=null?Ei(j.ori==1?yt:Ot,te):null}Ol($0,n,yt,Ot,$e,Be,S)}if(sc){let J=T&&sr.setSeries,te=oc.prox;gl==null?ml<=te&&oi(mc,Yo,!0,J):ml>te?oi(null,Yo,!0,J):mc!=gl&&oi(mc,Yo,!0,J)}}O!==!1&&or(\"setCursor\")}let qo=null;function gc(m){m===!0?qo=null:(qo=y.getBoundingClientRect(),or(\"syncRect\",qo))}function _O(m,O,T,S,x,k,Y){Se._lock||(xh(m,O,T,S,x,k,Y,!1,m!=null),m!=null?Ga(null,!0,!0):Ga(O,!0,!1))}function xh(m,O,T,S,x,k,Y,J,te){if(qo==null&&gc(!1),m!=null)T=m.clientX-qo.left,S=m.clientY-qo.top;else{if(T<0||S<0){yt=-10,Ot=-10;return}let[fe,Z]=sr.scales,ue=O.cursor.sync,[Ce,Dt]=ue.values,[xe,ct]=ue.scales,[ke,qe]=sr.match,It=O.axes[0].side%2==1,Fr=j.ori==0?$e:Be,vt=j.ori==1?$e:Be,pr=It?k:x,jr=It?x:k,Tr=It?S:T,an=It?T:S;if(xe!=null?T=ke(fe,xe)?l(Ce,A[fe],Fr,0):-10:T=Fr*(Tr/pr),ct!=null?S=qe(Z,ct)?l(Dt,A[Z],vt,0):-10:S=vt*(an/jr),j.ori==1){let ta=T;T=S,S=ta}}te&&((T<=1||T>=$e-1)&&(T=ro(T,$e)),(S<=1||S>=Be-1)&&(S=ro(S,Be))),J?(pO=T,hO=S,[pl,hl]=Se.move(n,T,S)):(yt=T,Ot=S)}const wO={width:0,height:0,left:0,top:0};function Mh(){vc(wO,!1)}function TO(m,O,T,S,x,k,Y){Ua=!0,Wt=Kt=dr._x=dr._y=!1,xh(m,O,T,S,x,k,Y,!0,!1),m!=null&&(En(sm,Ug,SO),Ol(C0,n,pl,hl,$e,Be,null))}function SO(m,O,T,S,x,k,Y){Ua=dr._x=dr._y=!1,xh(m,O,T,S,x,k,Y,!1,!0);let{left:J,top:te,width:fe,height:Z}=Lr,ue=fe>0||Z>0;if(ue&&vc(Lr),dr.setScale&&ue){let Ce=J,Dt=fe,xe=te,ct=Z;if(j.ori==1&&(Ce=te,Dt=Z,xe=J,ct=fe),Wt&&Ko(N,Ei(Ce,N),Ei(Ce+Dt,N)),Kt)for(let ke in A){let qe=A[ke];ke!=N&&qe.from==null&&qe.min!=Le&&Ko(ke,Ei(xe+ct,ke),Ei(xe,ke))}Mh()}else Se.lock&&(Se._lock=!Se._lock,Se._lock||Ga(null,!0,!1));m!=null&&(Ye(sm,Ug),Ol(sm,n,yt,Ot,$e,Be,null))}function dI(m,O,T,S,x,k,Y){if(!Se._lock){let J=Ua;if(Ua){let te=!0,fe=!0,Z=10,ue,Ce;j.ori==0?(ue=Wt,Ce=Kt):(ue=Kt,Ce=Wt),ue&&Ce&&(te=yt<=Z||yt>=$e-Z,fe=Ot<=Z||Ot>=Be-Z),ue&&te&&(yt=yt<pl?0:$e),Ce&&fe&&(Ot=Ot<hl?0:Be),Ga(null,!0,!0),Ua=!1}yt=-10,Ot=-10,Ga(null,!0,!0),J&&(Ua=J)}}function PO(m,O,T,S,x,k,Y){gh(),Mh(),m!=null&&Ol(R0,n,yt,Ot,$e,Be,null)}function EO(){B.forEach(dJ),mh(n.width,n.height,!0)}mo(Hd,Rs,EO);const Xo={};Xo.mousedown=TO,Xo.mousemove=_O,Xo.mouseup=SO,Xo.dblclick=PO,Xo.setSeries=(m,O,T,S)=>{oi(T,S,!0,!1)},Se.show&&(En(C0,y,TO),En($0,y,_O),En(D0,y,gc),En(A0,y,dI),En(R0,y,PO),qg.add(n),n.syncRect=gc);const bc=n.hooks=t.hooks||{};function or(m,O,T){m in bc&&bc[m].forEach(S=>{S.call(null,n,O,T)})}(t.plugins||[]).forEach(m=>{for(let O in m.hooks)bc[O]=(bc[O]||[]).concat(m.hooks[O])});const sr=Bt({key:null,setSeries:!1,filters:{pub:V0,sub:V0},scales:[N,D[1]?D[1].scale:null],match:[H0,H0],values:[null,null]},Se.sync);Se.sync=sr;const $O=sr.key,Nh=sN($O);function Ol(m,O,T,S,x,k,Y){sr.filters.pub(m,O,T,S,x,k,Y)&&Nh.pub(m,O,T,S,x,k,Y)}Nh.sub(n);function pI(m,O,T,S,x,k,Y){sr.filters.sub(m,O,T,S,x,k,Y)&&Xo[m](null,O,T,S,x,k,Y)}n.pub=pI;function hI(){Nh.unsub(n),qg.delete(n),Pi.clear(),Kg(Hd,Rs,EO),f.remove(),me==null||me.remove(),or(\"destroy\")}n.destroy=hI;function Ih(){or(\"init\",t,e),sO(e||t.data,!1),$[N]?Dh(N,$[N]):gh(),vh=Lr.show,Go=Vn=!0,mh(t.width,t.height)}return D.forEach(aO),B.forEach(KN),r?r instanceof HTMLElement?(r.appendChild(f),Ih()):r(n,Ih):Ih(),n}cr.assign=Bt;cr.fmtNum=Wy;cr.rangeNum=zd;cr.rangeLog=eh;cr.rangeAsinh=Uy;cr.orient=Vo;cr.pxRatio=ze;cr.join=nX;cr.fmtDate=Ky,cr.tzDate=fX;cr.sync=sN;{cr.addGap=XX,cr.clipGaps=ih;let t=cr.paths={points:pN};t.linear=vN,t.stepped=QX,t.bars=eJ,t.spline=rJ}const pJ={data(){return{timer:Number}},async mounted(){let e=new Proxy(new URLSearchParams(window.location.search),{get:(l,u)=>l.get(u)}).access_token;e&&localStorage.setItem(\"token\",e);const r={width:960,height:400,cursor:{drag:{setScale:!1}},select:{show:!1},series:[{value:\"{YYYY}/{MM}/{DD} {HH}:{mm}:{ss}\"},{label:this.$t(\"Publish TPS\"),show:!0,scale:\"s\",width:2,value:(l,u)=>u==null?\"-\":u.toFixed(1)+\"/s\",stroke:\"rgba(0,255,0,0.3)\"},{label:this.$t(\"Consume TPS\"),show:!0,scale:\"s\",width:2,value:(l,u)=>u==null?\"-\":u.toFixed(1)+\"/s\",stroke:\"rgba(255,0,0,0.3)\"},{label:this.$t(\"Subscriber Invoke Time\"),scale:\"ms\",width:1,paths:l=>null,points:{space:0,stroke:\"blue\"},value:(l,u)=>u==null?\"-\":u.toFixed(0)+\"ms\",stroke:\"blue\"}],axes:[{space:30,values:[[1,\"{mm}:{ss}\",`\n{YY}/{M}/{D}/ {HH}:{mm}`,null,`\n{M}/{D} {HH}:{mm}`,null,`\n{HH}:{mm}`,null,1]]},{scale:\"s\",label:this.$t(\"Rate (TPS)\"),ticks:{show:!0,stroke:\"#eee\",width:10,dash:[5],size:5},values:(l,u)=>u.map(f=>f+\"/s\"),incrs:[1,5,10,30,50,100]},{side:1,scale:\"ms\",label:this.$t(\"Elpsed Time (ms)\"),size:60,ticks:{show:!0,stroke:\"#eee\",width:10,dash:[5],size:5},incrs:[1,10,50,100,300,500,1e3],values:(l,u,f)=>u.map(d=>+d.toFixed(0)+\"ms\"),grid:{show:!1}}]};var n=[];async function i(){await Xi.get(\"/metrics-realtime\").then(l=>{n=l.data})}await i();let a=new cr(r,n,document.getElementById(\"realtimeGraph\"));this.timer=setInterval(async function(){await i(),a.setData(n)},1e3);var o=[];await Xi.get(\"/metrics-history\").then(l=>{o.push(l.data.dayHour),o.push(l.data.publishSuccessed),o.push(l.data.subscribeSuccessed),o.push(l.data.publishFailed),o.push(l.data.subscribeFailed)});var s={width:960,height:400,cursor:{drag:{setScale:!1}},select:{show:!1},series:[{value:\"{YYYY}/{MM}/{DD} {HH}:00\"},{label:this.$t(\"Publish Succeeded\"),fill:\"rgba(0,255,0,0.3)\"},{label:this.$t(\"Received Succeeded\"),fill:\"rgba(0,0,255,0.3)\"},{label:this.$t(\"Publish Failed\"),fill:\"rgba(255,0,0,0.5)\"},{label:this.$t(\"Received Failed\"),fill:\"rgba(255,255,0,0.5)\"}],axes:[{space:30,values:[[60,\"{HH}:00\",`\n{YYYY}/{M}/{D}`,null,`\n{M}/{D}`,null,null,null,1]]},{label:this.$t(\"Aggregation Count\")}]};new cr(s,o,document.getElementById(\"historyGraph\"))},destroyed(){window.clearInterval(this.timer)}};var hJ=function(){var e=this,r=e._self._c;return r(\"b-container\",[r(\"h2\",{staticClass:\"page-line mb-4\"},[e._v(e._s(e.$t(\"Dashboard\")))]),r(\"b-row\",[r(\"b-col\",[r(\"h3\",{staticClass:\"mb-4\"},[e._v(e._s(e.$t(\"Realtime Metric Graph\")))]),r(\"div\",{attrs:{id:\"realtimeGraph\"}}),r(\"p\",{staticClass:\"text-secondary\"},[e._v(e._s(e.$t(\"SubscriberInvokeMeanTime\")))])])],1),r(\"b-row\",[r(\"b-col\",[r(\"h3\",{staticClass:\"mt-4\"},[e._v(e._s(e.$t(\"24h History Graph\")))]),r(\"div\",{attrs:{id:\"historyGraph\"}})])],1)],1)},vJ=[],mJ=Up(pJ,hJ,vJ,!1,null,null,null,null);const gJ=mJ.exports;ye.use(FM);const bJ=[{path:\"/\",name:\"Home\",component:gJ},{path:\"/published/:status\",name:\"Published\",props:!0,component:()=>qc(()=>import(\"./Published.a8d638e6.js\"),[\"./Published.a8d638e6.js\",\"./index.2d8714a6.js\",\"./Published.429cfade.css\"],import.meta.url)},{path:\"/published\",redirect:\"/published/succeeded\"},{path:\"/received/:status\",name:\"Received\",props:!0,component:()=>qc(()=>import(\"./Received.e36ea621.js\"),[\"./Received.e36ea621.js\",\"./index.2d8714a6.js\",\"./Received.37160321.css\"],import.meta.url)},{path:\"/received\",redirect:\"/received/succeeded\"},{path:\"/subscriber\",name:\"Subscriber\",component:()=>qc(()=>import(\"./Subscriber.d66f9645.js\"),[\"./Subscriber.d66f9645.js\",\"./Subscriber.300bed2c.css\"],import.meta.url)},{path:\"/nodes\",name:\"Nodes\",component:()=>qc(()=>import(\"./Nodes.e12132f5.js\"),[\"./Nodes.e12132f5.js\",\"./Nodes.40464ac3.css\"],import.meta.url)}],yJ=new FM({routes:bJ});var yN={exports:{}};(function(t,e){(function(r,n){t.exports=n()})(PK,function(){return function(){var r={228:function(a){a.exports=function(o,s){(s==null||s>o.length)&&(s=o.length);for(var l=0,u=new Array(s);l<s;l++)u[l]=o[l];return u}},858:function(a){a.exports=function(o){if(Array.isArray(o))return o}},646:function(a,o,s){var l=s(228);a.exports=function(u){if(Array.isArray(u))return l(u)}},713:function(a){a.exports=function(o,s,l){return s in o?Object.defineProperty(o,s,{value:l,enumerable:!0,configurable:!0,writable:!0}):o[s]=l,o}},860:function(a){a.exports=function(o){if(typeof Symbol<\"u\"&&Symbol.iterator in Object(o))return Array.from(o)}},884:function(a){a.exports=function(o,s){if(typeof Symbol<\"u\"&&Symbol.iterator in Object(o)){var l=[],u=!0,f=!1,d=void 0;try{for(var p,h=o[Symbol.iterator]();!(u=(p=h.next()).done)&&(l.push(p.value),!s||l.length!==s);u=!0);}catch(b){f=!0,d=b}finally{try{u||h.return==null||h.return()}finally{if(f)throw d}}return l}}},521:function(a){a.exports=function(){throw new TypeError(`Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}},206:function(a){a.exports=function(){throw new TypeError(`Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}},38:function(a,o,s){var l=s(858),u=s(884),f=s(379),d=s(521);a.exports=function(p,h){return l(p)||u(p,h)||f(p,h)||d()}},319:function(a,o,s){var l=s(646),u=s(860),f=s(379),d=s(206);a.exports=function(p){return l(p)||u(p)||f(p)||d()}},8:function(a){function o(s){return typeof Symbol==\"function\"&&typeof Symbol.iterator==\"symbol\"?a.exports=o=function(l){return typeof l}:a.exports=o=function(l){return l&&typeof Symbol==\"function\"&&l.constructor===Symbol&&l!==Symbol.prototype?\"symbol\":typeof l},o(s)}a.exports=o},379:function(a,o,s){var l=s(228);a.exports=function(u,f){if(u){if(typeof u==\"string\")return l(u,f);var d=Object.prototype.toString.call(u).slice(8,-1);return d===\"Object\"&&u.constructor&&(d=u.constructor.name),d===\"Map\"||d===\"Set\"?Array.from(u):d===\"Arguments\"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(d)?l(u,f):void 0}}},569:function(a,o,s){s.r(o),s.d(o,{default:function(){return E}});var l=s(38),u=s.n(l),f=s(319),d=s.n(f),p=s(713),h=s.n(p);function b(v,w,$,M,F,X,Q,q){var K,U=typeof v==\"function\"?v.options:v;if(w&&(U.render=w,U.staticRenderFns=$,U._compiled=!0),M&&(U.functional=!0),X&&(U._scopeId=\"data-v-\"+X),Q?(K=function(me){(me=me||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||typeof __VUE_SSR_CONTEXT__>\"u\"||(me=__VUE_SSR_CONTEXT__),F&&F.call(this,me),me&&me._registeredComponents&&me._registeredComponents.add(Q)},U._ssrRegister=K):F&&(K=q?function(){F.call(this,(U.functional?this.parent:this).$root.$options.shadowRoot)}:F),K)if(U.functional){U._injectStyles=K;var le=U.render;U.render=function(me,Ie){return K.call(Ie),le(me,Ie)}}else{var be=U.beforeCreate;U.beforeCreate=be?[].concat(be,K):[K]}return{exports:v,options:U}}var y=b({props:{data:{required:!0,type:String}},methods:{toggleBrackets:function(v){this.$emit(\"click\",v)}}},function(){var v=this,w=v.$createElement;return(v._self._c||w)(\"span\",{staticClass:\"vjs-tree-brackets\",on:{click:function($){return $.stopPropagation(),v.toggleBrackets($)}}},[v._v(v._s(v.data))])},[],!1,null,null,null).exports,P=b({props:{checked:{type:Boolean,default:!1},isMultiple:Boolean},computed:{uiType:function(){return this.isMultiple?\"checkbox\":\"radio\"},model:{get:function(){return this.checked},set:function(v){this.$emit(\"input\",v)}}}},function(){var v=this,w=v.$createElement,$=v._self._c||w;return $(\"label\",{class:[\"vjs-check-controller\",v.checked?\"is-checked\":\"\"],on:{click:function(M){M.stopPropagation()}}},[$(\"span\",{class:\"vjs-check-controller-inner is-\"+v.uiType}),$(\"input\",{class:\"vjs-check-controller-original is-\"+v.uiType,attrs:{type:v.uiType},domProps:{checked:v.model},on:{change:function(M){return v.$emit(\"change\",v.model)}}})])},[],!1,null,null,null).exports,C=b({props:{nodeType:{type:String,required:!0}},computed:{isOpen:function(){return this.nodeType===\"objectStart\"||this.nodeType===\"arrayStart\"},isClose:function(){return this.nodeType===\"objectCollapsed\"||this.nodeType===\"arrayCollapsed\"}},methods:{handleClick:function(){this.$emit(\"click\")}}},function(){var v=this,w=v.$createElement,$=v._self._c||w;return v.isOpen||v.isClose?$(\"span\",{class:\"vjs-carets vjs-carets-\"+(v.isOpen?\"open\":\"close\"),on:{click:v.handleClick}},[$(\"svg\",{attrs:{viewBox:\"0 0 1024 1024\",focusable:\"false\",\"data-icon\":\"caret-down\",width:\"1em\",height:\"1em\",fill:\"currentColor\",\"aria-hidden\":\"true\"}},[$(\"path\",{attrs:{d:\"M840.4 300H183.6c-19.7 0-30.7 20.8-18.5 35l328.4 380.8c9.4 10.9 27.5 10.9 37 0L858.9 335c12.2-14.2 1.2-35-18.5-35z\"}})])]):v._e()},[],!1,null,null,null).exports,R=s(8),D=s.n(R);function B(v){return Object.prototype.toString.call(v).slice(8,-1).toLowerCase()}function A(v){var w=arguments.length>1&&arguments[1]!==void 0?arguments[1]:\"root\",$=arguments.length>2&&arguments[2]!==void 0?arguments[2]:0,M=arguments.length>3&&arguments[3]!==void 0?arguments[3]:{},F=M.key,X=M.index,Q=M.type,q=Q===void 0?\"content\":Q,K=M.showComma,U=K!==void 0&&K,le=M.length,be=le===void 0?1:le,me=B(v);if(me===\"array\"){var Ie=V(v.map(function(Re,Qe,Ir){return A(Re,\"\".concat(w,\"[\").concat(Qe,\"]\"),$+1,{index:Qe,showComma:Qe!==Ir.length-1,length:be,type:q})}));return[A(\"[\",w,$,{key:F,length:v.length,type:\"arrayStart\"})[0]].concat(Ie,A(\"]\",w,$,{showComma:U,length:v.length,type:\"arrayEnd\"})[0])}if(me===\"object\"){var Te=Object.keys(v),$t=V(Te.map(function(Re,Qe,Ir){return A(v[Re],/^[a-zA-Z_]\\w*$/.test(Re)?\"\".concat(w,\".\").concat(Re):\"\".concat(w,'[\"').concat(Re,'\"]'),$+1,{key:Re,showComma:Qe!==Ir.length-1,length:be,type:q})}));return[A(\"{\",w,$,{key:F,index:X,length:Te.length,type:\"objectStart\"})[0]].concat($t,A(\"}\",w,$,{showComma:U,length:Te.length,type:\"objectEnd\"})[0])}return[{content:v,level:$,key:F,index:X,path:w,showComma:U,length:be,type:q}]}function V(v){if(typeof Array.prototype.flat==\"function\")return v.flat();for(var w=d()(v),$=[];w.length;){var M=w.shift();Array.isArray(M)?w.unshift.apply(w,d()(M)):$.push(M)}return $}function N(v){var w=arguments.length>1&&arguments[1]!==void 0?arguments[1]:new WeakMap;if(v==null)return v;if(v instanceof Date)return new Date(v);if(v instanceof RegExp)return new RegExp(v);if(D()(v)!==\"object\")return v;if(w.get(v))return w.get(v);if(Array.isArray(v)){var $=v.map(function(X){return N(X,w)});return w.set(v,$),$}var M={};for(var F in v)M[F]=N(v[F],w);return w.set(v,M),M}var G=b({components:{Brackets:y,CheckController:P,Carets:C},props:{node:{required:!0,type:Object},collapsed:Boolean,showDoubleQuotes:Boolean,showLength:Boolean,checked:Boolean,selectableType:{type:String,default:\"\"},showSelectController:{type:Boolean,default:!1},showLine:{type:Boolean,default:!0},showLineNumber:{type:Boolean,default:!1},selectOnClickNode:{type:Boolean,default:!0},nodeSelectable:{type:Function,default:function(){return!0}},highlightSelectedNode:{type:Boolean,default:!0},showIcon:{type:Boolean,default:!1},showKeyValueSpace:{type:Boolean,default:!0},editable:{type:Boolean,default:!1},editableTrigger:{type:String,default:\"click\"}},data:function(){return{editing:!1}},computed:{valueClass:function(){return\"vjs-value vjs-value-\".concat(this.dataType)},dataType:function(){return B(this.node.content)},prettyKey:function(){return this.showDoubleQuotes?'\"'.concat(this.node.key,'\"'):this.node.key},selectable:function(){return this.nodeSelectable(this.node)&&(this.isMultiple||this.isSingle)},isMultiple:function(){return this.selectableType===\"multiple\"},isSingle:function(){return this.selectableType===\"single\"},defaultValue:function(){var v,w=(v=this.node)===null||v===void 0?void 0:v.content;return w==null&&(w+=\"\"),this.dataType===\"string\"?'\"'.concat(w,'\"'):w}},methods:{handleInputChange:function(v){var w,$,M=($=(w=v.target)===null||w===void 0?void 0:w.value)===\"null\"?null:$===\"undefined\"?void 0:$===\"true\"||$!==\"false\"&&($[0]+$[$.length-1]==='\"\"'||$[0]+$[$.length-1]===\"''\"?$.slice(1,-1):typeof Number($)==\"number\"&&!isNaN(Number($))||$===\"NaN\"?Number($):$);this.$emit(\"value-change\",M,this.node.path)},handleIconClick:function(){this.$emit(\"icon-click\",!this.collapsed,this.node.path)},handleBracketsClick:function(){this.$emit(\"brackets-click\",!this.collapsed,this.node.path)},handleSelectedChange:function(){this.$emit(\"selected-change\",this.node)},handleNodeClick:function(){this.$emit(\"node-click\",this.node),this.selectable&&this.selectOnClickNode&&this.$emit(\"selected-change\",this.node)},handleValueEdit:function(v){var w=this;if(this.editable&&!this.editing){this.editing=!0;var $=function M(F){var X;F.target!==v.target&&((X=F.target)===null||X===void 0?void 0:X.parentElement)!==v.target&&(w.editing=!1,document.removeEventListener(\"click\",M))};document.removeEventListener(\"click\",$),document.addEventListener(\"click\",$)}}}},function(){var v=this,w=v.$createElement,$=v._self._c||w;return $(\"div\",{class:{\"vjs-tree-node\":!0,\"has-selector\":v.showSelectController,\"has-carets\":v.showIcon,\"is-highlight\":v.highlightSelectedNode&&v.checked},on:{click:v.handleNodeClick}},[v.showLineNumber?$(\"span\",{staticClass:\"vjs-node-index\"},[v._v(`\n    `+v._s(v.node.id+1)+`\n  `)]):v._e(),v.showSelectController&&v.selectable&&v.node.type!==\"objectEnd\"&&v.node.type!==\"arrayEnd\"?$(\"check-controller\",{attrs:{\"is-multiple\":v.isMultiple,checked:v.checked},on:{change:v.handleSelectedChange}}):v._e(),$(\"div\",{staticClass:\"vjs-indent\"},[v._l(v.node.level,function(M,F){return $(\"div\",{key:F,class:{\"vjs-indent-unit\":!0,\"has-line\":v.showLine}})}),v.showIcon?$(\"carets\",{attrs:{\"node-type\":v.node.type},on:{click:v.handleIconClick}}):v._e()],2),v.node.key?$(\"span\",{staticClass:\"vjs-key\"},[v._t(\"key\",[v._v(v._s(v.prettyKey))],{node:v.node,defaultKey:v.prettyKey}),$(\"span\",{staticClass:\"vjs-colon\"},[v._v(v._s(\":\"+(v.showKeyValueSpace?\" \":\"\")))])],2):v._e(),$(\"span\",[v.node.type!==\"content\"?$(\"brackets\",{attrs:{data:v.node.content},on:{click:v.handleBracketsClick}}):$(\"span\",{class:v.valueClass,on:{click:function(M){!v.editable||v.editableTrigger&&v.editableTrigger!==\"click\"||v.handleValueEdit(M)},dblclick:function(M){v.editable&&v.editableTrigger===\"dblclick\"&&v.handleValueEdit(M)}}},[v.editable&&v.editing?$(\"input\",{style:{padding:\"3px 8px\",border:\"1px solid #eee\",boxShadow:\"none\",boxSizing:\"border-box\",borderRadius:5,fontFamily:\"inherit\"},domProps:{value:v.defaultValue},on:{change:v.handleInputChange}}):v._t(\"value\",[v._v(v._s(v.defaultValue))],{node:v.node,defaultValue:v.defaultValue})],2),v.node.showComma?$(\"span\",[v._v(\",\")]):v._e(),v.showLength&&v.collapsed?$(\"span\",{staticClass:\"vjs-comment\"},[v._v(\" // \"+v._s(v.node.length)+\" items \")]):v._e()],1)],1)},[],!1,null,null,null);function H(v,w){var $=Object.keys(v);if(Object.getOwnPropertySymbols){var M=Object.getOwnPropertySymbols(v);w&&(M=M.filter(function(F){return Object.getOwnPropertyDescriptor(v,F).enumerable})),$.push.apply($,M)}return $}function W(v){for(var w=1;w<arguments.length;w++){var $=arguments[w]!=null?arguments[w]:{};w%2?H(Object($),!0).forEach(function(M){h()(v,M,$[M])}):Object.getOwnPropertyDescriptors?Object.defineProperties(v,Object.getOwnPropertyDescriptors($)):H(Object($)).forEach(function(M){Object.defineProperty(v,M,Object.getOwnPropertyDescriptor($,M))})}return v}var j=b({name:\"VueJsonPretty\",components:{TreeNode:G.exports},model:{prop:\"data\"},props:{collapsedNodeLength:{type:Number,default:1/0},data:{type:[String,Number,Boolean,Array,Object],default:null},deep:{type:Number,default:1/0},rootPath:{type:String,default:\"root\"},virtual:{type:Boolean,default:!1},height:{type:Number,default:400},itemHeight:{type:Number,default:20},showLength:{type:Boolean,default:!1},showDoubleQuotes:{type:Boolean,default:!0},selectableType:{type:String,default:\"\"},showSelectController:{type:Boolean,default:!1},showLine:{type:Boolean,default:!0},showLineNumber:{type:Boolean,default:!1},selectOnClickNode:{type:Boolean,default:!0},selectedValue:{type:[Array,String],default:function(){return\"\"}},nodeSelectable:{type:Function,default:function(){return!0}},highlightSelectedNode:{type:Boolean,default:!0},collapsedOnClickBrackets:{type:Boolean,default:!0},showIcon:{type:Boolean,default:!1},showKeyValueSpace:{type:Boolean,default:!0},editable:{type:Boolean,default:!1},editableTrigger:{type:String,default:\"click\"}},data:function(){return{translateY:0,visibleData:null,hiddenPaths:this.initHiddenPaths(A(this.data,this.rootPath),this.deep,this.collapsedNodeLength)}},computed:{originFlatData:function(){return A(this.data,this.rootPath)},flatData:function(v){for(var w=v.originFlatData,$=v.hiddenPaths,M=null,F=[],X=w.length,Q=0;Q<X;Q++){var q=W(W({},w[Q]),{},{id:Q}),K=$[q.path];if(M&&M.path===q.path){var U=M.type===\"objectStart\",le=W(W(W({},q),M),{},{showComma:q.showComma,content:U?\"{...}\":\"[...]\",type:U?\"objectCollapsed\":\"arrayCollapsed\"});M=null,F.push(le)}else{if(K&&!M){M=q;continue}if(M)continue;F.push(q)}}return F},selectedPaths:{get:function(){var v=this.selectedValue;return v&&this.selectableType===\"multiple\"&&Array.isArray(v)?v:[v]},set:function(v){this.$emit(\"update:selectedValue\",v)}},propsError:function(){return!this.selectableType||this.selectOnClickNode||this.showSelectController?\"\":\"When selectableType is not null, selectOnClickNode and showSelectController cannot be false at the same time, because this will cause the selection to fail.\"}},watch:{propsError:{handler:function(v){if(v)throw new Error(\"[VueJsonPretty] \".concat(v))},immediate:!0},flatData:{handler:function(v){this.updateVisibleData(v)},immediate:!0},deep:{handler:function(v){this.hiddenPaths=this.initHiddenPaths(this.originFlatData,v,this.collapsedNodeLength)}},collapsedNodeLength:{handler:function(v){this.hiddenPaths=this.initHiddenPaths(this.originFlatData,this.deep,v)}}},methods:{initHiddenPaths:function(v,w,$){return v.reduce(function(M,F){var X=F.level>=w||F.length>=$;return F.type!==\"objectStart\"&&F.type!==\"arrayStart\"||!X?M:W(W({},M),{},h()({},F.path,1))},{})},updateVisibleData:function(v){if(this.virtual){var w=this.height/this.itemHeight,$=this.$refs.tree&&this.$refs.tree.scrollTop||0,M=Math.floor($/this.itemHeight),F=M<0?0:M+w>v.length?v.length-w:M;F<0&&(F=0);var X=F+w;this.translateY=F*this.itemHeight,this.visibleData=v.filter(function(Q,q){return q>=F&&q<X})}else this.visibleData=v},handleTreeScroll:function(){this.updateVisibleData(this.flatData)},handleSelectedChange:function(v){var w=v.path,$=this.selectableType;if($===\"multiple\"){var M=this.selectedPaths.findIndex(function(q){return q===w}),F=d()(this.selectedPaths);M!==-1?this.selectedPaths.splice(M,1):this.selectedPaths.push(w),this.$emit(\"selected-change\",this.selectedPaths,F)}else if($===\"single\"&&this.selectedPaths[0]!==w){var X=u()(this.selectedPaths,1)[0],Q=w;this.selectedPaths=Q,this.$emit(\"selected-change\",Q,X)}},handleNodeClick:function(v){this.$emit(\"node-click\",v)},updateCollapsedPaths:function(v,w){if(v)this.hiddenPaths=W(W({},this.hiddenPaths),{},h()({},w,1));else{var $=W({},this.hiddenPaths);delete $[w],this.hiddenPaths=$}},handleBracketsClick:function(v,w){this.collapsedOnClickBrackets&&this.updateCollapsedPaths(v,w),this.$emit(\"brackets-click\",v)},handleIconClick:function(v,w){this.updateCollapsedPaths(v,w),this.$emit(\"icon-click\",v)},handleValueChange:function(v,w){var $=N(this.data),M=this.rootPath;new Function(\"data\",\"val\",\"data\".concat(w.slice(M.length),\"=val\"))($,v),this.$emit(\"input\",$)}}},function(){var v=this,w=v.$createElement,$=v._self._c||w;return $(\"div\",{ref:\"tree\",class:{\"vjs-tree\":!0,\"is-virtual\":v.virtual},style:v.showLineNumber?{paddingLeft:12*Number(v.originFlatData.length.toString().length)+\"px\"}:{},on:{scroll:function(M){v.virtual&&v.handleTreeScroll()}}},[$(\"div\",{staticClass:\"vjs-tree-list\",style:v.virtual&&{height:v.height+\"px\"}},[$(\"div\",{staticClass:\"vjs-tree-list-holder\",style:v.virtual&&{height:v.flatData.length*v.itemHeight+\"px\"}},[$(\"div\",{staticClass:\"vjs-tree-list-holder-inner\",style:v.virtual&&{transform:\"translateY(\"+v.translateY+\"px)\"}},v._l(v.visibleData,function(M){return $(\"tree-node\",{key:M.id,style:v.itemHeight&&v.itemHeight!==20?{lineHeight:v.itemHeight+\"px\"}:{},attrs:{node:M,collapsed:!!v.hiddenPaths[M.path],\"show-double-quotes\":v.showDoubleQuotes,\"show-length\":v.showLength,\"collapsed-on-click-brackets\":v.collapsedOnClickBrackets,checked:v.selectedPaths.includes(M.path),\"selectable-type\":v.selectableType,\"show-line\":v.showLine,\"show-line-number\":v.showLineNumber,\"show-select-controller\":v.showSelectController,\"select-on-click-node\":v.selectOnClickNode,\"node-selectable\":v.nodeSelectable,\"highlight-selected-node\":v.highlightSelectedNode,\"show-icon\":v.showIcon,\"show-key-value-space\":v.showKeyValueSpace,editable:v.editable,\"editable-trigger\":v.editableTrigger},on:{\"node-click\":v.handleNodeClick,\"brackets-click\":v.handleBracketsClick,\"icon-click\":v.handleIconClick,\"selected-change\":v.handleSelectedChange,\"value-change\":v.handleValueChange},scopedSlots:v._u([{key:\"key\",fn:function(F){return[v._t(\"nodeKey\",null,{node:F.node,defaultKey:F.defaultKey})]}},{key:\"value\",fn:function(F){return[v._t(\"nodeValue\",null,{node:F.node,defaultValue:F.defaultValue})]}}],null,!0)})}),1)])])])},[],!1,null,null,null).exports,E=Object.assign({},j,{version:\"1.9.5\"})}},n={};function i(a){if(n[a])return n[a].exports;var o=n[a]={exports:{}};return r[a](o,o.exports,i),o.exports}return i.n=function(a){var o=a&&a.__esModule?function(){return a.default}:function(){return a};return i.d(o,{a:o}),o},i.d=function(a,o){for(var s in o)i.o(o,s)&&!i.o(a,s)&&Object.defineProperty(a,s,{enumerable:!0,get:o[s]})},i.o=function(a,o){return Object.prototype.hasOwnProperty.call(a,o)},i.r=function(a){typeof Symbol<\"u\"&&Symbol.toStringTag&&Object.defineProperty(a,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(a,\"__esModule\",{value:!0})},i(569)}()})})(yN);const OJ=Jx(yN.exports);/*!\n * vuex v3.6.2\n * (c) 2021 Evan You\n * @license MIT\n */function _J(t){var e=Number(t.version.split(\".\")[0]);if(e>=2)t.mixin({beforeCreate:n});else{var r=t.prototype._init;t.prototype._init=function(i){i===void 0&&(i={}),i.init=i.init?[n].concat(i.init):n,r.call(this,i)}}function n(){var i=this.$options;i.store?this.$store=typeof i.store==\"function\"?i.store():i.store:i.parent&&i.parent.$store&&(this.$store=i.parent.$store)}}var wJ=typeof window<\"u\"?window:typeof global<\"u\"?global:{},ps=wJ.__VUE_DEVTOOLS_GLOBAL_HOOK__;function TJ(t){!ps||(t._devtoolHook=ps,ps.emit(\"vuex:init\",t),ps.on(\"vuex:travel-to-state\",function(e){t.replaceState(e)}),t.subscribe(function(e,r){ps.emit(\"vuex:mutation\",e,r)},{prepend:!0}),t.subscribeAction(function(e,r){ps.emit(\"vuex:action\",e,r)},{prepend:!0}))}function SJ(t,e){return t.filter(e)[0]}function Jg(t,e){if(e===void 0&&(e=[]),t===null||typeof t!=\"object\")return t;var r=SJ(e,function(i){return i.original===t});if(r)return r.copy;var n=Array.isArray(t)?[]:{};return e.push({original:t,copy:n}),Object.keys(t).forEach(function(i){n[i]=Jg(t[i],e)}),n}function sl(t,e){Object.keys(t).forEach(function(r){return e(t[r],r)})}function ON(t){return t!==null&&typeof t==\"object\"}function PJ(t){return t&&typeof t.then==\"function\"}function EJ(t,e){return function(){return t(e)}}var ai=function(e,r){this.runtime=r,this._children=Object.create(null),this._rawModule=e;var n=e.state;this.state=(typeof n==\"function\"?n():n)||{}},_N={namespaced:{configurable:!0}};_N.namespaced.get=function(){return!!this._rawModule.namespaced};ai.prototype.addChild=function(e,r){this._children[e]=r};ai.prototype.removeChild=function(e){delete this._children[e]};ai.prototype.getChild=function(e){return this._children[e]};ai.prototype.hasChild=function(e){return e in this._children};ai.prototype.update=function(e){this._rawModule.namespaced=e.namespaced,e.actions&&(this._rawModule.actions=e.actions),e.mutations&&(this._rawModule.mutations=e.mutations),e.getters&&(this._rawModule.getters=e.getters)};ai.prototype.forEachChild=function(e){sl(this._children,e)};ai.prototype.forEachGetter=function(e){this._rawModule.getters&&sl(this._rawModule.getters,e)};ai.prototype.forEachAction=function(e){this._rawModule.actions&&sl(this._rawModule.actions,e)};ai.prototype.forEachMutation=function(e){this._rawModule.mutations&&sl(this._rawModule.mutations,e)};Object.defineProperties(ai.prototype,_N);var Ho=function(e){this.register([],e,!1)};Ho.prototype.get=function(e){return e.reduce(function(r,n){return r.getChild(n)},this.root)};Ho.prototype.getNamespace=function(e){var r=this.root;return e.reduce(function(n,i){return r=r.getChild(i),n+(r.namespaced?i+\"/\":\"\")},\"\")};Ho.prototype.update=function(e){wN([],this.root,e)};Ho.prototype.register=function(e,r,n){var i=this;n===void 0&&(n=!0);var a=new ai(r,n);if(e.length===0)this.root=a;else{var o=this.get(e.slice(0,-1));o.addChild(e[e.length-1],a)}r.modules&&sl(r.modules,function(s,l){i.register(e.concat(l),s,n)})};Ho.prototype.unregister=function(e){var r=this.get(e.slice(0,-1)),n=e[e.length-1],i=r.getChild(n);!i||!i.runtime||r.removeChild(n)};Ho.prototype.isRegistered=function(e){var r=this.get(e.slice(0,-1)),n=e[e.length-1];return r?r.hasChild(n):!1};function wN(t,e,r){if(e.update(r),r.modules)for(var n in r.modules){if(!e.getChild(n))return;wN(t.concat(n),e.getChild(n),r.modules[n])}}var Kr,Sn=function(e){var r=this;e===void 0&&(e={}),!Kr&&typeof window<\"u\"&&window.Vue&&PN(window.Vue);var n=e.plugins;n===void 0&&(n=[]);var i=e.strict;i===void 0&&(i=!1),this._committing=!1,this._actions=Object.create(null),this._actionSubscribers=[],this._mutations=Object.create(null),this._wrappedGetters=Object.create(null),this._modules=new Ho(e),this._modulesNamespaceMap=Object.create(null),this._subscribers=[],this._watcherVM=new Kr,this._makeLocalGettersCache=Object.create(null);var a=this,o=this,s=o.dispatch,l=o.commit;this.dispatch=function(p,h){return s.call(a,p,h)},this.commit=function(p,h,b){return l.call(a,p,h,b)},this.strict=i;var u=this._modules.root.state;lh(this,u,[],this._modules.root),eO(this,u),n.forEach(function(d){return d(r)});var f=e.devtools!==void 0?e.devtools:Kr.config.devtools;f&&TJ(this)},Qy={state:{configurable:!0}};Qy.state.get=function(){return this._vm._data.$$state};Qy.state.set=function(t){};Sn.prototype.commit=function(e,r,n){var i=this,a=Kd(e,r,n),o=a.type,s=a.payload,l={type:o,payload:s},u=this._mutations[o];!u||(this._withCommit(function(){u.forEach(function(d){d(s)})}),this._subscribers.slice().forEach(function(f){return f(l,i.state)}))};Sn.prototype.dispatch=function(e,r){var n=this,i=Kd(e,r),a=i.type,o=i.payload,s={type:a,payload:o},l=this._actions[a];if(!!l){try{this._actionSubscribers.slice().filter(function(f){return f.before}).forEach(function(f){return f.before(s,n.state)})}catch{}var u=l.length>1?Promise.all(l.map(function(f){return f(o)})):l[0](o);return new Promise(function(f,d){u.then(function(p){try{n._actionSubscribers.filter(function(h){return h.after}).forEach(function(h){return h.after(s,n.state)})}catch{}f(p)},function(p){try{n._actionSubscribers.filter(function(h){return h.error}).forEach(function(h){return h.error(s,n.state,p)})}catch{}d(p)})})}};Sn.prototype.subscribe=function(e,r){return TN(e,this._subscribers,r)};Sn.prototype.subscribeAction=function(e,r){var n=typeof e==\"function\"?{before:e}:e;return TN(n,this._actionSubscribers,r)};Sn.prototype.watch=function(e,r,n){var i=this;return this._watcherVM.$watch(function(){return e(i.state,i.getters)},r,n)};Sn.prototype.replaceState=function(e){var r=this;this._withCommit(function(){r._vm._data.$$state=e})};Sn.prototype.registerModule=function(e,r,n){n===void 0&&(n={}),typeof e==\"string\"&&(e=[e]),this._modules.register(e,r),lh(this,this.state,e,this._modules.get(e),n.preserveState),eO(this,this.state)};Sn.prototype.unregisterModule=function(e){var r=this;typeof e==\"string\"&&(e=[e]),this._modules.unregister(e),this._withCommit(function(){var n=tO(r.state,e.slice(0,-1));Kr.delete(n,e[e.length-1])}),SN(this)};Sn.prototype.hasModule=function(e){return typeof e==\"string\"&&(e=[e]),this._modules.isRegistered(e)};Sn.prototype.hotUpdate=function(e){this._modules.update(e),SN(this,!0)};Sn.prototype._withCommit=function(e){var r=this._committing;this._committing=!0,e(),this._committing=r};Object.defineProperties(Sn.prototype,Qy);function TN(t,e,r){return e.indexOf(t)<0&&(r&&r.prepend?e.unshift(t):e.push(t)),function(){var n=e.indexOf(t);n>-1&&e.splice(n,1)}}function SN(t,e){t._actions=Object.create(null),t._mutations=Object.create(null),t._wrappedGetters=Object.create(null),t._modulesNamespaceMap=Object.create(null);var r=t.state;lh(t,r,[],t._modules.root,!0),eO(t,r,e)}function eO(t,e,r){var n=t._vm;t.getters={},t._makeLocalGettersCache=Object.create(null);var i=t._wrappedGetters,a={};sl(i,function(s,l){a[l]=EJ(s,t),Object.defineProperty(t.getters,l,{get:function(){return t._vm[l]},enumerable:!0})});var o=Kr.config.silent;Kr.config.silent=!0,t._vm=new Kr({data:{$$state:e},computed:a}),Kr.config.silent=o,t.strict&&xJ(t),n&&(r&&t._withCommit(function(){n._data.$$state=null}),Kr.nextTick(function(){return n.$destroy()}))}function lh(t,e,r,n,i){var a=!r.length,o=t._modules.getNamespace(r);if(n.namespaced&&(t._modulesNamespaceMap[o],t._modulesNamespaceMap[o]=n),!a&&!i){var s=tO(e,r.slice(0,-1)),l=r[r.length-1];t._withCommit(function(){Kr.set(s,l,n.state)})}var u=n.context=$J(t,o,r);n.forEachMutation(function(f,d){var p=o+d;DJ(t,p,f,u)}),n.forEachAction(function(f,d){var p=f.root?d:o+d,h=f.handler||f;AJ(t,p,h,u)}),n.forEachGetter(function(f,d){var p=o+d;RJ(t,p,f,u)}),n.forEachChild(function(f,d){lh(t,e,r.concat(d),f,i)})}function $J(t,e,r){var n=e===\"\",i={dispatch:n?t.dispatch:function(a,o,s){var l=Kd(a,o,s),u=l.payload,f=l.options,d=l.type;return(!f||!f.root)&&(d=e+d),t.dispatch(d,u)},commit:n?t.commit:function(a,o,s){var l=Kd(a,o,s),u=l.payload,f=l.options,d=l.type;(!f||!f.root)&&(d=e+d),t.commit(d,u,f)}};return Object.defineProperties(i,{getters:{get:n?function(){return t.getters}:function(){return CJ(t,e)}},state:{get:function(){return tO(t.state,r)}}}),i}function CJ(t,e){if(!t._makeLocalGettersCache[e]){var r={},n=e.length;Object.keys(t.getters).forEach(function(i){if(i.slice(0,n)===e){var a=i.slice(n);Object.defineProperty(r,a,{get:function(){return t.getters[i]},enumerable:!0})}}),t._makeLocalGettersCache[e]=r}return t._makeLocalGettersCache[e]}function DJ(t,e,r,n){var i=t._mutations[e]||(t._mutations[e]=[]);i.push(function(o){r.call(t,n.state,o)})}function AJ(t,e,r,n){var i=t._actions[e]||(t._actions[e]=[]);i.push(function(o){var s=r.call(t,{dispatch:n.dispatch,commit:n.commit,getters:n.getters,state:n.state,rootGetters:t.getters,rootState:t.state},o);return PJ(s)||(s=Promise.resolve(s)),t._devtoolHook?s.catch(function(l){throw t._devtoolHook.emit(\"vuex:error\",l),l}):s})}function RJ(t,e,r,n){t._wrappedGetters[e]||(t._wrappedGetters[e]=function(a){return r(n.state,n.getters,a.state,a.getters)})}function xJ(t){t._vm.$watch(function(){return this._data.$$state},function(){},{deep:!0,sync:!0})}function tO(t,e){return e.reduce(function(r,n){return r[n]},t)}function Kd(t,e,r){return ON(t)&&t.type&&(r=e,e=t,t=t.type),{type:t,payload:e,options:r}}function PN(t){Kr&&t===Kr||(Kr=t,_J(Kr))}var EN=ch(function(t,e){var r={};return uh(e).forEach(function(n){var i=n.key,a=n.val;r[i]=function(){var s=this.$store.state,l=this.$store.getters;if(t){var u=fh(this.$store,\"mapState\",t);if(!u)return;s=u.context.state,l=u.context.getters}return typeof a==\"function\"?a.call(this,s,l):s[a]},r[i].vuex=!0}),r}),$N=ch(function(t,e){var r={};return uh(e).forEach(function(n){var i=n.key,a=n.val;r[i]=function(){for(var s=[],l=arguments.length;l--;)s[l]=arguments[l];var u=this.$store.commit;if(t){var f=fh(this.$store,\"mapMutations\",t);if(!f)return;u=f.context.commit}return typeof a==\"function\"?a.apply(this,[u].concat(s)):u.apply(this.$store,[a].concat(s))}}),r}),CN=ch(function(t,e){var r={};return uh(e).forEach(function(n){var i=n.key,a=n.val;a=t+a,r[i]=function(){if(!(t&&!fh(this.$store,\"mapGetters\",t)))return this.$store.getters[a]},r[i].vuex=!0}),r}),DN=ch(function(t,e){var r={};return uh(e).forEach(function(n){var i=n.key,a=n.val;r[i]=function(){for(var s=[],l=arguments.length;l--;)s[l]=arguments[l];var u=this.$store.dispatch;if(t){var f=fh(this.$store,\"mapActions\",t);if(!f)return;u=f.context.dispatch}return typeof a==\"function\"?a.apply(this,[u].concat(s)):u.apply(this.$store,[a].concat(s))}}),r}),MJ=function(t){return{mapState:EN.bind(null,t),mapGetters:CN.bind(null,t),mapMutations:$N.bind(null,t),mapActions:DN.bind(null,t)}};function uh(t){return NJ(t)?Array.isArray(t)?t.map(function(e){return{key:e,val:e}}):Object.keys(t).map(function(e){return{key:e,val:t[e]}}):[]}function NJ(t){return Array.isArray(t)||ON(t)}function ch(t){return function(e,r){return typeof e!=\"string\"?(r=e,e=\"\"):e.charAt(e.length-1)!==\"/\"&&(e+=\"/\"),t(e,r)}}function fh(t,e,r){var n=t._modulesNamespaceMap[r];return n}function IJ(t){t===void 0&&(t={});var e=t.collapsed;e===void 0&&(e=!0);var r=t.filter;r===void 0&&(r=function(f,d,p){return!0});var n=t.transformer;n===void 0&&(n=function(f){return f});var i=t.mutationTransformer;i===void 0&&(i=function(f){return f});var a=t.actionFilter;a===void 0&&(a=function(f,d){return!0});var o=t.actionTransformer;o===void 0&&(o=function(f){return f});var s=t.logMutations;s===void 0&&(s=!0);var l=t.logActions;l===void 0&&(l=!0);var u=t.logger;return u===void 0&&(u=console),function(f){var d=Jg(f.state);typeof u>\"u\"||(s&&f.subscribe(function(p,h){var b=Jg(h);if(r(p,d,b)){var y=f1(),P=i(p),C=\"mutation \"+p.type+y;u1(u,C,e),u.log(\"%c prev state\",\"color: #9E9E9E; font-weight: bold\",n(d)),u.log(\"%c mutation\",\"color: #03A9F4; font-weight: bold\",P),u.log(\"%c next state\",\"color: #4CAF50; font-weight: bold\",n(b)),c1(u)}d=b}),l&&f.subscribeAction(function(p,h){if(a(p,h)){var b=f1(),y=o(p),P=\"action \"+p.type+b;u1(u,P,e),u.log(\"%c action\",\"color: #03A9F4; font-weight: bold\",y),c1(u)}}))}}function u1(t,e,r){var n=r?t.groupCollapsed:t.group;try{n.call(t,e)}catch{t.log(e)}}function c1(t){try{t.groupEnd()}catch{t.log(\"\\u2014\\u2014 log end \\u2014\\u2014\")}}function f1(){var t=new Date;return\" @ \"+ef(t.getHours(),2)+\":\"+ef(t.getMinutes(),2)+\":\"+ef(t.getSeconds(),2)+\".\"+ef(t.getMilliseconds(),3)}function BJ(t,e){return new Array(e+1).join(t)}function ef(t,e){return BJ(\"0\",e-t.toString().length)+t}var kJ={Store:Sn,install:PN,version:\"3.6.2\",mapState:EN,mapMutations:$N,mapGetters:CN,mapActions:DN,createNamespacedHelpers:MJ,createLogger:IJ};const AN=kJ;ye.use(AN);let LJ=new AN.Store({state:{metric:{},info:{}},getters:{getMetric(t){return t.metric}},mutations:{setMertic(t,e){t.metric=e},setInfo(t,e){t.info=e}},actions:{pollingMertic({commit:t},e){t(\"setMertic\",e)},pollingInfo({commit:t},e){t(\"setInfo\",e)}}});/*!\n * vue-i18n v8.28.2 \n * (c) 2022 kazuya kawaguchi\n * Released under the MIT License.\n */var RN=[\"compactDisplay\",\"currency\",\"currencyDisplay\",\"currencySign\",\"localeMatcher\",\"notation\",\"numberingSystem\",\"signDisplay\",\"style\",\"unit\",\"unitDisplay\",\"useGrouping\",\"minimumIntegerDigits\",\"minimumFractionDigits\",\"maximumFractionDigits\",\"minimumSignificantDigits\",\"maximumSignificantDigits\"],FJ=[\"dateStyle\",\"timeStyle\",\"calendar\",\"localeMatcher\",\"hour12\",\"hourCycle\",\"timeZone\",\"formatMatcher\",\"weekday\",\"era\",\"year\",\"month\",\"day\",\"hour\",\"minute\",\"second\",\"timeZoneName\"];function qs(t,e){typeof console<\"u\"&&(console.warn(\"[vue-i18n] \"+t),e&&console.warn(e.stack))}function jJ(t,e){typeof console<\"u\"&&(console.error(\"[vue-i18n] \"+t),e&&console.error(e.stack))}var _i=Array.isArray;function Fn(t){return t!==null&&typeof t==\"object\"}function VJ(t){return typeof t==\"boolean\"}function nr(t){return typeof t==\"string\"}var HJ=Object.prototype.toString,zJ=\"[object Object]\";function bi(t){return HJ.call(t)===zJ}function qr(t){return t==null}function Zg(t){return typeof t==\"function\"}function dh(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];var r=null,n=null;return t.length===1?Fn(t[0])||_i(t[0])?n=t[0]:typeof t[0]==\"string\"&&(r=t[0]):t.length===2&&(typeof t[0]==\"string\"&&(r=t[0]),(Fn(t[1])||_i(t[1]))&&(n=t[1])),{locale:r,params:n}}function ll(t){return JSON.parse(JSON.stringify(t))}function UJ(t,e){if(t.delete(e))return t}function GJ(t){var e=[];return t.forEach(function(r){return e.push(r)}),e}function ic(t,e){return!!~t.indexOf(e)}var WJ=Object.prototype.hasOwnProperty;function KJ(t,e){return WJ.call(t,e)}function yo(t){for(var e=arguments,r=Object(t),n=1;n<arguments.length;n++){var i=e[n];if(i!=null){var a=void 0;for(a in i)KJ(i,a)&&(Fn(i[a])?r[a]=yo(r[a],i[a]):r[a]=i[a])}}return r}function Yd(t,e){if(t===e)return!0;var r=Fn(t),n=Fn(e);if(r&&n)try{var i=_i(t),a=_i(e);if(i&&a)return t.length===e.length&&t.every(function(l,u){return Yd(l,e[u])});if(!i&&!a){var o=Object.keys(t),s=Object.keys(e);return o.length===s.length&&o.every(function(l){return Yd(t[l],e[l])})}else return!1}catch{return!1}else return!r&&!n?String(t)===String(e):!1}function YJ(t){return t.replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\").replace(/\"/g,\"&quot;\").replace(/'/g,\"&apos;\")}function qJ(t){return t!=null&&Object.keys(t).forEach(function(e){typeof t[e]==\"string\"&&(t[e]=YJ(t[e]))}),t}function XJ(t){t.prototype.hasOwnProperty(\"$i18n\")||Object.defineProperty(t.prototype,\"$i18n\",{get:function(){return this._i18n}}),t.prototype.$t=function(e){for(var r=[],n=arguments.length-1;n-- >0;)r[n]=arguments[n+1];var i=this.$i18n;return i._t.apply(i,[e,i.locale,i._getMessages(),this].concat(r))},t.prototype.$tc=function(e,r){for(var n=[],i=arguments.length-2;i-- >0;)n[i]=arguments[i+2];var a=this.$i18n;return a._tc.apply(a,[e,a.locale,a._getMessages(),this,r].concat(n))},t.prototype.$te=function(e,r){var n=this.$i18n;return n._te(e,n.locale,n._getMessages(),r)},t.prototype.$d=function(e){for(var r,n=[],i=arguments.length-1;i-- >0;)n[i]=arguments[i+1];return(r=this.$i18n).d.apply(r,[e].concat(n))},t.prototype.$n=function(e){for(var r,n=[],i=arguments.length-1;i-- >0;)n[i]=arguments[i+1];return(r=this.$i18n).n.apply(r,[e].concat(n))}}function JJ(t){t===void 0&&(t=!1);function e(){this!==this.$root&&this.$options.__INTLIFY_META__&&this.$el&&this.$el.setAttribute(\"data-intlify\",this.$options.__INTLIFY_META__)}return t?{mounted:e}:{beforeCreate:function(){var n=this.$options;if(n.i18n=n.i18n||(n.__i18nBridge||n.__i18n?{}:null),n.i18n){if(n.i18n instanceof ne){if(n.__i18nBridge||n.__i18n)try{var i=n.i18n&&n.i18n.messages?n.i18n.messages:{},a=n.__i18nBridge||n.__i18n;a.forEach(function(d){i=yo(i,JSON.parse(d))}),Object.keys(i).forEach(function(d){n.i18n.mergeLocaleMessage(d,i[d])})}catch{}this._i18n=n.i18n,this._i18nWatcher=this._i18n.watchI18nData()}else if(bi(n.i18n)){var o=this.$root&&this.$root.$i18n&&this.$root.$i18n instanceof ne?this.$root.$i18n:null;if(o&&(n.i18n.root=this.$root,n.i18n.formatter=o.formatter,n.i18n.fallbackLocale=o.fallbackLocale,n.i18n.formatFallbackMessages=o.formatFallbackMessages,n.i18n.silentTranslationWarn=o.silentTranslationWarn,n.i18n.silentFallbackWarn=o.silentFallbackWarn,n.i18n.pluralizationRules=o.pluralizationRules,n.i18n.preserveDirectiveContent=o.preserveDirectiveContent),n.__i18nBridge||n.__i18n)try{var s=n.i18n&&n.i18n.messages?n.i18n.messages:{},l=n.__i18nBridge||n.__i18n;l.forEach(function(d){s=yo(s,JSON.parse(d))}),n.i18n.messages=s}catch{}var u=n.i18n,f=u.sharedMessages;f&&bi(f)&&(n.i18n.messages=yo(n.i18n.messages,f)),this._i18n=new ne(n.i18n),this._i18nWatcher=this._i18n.watchI18nData(),(n.i18n.sync===void 0||!!n.i18n.sync)&&(this._localeWatcher=this.$i18n.watchLocale()),o&&o.onComponentInstanceCreated(this._i18n)}}else this.$root&&this.$root.$i18n&&this.$root.$i18n instanceof ne?this._i18n=this.$root.$i18n:n.parent&&n.parent.$i18n&&n.parent.$i18n instanceof ne&&(this._i18n=n.parent.$i18n)},beforeMount:function(){var n=this.$options;n.i18n=n.i18n||(n.__i18nBridge||n.__i18n?{}:null),n.i18n?n.i18n instanceof ne?(this._i18n.subscribeDataChanging(this),this._subscribing=!0):bi(n.i18n)&&(this._i18n.subscribeDataChanging(this),this._subscribing=!0):this.$root&&this.$root.$i18n&&this.$root.$i18n instanceof ne?(this._i18n.subscribeDataChanging(this),this._subscribing=!0):n.parent&&n.parent.$i18n&&n.parent.$i18n instanceof ne&&(this._i18n.subscribeDataChanging(this),this._subscribing=!0)},mounted:e,beforeDestroy:function(){if(!!this._i18n){var n=this;this.$nextTick(function(){n._subscribing&&(n._i18n.unsubscribeDataChanging(n),delete n._subscribing),n._i18nWatcher&&(n._i18nWatcher(),n._i18n.destroyVM(),delete n._i18nWatcher),n._localeWatcher&&(n._localeWatcher(),delete n._localeWatcher)})}}}}var d1={name:\"i18n\",functional:!0,props:{tag:{type:[String,Boolean,Object],default:\"span\"},path:{type:String,required:!0},locale:{type:String},places:{type:[Array,Object]}},render:function(e,r){var n=r.data,i=r.parent,a=r.props,o=r.slots,s=i.$i18n;if(!!s){var l=a.path,u=a.locale,f=a.places,d=o(),p=s.i(l,u,ZJ(d)||f?QJ(d.default,f):d),h=!!a.tag&&a.tag!==!0||a.tag===!1?a.tag:\"span\";return h?e(h,n,p):p}}};function ZJ(t){var e;for(e in t)if(e!==\"default\")return!1;return Boolean(e)}function QJ(t,e){var r=e?eZ(e):{};if(!t)return r;t=t.filter(function(i){return i.tag||i.text.trim()!==\"\"});var n=t.every(rZ);return t.reduce(n?tZ:xN,r)}function eZ(t){return Array.isArray(t)?t.reduce(xN,{}):Object.assign({},t)}function tZ(t,e){return e.data&&e.data.attrs&&e.data.attrs.place&&(t[e.data.attrs.place]=e),t}function xN(t,e,r){return t[r]=e,t}function rZ(t){return Boolean(t.data&&t.data.attrs&&t.data.attrs.place)}var p1={name:\"i18n-n\",functional:!0,props:{tag:{type:[String,Boolean,Object],default:\"span\"},value:{type:Number,required:!0},format:{type:[String,Object]},locale:{type:String}},render:function(e,r){var n=r.props,i=r.parent,a=r.data,o=i.$i18n;if(!o)return null;var s=null,l=null;nr(n.format)?s=n.format:Fn(n.format)&&(n.format.key&&(s=n.format.key),l=Object.keys(n.format).reduce(function(h,b){var y;return ic(RN,b)?Object.assign({},h,(y={},y[b]=n.format[b],y)):h},null));var u=n.locale||o.locale,f=o._ntp(n.value,u,s,l),d=f.map(function(h,b){var y,P=a.scopedSlots&&a.scopedSlots[h.type];return P?P((y={},y[h.type]=h.value,y.index=b,y.parts=f,y)):h.value}),p=!!n.tag&&n.tag!==!0||n.tag===!1?n.tag:\"span\";return p?e(p,{attrs:a.attrs,class:a.class,staticClass:a.staticClass},d):d}};function nZ(t,e,r){!MN(t,r)||NN(t,e,r)}function iZ(t,e,r,n){if(!!MN(t,r)){var i=r.context.$i18n;oZ(t,r)&&Yd(e.value,e.oldValue)&&Yd(t._localeMessage,i.getLocaleMessage(i.locale))||NN(t,e,r)}}function aZ(t,e,r,n){var i=r.context;if(!i){qs(\"Vue instance does not exists in VNode context\");return}var a=r.context.$i18n||{};!e.modifiers.preserve&&!a.preserveDirectiveContent&&(t.textContent=\"\"),t._vt=void 0,delete t._vt,t._locale=void 0,delete t._locale,t._localeMessage=void 0,delete t._localeMessage}function MN(t,e){var r=e.context;return r?r.$i18n?!0:(qs(\"VueI18n instance does not exists in Vue instance\"),!1):(qs(\"Vue instance does not exists in VNode context\"),!1)}function oZ(t,e){var r=e.context;return t._locale===r.$i18n.locale}function NN(t,e,r){var n,i,a=e.value,o=sZ(a),s=o.path,l=o.locale,u=o.args,f=o.choice;if(!s&&!l&&!u){qs(\"value type not supported\");return}if(!s){qs(\"`path` is required in v-t directive\");return}var d=r.context;f!=null?t._vt=t.textContent=(n=d.$i18n).tc.apply(n,[s,f].concat(h1(l,u))):t._vt=t.textContent=(i=d.$i18n).t.apply(i,[s].concat(h1(l,u))),t._locale=d.$i18n.locale,t._localeMessage=d.$i18n.getLocaleMessage(d.$i18n.locale)}function sZ(t){var e,r,n,i;return nr(t)?e=t:bi(t)&&(e=t.path,r=t.locale,n=t.args,i=t.choice),{path:e,locale:r,args:n,choice:i}}function h1(t,e){var r=[];return t&&r.push(t),e&&(Array.isArray(e)||bi(e))&&r.push(e),r}var Er;function rO(t,e){e===void 0&&(e={bridge:!1}),rO.installed=!0,Er=t,Er.version&&Number(Er.version.split(\".\")[0]),XJ(Er),Er.mixin(JJ(e.bridge)),Er.directive(\"t\",{bind:nZ,update:iZ,unbind:aZ}),Er.component(d1.name,d1),Er.component(p1.name,p1);var r=Er.config.optionMergeStrategies;r.i18n=function(n,i){return i===void 0?n:i}}var IN=function(){this._caches=Object.create(null)};IN.prototype.interpolate=function(e,r){if(!r)return[e];var n=this._caches[e];return n||(n=cZ(e),this._caches[e]=n),fZ(n,r)};var lZ=/^(?:\\d)+/,uZ=/^(?:\\w)+/;function cZ(t){for(var e=[],r=0,n=\"\";r<t.length;){var i=t[r++];if(i===\"{\"){n&&e.push({type:\"text\",value:n}),n=\"\";var a=\"\";for(i=t[r++];i!==void 0&&i!==\"}\";)a+=i,i=t[r++];var o=i===\"}\",s=lZ.test(a)?\"list\":o&&uZ.test(a)?\"named\":\"unknown\";e.push({value:a,type:s})}else i===\"%\"?t[r]!==\"{\"&&(n+=i):n+=i}return n&&e.push({type:\"text\",value:n}),e}function fZ(t,e){var r=[],n=0,i=Array.isArray(e)?\"list\":Fn(e)?\"named\":\"unknown\";if(i===\"unknown\")return r;for(;n<t.length;){var a=t[n];switch(a.type){case\"text\":r.push(a.value);break;case\"list\":r.push(e[parseInt(a.value,10)]);break;case\"named\":i===\"named\"&&r.push(e[a.value]);break}n++}return r}var er=0,$s=1,BN=2,kN=3,Qg=0,qd=1,Xd=2,ma=3,Ui=4,Jd=5,Zd=6,ph=7,Fu=8,ja=[];ja[Qg]={ws:[Qg],ident:[ma,er],\"[\":[Ui],eof:[ph]};ja[qd]={ws:[qd],\".\":[Xd],\"[\":[Ui],eof:[ph]};ja[Xd]={ws:[Xd],ident:[ma,er],0:[ma,er],number:[ma,er]};ja[ma]={ident:[ma,er],0:[ma,er],number:[ma,er],ws:[qd,$s],\".\":[Xd,$s],\"[\":[Ui,$s],eof:[ph,$s]};ja[Ui]={\"'\":[Jd,er],'\"':[Zd,er],\"[\":[Ui,BN],\"]\":[qd,kN],eof:Fu,else:[Ui,er]};ja[Jd]={\"'\":[Ui,er],eof:Fu,else:[Jd,er]};ja[Zd]={'\"':[Ui,er],eof:Fu,else:[Zd,er]};var dZ=/^\\s?(?:true|false|-?[\\d.]+|'[^']*'|\"[^\"]*\")\\s?$/;function pZ(t){return dZ.test(t)}function hZ(t){var e=t.charCodeAt(0),r=t.charCodeAt(t.length-1);return e===r&&(e===34||e===39)?t.slice(1,-1):t}function vZ(t){if(t==null)return\"eof\";var e=t.charCodeAt(0);switch(e){case 91:case 93:case 46:case 34:case 39:return t;case 95:case 36:case 45:return\"ident\";case 9:case 10:case 13:case 160:case 65279:case 8232:case 8233:return\"ws\"}return\"ident\"}function mZ(t){var e=t.trim();return t.charAt(0)===\"0\"&&isNaN(t)?!1:pZ(e)?hZ(e):\"*\"+e}function gZ(t){var e=[],r=-1,n=Qg,i=0,a,o,s,l,u,f,d,p=[];p[$s]=function(){o!==void 0&&(e.push(o),o=void 0)},p[er]=function(){o===void 0?o=s:o+=s},p[BN]=function(){p[er](),i++},p[kN]=function(){if(i>0)i--,n=Ui,p[er]();else{if(i=0,o===void 0||(o=mZ(o),o===!1))return!1;p[$s]()}};function h(){var b=t[r+1];if(n===Jd&&b===\"'\"||n===Zd&&b==='\"')return r++,s=\"\\\\\"+b,p[er](),!0}for(;n!==null;)if(r++,a=t[r],!(a===\"\\\\\"&&h())){if(l=vZ(a),d=ja[n],u=d[l]||d.else||Fu,u===Fu||(n=u[0],f=p[u[1]],f&&(s=u[2],s=s===void 0?a:s,f()===!1)))return;if(n===ph)return e}}var nO=function(){this._cache=Object.create(null)};nO.prototype.parsePath=function(e){var r=this._cache[e];return r||(r=gZ(e),r&&(this._cache[e]=r)),r||[]};nO.prototype.getPathValue=function(e,r){if(!Fn(e))return null;var n=this.parsePath(r);if(n.length===0)return null;for(var i=n.length,a=e,o=0;o<i;){var s=a[n[o]];if(s==null)return null;a=s,o++}return a};var bZ=/<\\/?[\\w\\s=\"/.':;#-\\/]+>/,yZ=/(?:@(?:\\.[a-zA-Z]+)?:(?:[\\w\\-_|./]+|\\([\\w\\-_:|./]+\\)))/g,OZ=/^@(?:\\.([a-zA-Z]+))?:/,_Z=/[()]/g,v1={upper:function(t){return t.toLocaleUpperCase()},lower:function(t){return t.toLocaleLowerCase()},capitalize:function(t){return\"\"+t.charAt(0).toLocaleUpperCase()+t.substr(1)}},eb=new IN,ne=function(e){var r=this;e===void 0&&(e={}),!Er&&typeof window<\"u\"&&window.Vue&&rO(window.Vue);var n=e.locale||\"en-US\",i=e.fallbackLocale===!1?!1:e.fallbackLocale||\"en-US\",a=e.messages||{},o=e.dateTimeFormats||e.datetimeFormats||{},s=e.numberFormats||{};this._vm=null,this._formatter=e.formatter||eb,this._modifiers=e.modifiers||{},this._missing=e.missing||null,this._root=e.root||null,this._sync=e.sync===void 0?!0:!!e.sync,this._fallbackRoot=e.fallbackRoot===void 0?!0:!!e.fallbackRoot,this._fallbackRootWithEmptyString=e.fallbackRootWithEmptyString===void 0?!0:!!e.fallbackRootWithEmptyString,this._formatFallbackMessages=e.formatFallbackMessages===void 0?!1:!!e.formatFallbackMessages,this._silentTranslationWarn=e.silentTranslationWarn===void 0?!1:e.silentTranslationWarn,this._silentFallbackWarn=e.silentFallbackWarn===void 0?!1:!!e.silentFallbackWarn,this._dateTimeFormatters={},this._numberFormatters={},this._path=new nO,this._dataListeners=new Set,this._componentInstanceCreatedListener=e.componentInstanceCreatedListener||null,this._preserveDirectiveContent=e.preserveDirectiveContent===void 0?!1:!!e.preserveDirectiveContent,this.pluralizationRules=e.pluralizationRules||{},this._warnHtmlInMessage=e.warnHtmlInMessage||\"off\",this._postTranslation=e.postTranslation||null,this._escapeParameterHtml=e.escapeParameterHtml||!1,\"__VUE_I18N_BRIDGE__\"in e&&(this.__VUE_I18N_BRIDGE__=e.__VUE_I18N_BRIDGE__),this.getChoiceIndex=function(l,u){var f=Object.getPrototypeOf(r);if(f&&f.getChoiceIndex){var d=f.getChoiceIndex;return d.call(r,l,u)}var p=function(h,b){return h=Math.abs(h),b===2?h?h>1?1:0:1:h?Math.min(h,2):0};return r.locale in r.pluralizationRules?r.pluralizationRules[r.locale].apply(r,[l,u]):p(l,u)},this._exist=function(l,u){return!l||!u?!1:!!(!qr(r._path.getPathValue(l,u))||l[u])},(this._warnHtmlInMessage===\"warn\"||this._warnHtmlInMessage===\"error\")&&Object.keys(a).forEach(function(l){r._checkLocaleMessage(l,r._warnHtmlInMessage,a[l])}),this._initVM({locale:n,fallbackLocale:i,messages:a,dateTimeFormats:o,numberFormats:s})},tt={vm:{configurable:!0},messages:{configurable:!0},dateTimeFormats:{configurable:!0},numberFormats:{configurable:!0},availableLocales:{configurable:!0},locale:{configurable:!0},fallbackLocale:{configurable:!0},formatFallbackMessages:{configurable:!0},missing:{configurable:!0},formatter:{configurable:!0},silentTranslationWarn:{configurable:!0},silentFallbackWarn:{configurable:!0},preserveDirectiveContent:{configurable:!0},warnHtmlInMessage:{configurable:!0},postTranslation:{configurable:!0},sync:{configurable:!0}};ne.prototype._checkLocaleMessage=function(e,r,n){var i=[],a=function(o,s,l,u){if(bi(l))Object.keys(l).forEach(function(p){var h=l[p];bi(h)?(u.push(p),u.push(\".\"),a(o,s,h,u),u.pop(),u.pop()):(u.push(p),a(o,s,h,u),u.pop())});else if(_i(l))l.forEach(function(p,h){bi(p)?(u.push(\"[\"+h+\"]\"),u.push(\".\"),a(o,s,p,u),u.pop(),u.pop()):(u.push(\"[\"+h+\"]\"),a(o,s,p,u),u.pop())});else if(nr(l)){var f=bZ.test(l);if(f){var d=\"Detected HTML in message '\"+l+\"' of keypath '\"+u.join(\"\")+\"' at '\"+s+\"'. Consider component interpolation with '<i18n>' to avoid XSS. See https://bit.ly/2ZqJzkp\";o===\"warn\"?qs(d):o===\"error\"&&jJ(d)}}};a(r,e,n,i)};ne.prototype._initVM=function(e){var r=Er.config.silent;Er.config.silent=!0,this._vm=new Er({data:e,__VUE18N__INSTANCE__:!0}),Er.config.silent=r};ne.prototype.destroyVM=function(){this._vm.$destroy()};ne.prototype.subscribeDataChanging=function(e){this._dataListeners.add(e)};ne.prototype.unsubscribeDataChanging=function(e){UJ(this._dataListeners,e)};ne.prototype.watchI18nData=function(){var e=this;return this._vm.$watch(\"$data\",function(){for(var r=GJ(e._dataListeners),n=r.length;n--;)Er.nextTick(function(){r[n]&&r[n].$forceUpdate()})},{deep:!0})};ne.prototype.watchLocale=function(e){if(e){if(!this.__VUE_I18N_BRIDGE__)return null;var n=this,i=this._vm;return this.vm.$watch(\"locale\",function(a){i.$set(i,\"locale\",a),n.__VUE_I18N_BRIDGE__&&e&&(e.locale.value=a),i.$forceUpdate()},{immediate:!0})}else{if(!this._sync||!this._root)return null;var r=this._vm;return this._root.$i18n.vm.$watch(\"locale\",function(a){r.$set(r,\"locale\",a),r.$forceUpdate()},{immediate:!0})}};ne.prototype.onComponentInstanceCreated=function(e){this._componentInstanceCreatedListener&&this._componentInstanceCreatedListener(e,this)};tt.vm.get=function(){return this._vm};tt.messages.get=function(){return ll(this._getMessages())};tt.dateTimeFormats.get=function(){return ll(this._getDateTimeFormats())};tt.numberFormats.get=function(){return ll(this._getNumberFormats())};tt.availableLocales.get=function(){return Object.keys(this.messages).sort()};tt.locale.get=function(){return this._vm.locale};tt.locale.set=function(t){this._vm.$set(this._vm,\"locale\",t)};tt.fallbackLocale.get=function(){return this._vm.fallbackLocale};tt.fallbackLocale.set=function(t){this._localeChainCache={},this._vm.$set(this._vm,\"fallbackLocale\",t)};tt.formatFallbackMessages.get=function(){return this._formatFallbackMessages};tt.formatFallbackMessages.set=function(t){this._formatFallbackMessages=t};tt.missing.get=function(){return this._missing};tt.missing.set=function(t){this._missing=t};tt.formatter.get=function(){return this._formatter};tt.formatter.set=function(t){this._formatter=t};tt.silentTranslationWarn.get=function(){return this._silentTranslationWarn};tt.silentTranslationWarn.set=function(t){this._silentTranslationWarn=t};tt.silentFallbackWarn.get=function(){return this._silentFallbackWarn};tt.silentFallbackWarn.set=function(t){this._silentFallbackWarn=t};tt.preserveDirectiveContent.get=function(){return this._preserveDirectiveContent};tt.preserveDirectiveContent.set=function(t){this._preserveDirectiveContent=t};tt.warnHtmlInMessage.get=function(){return this._warnHtmlInMessage};tt.warnHtmlInMessage.set=function(t){var e=this,r=this._warnHtmlInMessage;if(this._warnHtmlInMessage=t,r!==t&&(t===\"warn\"||t===\"error\")){var n=this._getMessages();Object.keys(n).forEach(function(i){e._checkLocaleMessage(i,e._warnHtmlInMessage,n[i])})}};tt.postTranslation.get=function(){return this._postTranslation};tt.postTranslation.set=function(t){this._postTranslation=t};tt.sync.get=function(){return this._sync};tt.sync.set=function(t){this._sync=t};ne.prototype._getMessages=function(){return this._vm.messages};ne.prototype._getDateTimeFormats=function(){return this._vm.dateTimeFormats};ne.prototype._getNumberFormats=function(){return this._vm.numberFormats};ne.prototype._warnDefault=function(e,r,n,i,a,o){if(!qr(n))return n;if(this._missing){var s=this._missing.apply(null,[e,r,i,a]);if(nr(s))return s}if(this._formatFallbackMessages){var l=dh.apply(void 0,a);return this._render(r,o,l.params,r)}else return r};ne.prototype._isFallbackRoot=function(e){return(this._fallbackRootWithEmptyString?!e:qr(e))&&!qr(this._root)&&this._fallbackRoot};ne.prototype._isSilentFallbackWarn=function(e){return this._silentFallbackWarn instanceof RegExp?this._silentFallbackWarn.test(e):this._silentFallbackWarn};ne.prototype._isSilentFallback=function(e,r){return this._isSilentFallbackWarn(r)&&(this._isFallbackRoot()||e!==this.fallbackLocale)};ne.prototype._isSilentTranslationWarn=function(e){return this._silentTranslationWarn instanceof RegExp?this._silentTranslationWarn.test(e):this._silentTranslationWarn};ne.prototype._interpolate=function(e,r,n,i,a,o,s){if(!r)return null;var l=this._path.getPathValue(r,n);if(_i(l)||bi(l))return l;var u;if(qr(l))if(bi(r)){if(u=r[n],!(nr(u)||Zg(u)))return null}else return null;else if(nr(l)||Zg(l))u=l;else return null;return nr(u)&&(u.indexOf(\"@:\")>=0||u.indexOf(\"@.\")>=0)&&(u=this._link(e,r,u,i,\"raw\",o,s)),this._render(u,a,o,n)};ne.prototype._link=function(e,r,n,i,a,o,s){var l=n,u=l.match(yZ);for(var f in u)if(!!u.hasOwnProperty(f)){var d=u[f],p=d.match(OZ),h=p[0],b=p[1],y=d.replace(h,\"\").replace(_Z,\"\");if(ic(s,y))return l;s.push(y);var P=this._interpolate(e,r,y,i,a===\"raw\"?\"string\":a,a===\"raw\"?void 0:o,s);if(this._isFallbackRoot(P)){if(!this._root)throw Error(\"unexpected error\");var C=this._root.$i18n;P=C._translate(C._getMessages(),C.locale,C.fallbackLocale,y,i,a,o)}P=this._warnDefault(e,y,P,i,_i(o)?o:[o],a),this._modifiers.hasOwnProperty(b)?P=this._modifiers[b](P):v1.hasOwnProperty(b)&&(P=v1[b](P)),s.pop(),l=P?l.replace(d,P):l}return l};ne.prototype._createMessageContext=function(e,r,n,i){var a=this,o=_i(e)?e:[],s=Fn(e)?e:{},l=function(p){return o[p]},u=function(p){return s[p]},f=this._getMessages(),d=this.locale;return{list:l,named:u,values:e,formatter:r,path:n,messages:f,locale:d,linked:function(p){return a._interpolate(d,f[d]||{},p,null,i,void 0,[p])}}};ne.prototype._render=function(e,r,n,i){if(Zg(e))return e(this._createMessageContext(n,this._formatter||eb,i,r));var a=this._formatter.interpolate(e,n,i);return a||(a=eb.interpolate(e,n,i)),r===\"string\"&&!nr(a)?a.join(\"\"):a};ne.prototype._appendItemToChain=function(e,r,n){var i=!1;return ic(e,r)||(i=!0,r&&(i=r[r.length-1]!==\"!\",r=r.replace(/!/g,\"\"),e.push(r),n&&n[r]&&(i=n[r]))),i};ne.prototype._appendLocaleToChain=function(e,r,n){var i,a=r.split(\"-\");do{var o=a.join(\"-\");i=this._appendItemToChain(e,o,n),a.splice(-1,1)}while(a.length&&i===!0);return i};ne.prototype._appendBlockToChain=function(e,r,n){for(var i=!0,a=0;a<r.length&&VJ(i);a++){var o=r[a];nr(o)&&(i=this._appendLocaleToChain(e,o,n))}return i};ne.prototype._getLocaleChain=function(e,r){if(e===\"\")return[];this._localeChainCache||(this._localeChainCache={});var n=this._localeChainCache[e];if(!n){r||(r=this.fallbackLocale),n=[];for(var i=[e];_i(i);)i=this._appendBlockToChain(n,i,r);var a;_i(r)?a=r:Fn(r)?r.default?a=r.default:a=null:a=r,nr(a)?i=[a]:i=a,i&&this._appendBlockToChain(n,i,null),this._localeChainCache[e]=n}return n};ne.prototype._translate=function(e,r,n,i,a,o,s){for(var l=this._getLocaleChain(r,n),u,f=0;f<l.length;f++){var d=l[f];if(u=this._interpolate(d,e[d],i,a,o,s,[i]),!qr(u))return u}return null};ne.prototype._t=function(e,r,n,i){for(var a,o=[],s=arguments.length-4;s-- >0;)o[s]=arguments[s+4];if(!e)return\"\";var l=dh.apply(void 0,o);this._escapeParameterHtml&&(l.params=qJ(l.params));var u=l.locale||r,f=this._translate(n,u,this.fallbackLocale,e,i,\"string\",l.params);if(this._isFallbackRoot(f)){if(!this._root)throw Error(\"unexpected error\");return(a=this._root).$t.apply(a,[e].concat(o))}else return f=this._warnDefault(u,e,f,i,o,\"string\"),this._postTranslation&&f!==null&&f!==void 0&&(f=this._postTranslation(f,e)),f};ne.prototype.t=function(e){for(var r,n=[],i=arguments.length-1;i-- >0;)n[i]=arguments[i+1];return(r=this)._t.apply(r,[e,this.locale,this._getMessages(),null].concat(n))};ne.prototype._i=function(e,r,n,i,a){var o=this._translate(n,r,this.fallbackLocale,e,i,\"raw\",a);if(this._isFallbackRoot(o)){if(!this._root)throw Error(\"unexpected error\");return this._root.$i18n.i(e,r,a)}else return this._warnDefault(r,e,o,i,[a],\"raw\")};ne.prototype.i=function(e,r,n){return e?(nr(r)||(r=this.locale),this._i(e,r,this._getMessages(),null,n)):\"\"};ne.prototype._tc=function(e,r,n,i,a){for(var o,s=[],l=arguments.length-5;l-- >0;)s[l]=arguments[l+5];if(!e)return\"\";a===void 0&&(a=1);var u={count:a,n:a},f=dh.apply(void 0,s);return f.params=Object.assign(u,f.params),s=f.locale===null?[f.params]:[f.locale,f.params],this.fetchChoice((o=this)._t.apply(o,[e,r,n,i].concat(s)),a)};ne.prototype.fetchChoice=function(e,r){if(!e||!nr(e))return null;var n=e.split(\"|\");return r=this.getChoiceIndex(r,n.length),n[r]?n[r].trim():e};ne.prototype.tc=function(e,r){for(var n,i=[],a=arguments.length-2;a-- >0;)i[a]=arguments[a+2];return(n=this)._tc.apply(n,[e,this.locale,this._getMessages(),null,r].concat(i))};ne.prototype._te=function(e,r,n){for(var i=[],a=arguments.length-3;a-- >0;)i[a]=arguments[a+3];var o=dh.apply(void 0,i).locale||r;return this._exist(n[o],e)};ne.prototype.te=function(e,r){return this._te(e,this.locale,this._getMessages(),r)};ne.prototype.getLocaleMessage=function(e){return ll(this._vm.messages[e]||{})};ne.prototype.setLocaleMessage=function(e,r){(this._warnHtmlInMessage===\"warn\"||this._warnHtmlInMessage===\"error\")&&this._checkLocaleMessage(e,this._warnHtmlInMessage,r),this._vm.$set(this._vm.messages,e,r)};ne.prototype.mergeLocaleMessage=function(e,r){(this._warnHtmlInMessage===\"warn\"||this._warnHtmlInMessage===\"error\")&&this._checkLocaleMessage(e,this._warnHtmlInMessage,r),this._vm.$set(this._vm.messages,e,yo(typeof this._vm.messages[e]<\"u\"&&Object.keys(this._vm.messages[e]).length?Object.assign({},this._vm.messages[e]):{},r))};ne.prototype.getDateTimeFormat=function(e){return ll(this._vm.dateTimeFormats[e]||{})};ne.prototype.setDateTimeFormat=function(e,r){this._vm.$set(this._vm.dateTimeFormats,e,r),this._clearDateTimeFormat(e,r)};ne.prototype.mergeDateTimeFormat=function(e,r){this._vm.$set(this._vm.dateTimeFormats,e,yo(this._vm.dateTimeFormats[e]||{},r)),this._clearDateTimeFormat(e,r)};ne.prototype._clearDateTimeFormat=function(e,r){for(var n in r){var i=e+\"__\"+n;!this._dateTimeFormatters.hasOwnProperty(i)||delete this._dateTimeFormatters[i]}};ne.prototype._localizeDateTime=function(e,r,n,i,a,o){for(var s=r,l=i[s],u=this._getLocaleChain(r,n),f=0;f<u.length;f++){var d=s,p=u[f];if(l=i[p],s=p,!(qr(l)||qr(l[a])))break}if(qr(l)||qr(l[a]))return null;var h=l[a],b;if(o)b=new Intl.DateTimeFormat(s,Object.assign({},h,o));else{var y=s+\"__\"+a;b=this._dateTimeFormatters[y],b||(b=this._dateTimeFormatters[y]=new Intl.DateTimeFormat(s,h))}return b.format(e)};ne.prototype._d=function(e,r,n,i){if(!n){var a=i?new Intl.DateTimeFormat(r,i):new Intl.DateTimeFormat(r);return a.format(e)}var o=this._localizeDateTime(e,r,this.fallbackLocale,this._getDateTimeFormats(),n,i);if(this._isFallbackRoot(o)){if(!this._root)throw Error(\"unexpected error\");return this._root.$i18n.d(e,n,r)}else return o||\"\"};ne.prototype.d=function(e){for(var r=[],n=arguments.length-1;n-- >0;)r[n]=arguments[n+1];var i=this.locale,a=null,o=null;return r.length===1?(nr(r[0])?a=r[0]:Fn(r[0])&&(r[0].locale&&(i=r[0].locale),r[0].key&&(a=r[0].key)),o=Object.keys(r[0]).reduce(function(s,l){var u;return ic(FJ,l)?Object.assign({},s,(u={},u[l]=r[0][l],u)):s},null)):r.length===2&&(nr(r[0])&&(a=r[0]),nr(r[1])&&(i=r[1])),this._d(e,i,a,o)};ne.prototype.getNumberFormat=function(e){return ll(this._vm.numberFormats[e]||{})};ne.prototype.setNumberFormat=function(e,r){this._vm.$set(this._vm.numberFormats,e,r),this._clearNumberFormat(e,r)};ne.prototype.mergeNumberFormat=function(e,r){this._vm.$set(this._vm.numberFormats,e,yo(this._vm.numberFormats[e]||{},r)),this._clearNumberFormat(e,r)};ne.prototype._clearNumberFormat=function(e,r){for(var n in r){var i=e+\"__\"+n;!this._numberFormatters.hasOwnProperty(i)||delete this._numberFormatters[i]}};ne.prototype._getNumberFormatter=function(e,r,n,i,a,o){for(var s=r,l=i[s],u=this._getLocaleChain(r,n),f=0;f<u.length;f++){var d=s,p=u[f];if(l=i[p],s=p,!(qr(l)||qr(l[a])))break}if(qr(l)||qr(l[a]))return null;var h=l[a],b;if(o)b=new Intl.NumberFormat(s,Object.assign({},h,o));else{var y=s+\"__\"+a;b=this._numberFormatters[y],b||(b=this._numberFormatters[y]=new Intl.NumberFormat(s,h))}return b};ne.prototype._n=function(e,r,n,i){if(!ne.availabilities.numberFormat)return\"\";if(!n){var a=i?new Intl.NumberFormat(r,i):new Intl.NumberFormat(r);return a.format(e)}var o=this._getNumberFormatter(e,r,this.fallbackLocale,this._getNumberFormats(),n,i),s=o&&o.format(e);if(this._isFallbackRoot(s)){if(!this._root)throw Error(\"unexpected error\");return this._root.$i18n.n(e,Object.assign({},{key:n,locale:r},i))}else return s||\"\"};ne.prototype.n=function(e){for(var r=[],n=arguments.length-1;n-- >0;)r[n]=arguments[n+1];var i=this.locale,a=null,o=null;return r.length===1?nr(r[0])?a=r[0]:Fn(r[0])&&(r[0].locale&&(i=r[0].locale),r[0].key&&(a=r[0].key),o=Object.keys(r[0]).reduce(function(s,l){var u;return ic(RN,l)?Object.assign({},s,(u={},u[l]=r[0][l],u)):s},null)):r.length===2&&(nr(r[0])&&(a=r[0]),nr(r[1])&&(i=r[1])),this._n(e,i,a,o)};ne.prototype._ntp=function(e,r,n,i){if(!ne.availabilities.numberFormat)return[];if(!n){var a=i?new Intl.NumberFormat(r,i):new Intl.NumberFormat(r);return a.formatToParts(e)}var o=this._getNumberFormatter(e,r,this.fallbackLocale,this._getNumberFormats(),n,i),s=o&&o.formatToParts(e);if(this._isFallbackRoot(s)){if(!this._root)throw Error(\"unexpected error\");return this._root.$i18n._ntp(e,r,n,i)}else return s||[]};Object.defineProperties(ne.prototype,tt);var dm;Object.defineProperty(ne,\"availabilities\",{get:function(){if(!dm){var e=typeof Intl<\"u\";dm={dateTimeFormat:e&&typeof Intl.DateTimeFormat<\"u\",numberFormat:e&&typeof Intl.NumberFormat<\"u\"}}return dm}});ne.install=rO;ne.version=\"8.28.2\";const LN=ne,wZ={LanguageName:\"\\u7B80\\u4F53\\u4E2D\\u6587\",Published:\"\\u53D1\\u5E03\",Delayed:\"\\u5EF6\\u8FDF\",Received:\"\\u63A5\\u6536\",Subscriber:\"\\u8BA2\\u9605\\u8005\",Nodes:\"\\u8282\\u70B9\",Dashboard:\"\\u4EEA\\u8868\\u677F\",\"CAP Dashboard\":\"CAP \\u4EEA\\u8868\\u677F\",Loading:\"\\u52A0\\u8F7D\\u4E2D\",First:\"\\u9996\\u9875\",Next:\"\\u4E0B\\u4E00\\u9875\",Prev:\"\\u4E0A\\u4E00\\u9875\",Last:\"\\u5C3E\\u9875\",\"Page Size\":\"\\u6BCF\\u9875\\u6570\\u91CF\",\"Realtime Metric Graph\":\"\\u5B9E\\u65F6\\u5EA6\\u91CF\\u56FE\\u8868\",PublishedPerSec:\"\\u53D1\\u5E03\\u901F\\u7387(\\u79D2)\",ConsumePerSec:\"\\u6D88\\u8D39\\u901F\\u7387(\\u79D2)\",InvokeSubscriberPerSec:\"\\u8BA2\\u9605\\u8005\\u8C03\\u7528\\u901F\\u7387(\\u79D2)\",\"24h History Graph\":\"24\\u5C0F\\u65F6\\u7EDF\\u8BA1\\u56FE\\u8868\",\"Publish Succeeded\":\"\\u53D1\\u5E03\\u6210\\u529F\",\"Publish Failed\":\"\\u53D1\\u5E03\\u5931\\u8D25\",\"Received Succeeded\":\"\\u6D88\\u8D39\\u6210\\u529F\",\"Received Failed\":\"\\u6D88\\u8D39\\u5931\\u8D25\",\"Published Message\":\"\\u5DF2\\u53D1\\u5E03\\u6D88\\u606F\",\"Received Message\":\"\\u63A5\\u6536\\u7684\\u6D88\\u606F\",\"Aggregation Count\":\"\\u805A\\u5408\\u6570\\u91CF\",\"Publish TPS\":\"\\u53D1\\u5E03\\u901F\\u7387\",\"Consume TPS\":\"\\u6D88\\u8D39\\u901F\\u7387\",\"Subscriber Invoke Time\":\"\\u8BA2\\u9605\\u6267\\u884C\\u65F6\\u95F4\",\"Rate (TPS)\":\"\\u901F\\u7387 (TPS)\",SubscriberInvokeMeanTime:\"Y1\\u8F74\\u8868\\u793A\\u8BA2\\u9605\\u5E73\\u5747\\u65F6\\u95F4\\uFF08\\u8BA2\\u9605\\u65B9\\u6CD5\\u5355\\u4F4D\\u65F6\\u95F4\\u7684\\u5E73\\u5747\\u6267\\u884C\\u8017\\u65F6\\uFF0C\\u4E0D\\u4EE3\\u8868\\u6B21\\u6570\\uFF09\",\"Elpsed Time (ms)\":\"\\u8BA2\\u9605\\u6267\\u884C\\u65F6\\u95F4\\uFF08ms\\uFF09\",DelayedPublishTime:\"\\u5EF6\\u8FDF\\u53D1\\u5E03\\u65F6\\u95F4\",Succeeded:\"\\u6210\\u529F\",Failed:\"\\u5931\\u8D25\",Requeue:\"\\u91CD\\u65B0\\u53D1\\u5E03\",Delete:\"\\u5220\\u9664\",PublishNow:\"\\u7ACB\\u5373\\u53D1\\u5E03\",DelayedInfo:\"\\u8FD9\\u91CC\\u53EA\\u663E\\u793A1\\u5206\\u949F\\u540E\\u7684\\u5EF6\\u8FDF\\u6D88\\u606F\\uFF0C1\\u5206\\u949F\\u5185\\u7684\\u72B6\\u6001\\u4E3A Queued \\u4F60\\u53EF\\u4EE5\\u5728\\u6570\\u636E\\u5E93\\u67E5\\u770B\",Name:\"\\u540D\\u79F0\",Content:\"\\u5185\\u5BB9\",Search:\"\\u641C\\u7D22\",\"Re-execute\":\"\\u91CD\\u65B0\\u6267\\u884C\",Group:\"\\u6D88\\u606F\\u7EC4\",IdName:\"ID/\\u540D\\u79F0\",Added:\"\\u6DFB\\u52A0\\u65F6\\u95F4\",Retries:\"\\u91CD\\u8BD5\\u6B21\\u6570\",Expires:\"\\u8FC7\\u671F\\u65F6\\u95F4\",Total:\"\\u5408\\u8BA1\",SubscriberDescription:\"\\u8282\\u70B9\\u4E0B\\u7684\\u6240\\u6709\\u8BA2\\u9605\\u65B9\\u6CD5,\\u6309\\u7167 Group\\u4FE1\\u606F \\u8FDB\\u884C\\u5206\\u7EC4\",Method:\"\\u65B9\\u6CD5\",Id:\"Id\",Latency:\"\\u5EF6\\u8FDF\",\"Node Name\":\"\\u8282\\u70B9\\u540D\\u79F0\",\"Ip Address\":\"\\u5730\\u5740\",Port:\"\\u7AEF\\u53E3\",Tags:\"\\u6807\\u7B7E\",Actions:\"\\u52A8\\u4F5C\",ReexecuteSuccess:\"\\u{1F600} \\u91CD\\u65B0\\u6267\\u884C\\u6210\\u529F\\uFF01\",DeleteSuccess:\"\\u{1F600} \\u5220\\u9664\\u6210\\u529F\\uFF01\",RequeueSuccess:\"\\u{1F600} \\u91CD\\u65B0\\u53D1\\u5E03\\u6210\\u529F\\uFF01\",SwitchedNode:\"\\u5207\\u6362\\u7684\\u8282\\u70B9\",Storage:\"\\u5B58\\u50A8\",Transport:\"\\u4F20\\u8F93\",Switch:\"\\u5207\\u6362\",SelectNamespaces:\"-- \\u8BF7\\u9009\\u62E9\\u4E00\\u4E2A kubernetes \\u547D\\u540D\\u7A7A\\u95F4 --\",NonDiscovery:\"\\u672A\\u914D\\u7F6EConsul\\u6216K8S\\u670D\\u52A1\\u53D1\\u73B0 !\",EmptyRecords:\"\\u6CA1\\u6709\\u8981\\u663E\\u793A\\u7684\\u8BB0\\u5F55\"},TZ={LanguageName:\"English\",Published:\"Published\",Delayed:\"Delayed\",Received:\"Received\",Subscriber:\"Subscriber\",Nodes:\"Nodes\",Dashboard:\"Dashboard\",Transport:\"Transport\",Storage:\"Storage\",\"CAP Dashboard\":\"CAP Dashboard\",Loading:\"Loading\",First:\"First\",Next:\"Next\",Prev:\"Prev\",Last:\"Last\",\"Page Size\":\"Page Size\",\"Realtime Metric Graph\":\"Realtime Metric Graph\",PublishedPerSec:\"Publish Rate(sec)\",ConsumePerSec:\"Consume Rate(sec)\",InvokeSubscriberPerSec:\"Call Subscriber Rate(sec)\",\"24h History Graph\":\"24h History Graph\",\"Publish Succeeded\":\"Publish Succeeded\",\"Publish Failed\":\"Publish Failed\",\"Received Succeeded\":\"Received Succeeded\",\"Received Failed\":\"Received Failed\",\"Published Message\":\"Published Message\",\"Received Message\":\"Received Message\",\"Aggregation Count\":\"Aggregation Count\",\"Publish TPS\":\"Publish TPS\",\"Consume TPS\":\"Consume TPS\",\"Subscriber Invoke Time\":\"Subscriber Invoke Time\",\"Rate (TPS)\":\"Rate (TPS)\",SubscriberInvokeMeanTime:\"The Y1 axis represents the subscriber invoke mean time (not execute times)\",\"Elpsed Time (ms)\":\"Elpsed Time (ms)\",DelayedPublishTime:\"Delayed Publish Time\",Succeeded:\"Succeeded\",Failed:\"Failed\",Requeue:\"Requeue\",Delete:\"Delete\",PublishNow:\"Immediately Publish\",DelayedInfo:\"Only show delay time more than 1 minute messages here, the status of shorter than 1 minute messages name is 'Queued', you can check it in the database\",Name:\"Name\",Content:\"Content\",Search:\"Search\",\"Re-execute\":\"Re-execute\",Group:\"Group\",IdName:\"Id/Name\",Added:\"Added\",Retries:\"Retries\",Expires:\"Expires\",Total:\"Total\",SubscriberDescription:\"The subscription methods under the node are grouped by Group\",Method:\"Method\",Id:\"Id\",\"Node Name\":\"Node Name\",\"Ip Address\":\"Ip Address\",Port:\"Port\",Tags:\"Tags\",Actions:\"Actions\",ReexecuteSuccess:\"\\u{1F600} Reexecute Successful !\",DeleteSuccess:\"\\u{1F600} Delete Successful !\",RequeueSuccess:\"\\u{1F600} Requeue Successfull !\",SelectNamespaces:\"-- Please select a kubernetes namespace --\",Latency:\"Latency\",NonDiscovery:\"Unconfigure node discovery !\",EmptyRecords:\"No records to show\"};let tb=\"\";switch(\"production\"){case\"development\":tb=\"/cap/api\";break;default:tb=window.serverUrl;break}Xi.defaults.baseURL=tb;Xi.defaults.withCredentials=!0;Xi.defaults.headers.post[\"Content-Type\"]=\"application/json\";Xi.interceptors.request.use(t=>{let e=localStorage.getItem(\"token\");return e&&(t.headers=Object.assign({Authorization:`Bearer ${e}`},t.headers)),t},t=>Promise.reject(t));ye.config.productionTip=!1;ye.use(yK);ye.component(\"vue-json-pretty\",OJ);ye.use(LN);const SZ=new LN({locale:function(){return localStorage.getItem(\"lang\")?localStorage.getItem(\"lang\"):\"en-us\"}(),messages:{\"en-us\":TZ,\"zh-cn\":wZ}});new ye({router:yJ,store:LJ,i18n:SZ,render:t=>t(dY)}).$mount(\"#app\");export{AZ as B,$Z as a,EZ as b,CZ as c,Xi as d,PK as e,DZ as f,PZ as g,Up as n};\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/dist/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n    <link rel=\"icon\" href=\"./favicon.ico\">\n    <title>CAP Dashboard</title>\n  <script type=\"module\" crossorigin src=\"./assets/index.909977fe.js\"></script>\n  <link rel=\"stylesheet\" href=\"./assets/index.856c0890.css\">\n</head>\n\n<body>\n<div id=\"app\"></div>\n\n<!-- built files will be auto injected -->\n<script>\n    window.serverUrl = window.location.origin + \"%(servicePrefix)\";\n    window.pollingInterval = \"%(pollingInterval)\";\n  </script>\n</body>\n\n</html>"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n    <link rel=\"icon\" href=\"/favicon.ico\">\n    <title>CAP Dashboard</title>\n</head>\n\n<body>\n<div id=\"app\"></div>\n<script type=\"module\" src=\"/src/main.js\"></script>\n<!-- built files will be auto injected -->\n<script>\n    window.serverUrl = window.location.origin + \"%(servicePrefix)\";\n    window.pollingInterval = \"%(pollingInterval)\";\n  </script>\n</body>\n\n</html>"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/package.json",
    "content": "{\n  \"name\": \"cap-dashboard\",\n  \"version\": \"8.0.0\",\n  \"description\": \"Dashboard for CAP\",\n  \"author\": \"Savorboard, NCC\",\n  \"homepage\": \"https://github.com/dotnetcore/CAP\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/dotnetcore/CAP.git\"\n  },\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"vite build\",\n    \"preview\": \"vite preview --port 4173\",\n    \"lint\": \"eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore\"\n  },\n  \"dependencies\": {\n    \"axios\": \"^0.28.1\",\n    \"bootstrap\": \"^4.6.2\",\n    \"bootstrap-vue\": \"^2.23.1\",\n    \"json-bigint\": \"^1.0.0\",\n    \"vue\": \"^2.7.16\",\n    \"vue-i18n\": \"^8.28.2\",\n    \"vue-json-pretty\": \"^1.9.5\",\n    \"vue-router\": \"^3.6.5\",\n    \"vuex\": \"^3.6.2\"\n  },\n  \"devDependencies\": {\n    \"@rushstack/eslint-patch\": \"^1.10.2\",\n    \"@vitejs/plugin-vue2\": \"^1.1.2\",\n    \"@vue/eslint-config-prettier\": \"^7.1.0\",\n    \"eslint\": \"^8.57.0\",\n    \"eslint-plugin-vue\": \"^9.26.0\",\n    \"prettier\": \"^2.8.8\",\n    \"terser\": \"^5.31.0\",\n    \"vite\": \"^3.2.10\"\n  }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/src/App.vue",
    "content": "<template>\n  <div id=\"app\">\n    <Navigation />\n    <b-container class=\"mt-4\">\n      <router-view />\n    </b-container>\n    <Footer />\n  </div>\n</template>\n\n<script>\nimport Navigation from \"@/components/Navigation.vue\";\nimport Footer from \"@/components/Footer.vue\";\nimport axios from \"axios\";\n\n\nexport default {\n  name: \"App\",\n  components: {\n    Navigation,\n    Footer\n  },\n  data() {\n    return { timer: '' }\n  },\n  methods: {\n    getData() {\n      if (window.pollingInterval == \"%(pollingInterval)\") {\n        window.pollingInterval = 2000;\n      }\n\n      axios.get('/stats').then(response => {\n        this.$store.dispatch(\"pollingMertic\", response.data);\n        setTimeout(() => {\n          this.getData()\n        }, window.pollingInterval);\n      });\n    }\n  },\n  mounted() {\n    axios.interceptors.response.use(\n      res => {\n        if (res.status === 500) {\n          this.$bvToast.toast(\"request failed\", {\n            title: \"Request Error\",\n            variant: \"danger\",\n            autoHideDelay: 1000,\n            appendToast: true,\n            solid: true\n          });\n        }\n        return res;\n      }\n    );\n\n    this.getData();\n  },\n  beforeDestroy() {\n    clearInterval(this.timer);\n  }\n};\n\nDate.prototype.format = function (fmt) {\n  var o = {\n    \"M+\": this.getMonth() + 1,\n    \"d+\": this.getDate(),\n    \"h+\": this.getHours(),\n    \"m+\": this.getMinutes(),\n    \"s+\": this.getSeconds(),\n    \"q+\": Math.floor((this.getMonth() + 3) / 3),\n    S: this.getMilliseconds(),\n  };\n  if (/(y+)/.test(fmt)) {\n    fmt = fmt.replace(\n      RegExp.$1,\n      (this.getFullYear() + \"\").substr(4 - RegExp.$1.length)\n    );\n  }\n  for (var k in o) {\n    if (new RegExp(\"(\" + k + \")\").test(fmt)) {\n      fmt = fmt.replace(\n        RegExp.$1,\n        RegExp.$1.length == 1 ? o[k] : (\"00\" + o[k]).substr((\"\" + o[k]).length)\n      );\n    }\n  }\n  return fmt;\n};\n</script>\n<style>\n#app {\n  font-family: Avenir, Helvetica, Arial, sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  text-align: center;\n  color: #2c3e50;\n  padding-bottom: 50px;\n}\n\n.page-line {\n  text-align: left;\n  line-height: 38px;\n  padding-bottom: 9px;\n  border-bottom: 1px solid #eee;\n}\n</style>"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/src/assets/language/en-us.js",
    "content": "export default {\r\n    LanguageName: \"English\",\r\n    Published: \"Published\",\r\n    Delayed: \"Delayed\",\r\n    Received: \"Received\",\r\n    Subscriber: \"Subscriber\",\r\n    Nodes: \"Nodes\",\r\n    Dashboard: \"Dashboard\",\r\n    Transport: \"Transport\",\r\n    Storage: \"Storage\",\r\n    \"CAP Dashboard\": \"CAP Dashboard\",\r\n    Loading: \"Loading\",\r\n    First: \"First\",\r\n    Next: \"Next\",\r\n    Prev: \"Prev\",\r\n    Last: \"Last\",\r\n    \"Page Size\": \"Page Size\",\r\n    \"Realtime Metric Graph\": \"Realtime Metric Graph\",\r\n    PublishedPerSec: \"Publish Rate(sec)\",\r\n    ConsumePerSec: \"Consume Rate(sec)\",\r\n    InvokeSubscriberPerSec: \"Call Subscriber Rate(sec)\",\r\n    \"24h History Graph\": \"24h History Graph\",\r\n    \"Publish Succeeded\": \"Publish Succeeded\",\r\n    \"Publish Failed\": \"Publish Failed\",\r\n    \"Received Succeeded\": \"Received Succeeded\",\r\n    \"Received Failed\": \"Received Failed\",\r\n    \"Published Message\": \"Published Message\",\r\n    \"Received Message\": \"Received Message\",\r\n    \"Aggregation Count\": \"Aggregation Count\",\r\n    \"Publish TPS\": \"Publish TPS\",\r\n    \"Consume TPS\": \"Consume TPS\",\r\n    \"Subscriber Invoke Time\": \"Subscriber Invoke Time\",\r\n    \"Rate (TPS)\": \"Rate (TPS)\",\r\n    \"SubscriberInvokeMeanTime\": \"The Y1 axis represents the subscriber invoke mean time (not execute times)\",\r\n    \"Elpsed Time (ms)\": \"Elpsed Time (ms)\",\r\n    \"DelayedPublishTime\": \"Delayed Publish Time\",\r\n    Succeeded: \"Succeeded\",\r\n    Failed: \"Failed\",\r\n    Requeue: \"Requeue\",\r\n    Delete: \"Delete\",\r\n    PublishNow: \"Immediately Publish\",\r\n    DelayedInfo: \"Only show delay time more than 1 minute messages here, the status of shorter than 1 minute messages name is 'Queued', you can check it in the database\",\r\n    Name: \"Name\",\r\n    Content: \"Content\",\r\n    Search: \"Search\",\r\n    \"Re-execute\": \"Re-execute\",\r\n    Group: \"Group\",\r\n    IdName: \"Id/Name\",\r\n    Added: \"Added\",\r\n    Retries: \"Retries\",\r\n    Expires: \"Expires\",\r\n    Total: \"Total\",\r\n    SubscriberDescription: \"The subscription methods under the node are grouped by Group\",\r\n    Method: \"Method\",\r\n    Id: \"Id\",\r\n    \"Node Name\": \"Node Name\",\r\n    \"Ip Address\": \"Ip Address\",\r\n    Port: \"Port\",\r\n    Tags: \"Tags\",\r\n    Actions: \"Actions\",\r\n    ReexecuteSuccess: \"😀 Reexecute Successful !\",\r\n    DeleteSuccess: \"😀 Delete Successful !\",\r\n    RequeueSuccess: \"😀 Requeue Successfull !\",\r\n    SelectNamespaces: \"-- Please select a kubernetes namespace --\",\r\n    Latency: \"Latency\",\r\n    NonDiscovery: \"Unconfigure node discovery !\",\r\n    EmptyRecords: \"No records to show\"\r\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/src/assets/language/zh-cn.js",
    "content": "export default {\r\n    LanguageName: \"简体中文\",\r\n    Published: \"发布\",\r\n    Delayed: \"延迟\",\r\n    Received: \"接收\",\r\n    Subscriber: \"订阅者\",\r\n    Nodes: \"节点\",\r\n    Dashboard: \"仪表板\",\r\n    \"CAP Dashboard\": \"CAP 仪表板\",\r\n    Loading: \"加载中\",\r\n    First: \"首页\",\r\n    Next: \"下一页\",\r\n    Prev: \"上一页\",\r\n    Last: \"尾页\",\r\n    \"Page Size\": \"每页数量\",\r\n    \"Realtime Metric Graph\": \"实时度量图表\",\r\n    PublishedPerSec: \"发布速率(秒)\",\r\n    ConsumePerSec: \"消费速率(秒)\",\r\n    InvokeSubscriberPerSec: \"订阅者调用速率(秒)\",\r\n    \"24h History Graph\": \"24小时统计图表\",\r\n    \"Publish Succeeded\": \"发布成功\",\r\n    \"Publish Failed\": \"发布失败\",\r\n    \"Received Succeeded\": \"消费成功\",\r\n    \"Received Failed\": \"消费失败\",\r\n    \"Published Message\": \"已发布消息\",\r\n    \"Received Message\": \"接收的消息\",\r\n    \"Aggregation Count\": \"聚合数量\",\r\n    \"Publish TPS\": \"发布速率\",\r\n    \"Consume TPS\": \"消费速率\",\r\n    \"Subscriber Invoke Time\": \"订阅执行时间\",\r\n    \"Rate (TPS)\": \"速率 (TPS)\",\r\n    \"SubscriberInvokeMeanTime\": \"Y1轴表示订阅平均时间（订阅方法单位时间的平均执行耗时，不代表次数）\",\r\n    \"Elpsed Time (ms)\": \"订阅执行时间（ms）\",\r\n    \"DelayedPublishTime\": \"延迟发布时间\",\r\n    Succeeded: \"成功\",\r\n    Failed: \"失败\",\r\n    Requeue: \"重新发布\",\r\n    Delete: \"删除\",\r\n    PublishNow: \"立即发布\",\r\n    DelayedInfo: \"这里只显示1分钟后的延迟消息，1分钟内的状态为 Queued 你可以在数据库查看\",\r\n    Name: \"名称\",\r\n    Content: \"内容\",\r\n    Search: \"搜索\",\r\n    \"Re-execute\": \"重新执行\",\r\n    Group: \"消息组\",\r\n    IdName: \"ID/名称\",\r\n    Added: \"添加时间\",\r\n    Retries: \"重试次数\",\r\n    Expires: \"过期时间\",\r\n    Total: \"合计\",\r\n    SubscriberDescription: \"节点下的所有订阅方法,按照 Group信息 进行分组\",\r\n    Method: \"方法\",\r\n    Id: \"Id\",\r\n    Latency: \"延迟\",\r\n    \"Node Name\": \"节点名称\",\r\n    \"Ip Address\": \"地址\",\r\n    Port: \"端口\",\r\n    Tags: \"标签\",\r\n    Actions: \"动作\",\r\n    ReexecuteSuccess: \"😀 重新执行成功！\",\r\n    DeleteSuccess: \"😀 删除成功！\",\r\n    RequeueSuccess: \"😀 重新发布成功！\",\r\n    SwitchedNode: \"切换的节点\",\r\n    Storage: \"存储\",\r\n    Transport: \"传输\",\r\n    Switch: \"切换\",\r\n    SelectNamespaces: \"-- 请选择一个 kubernetes 命名空间 --\",\r\n    NonDiscovery: \"未配置Consul或K8S服务发现 !\",\r\n    EmptyRecords: \"没有要显示的记录\"\r\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/src/assets/uPlot.esm.js",
    "content": "/**\n* Copyright (c) 2022, Leon Sorokin\n* All rights reserved. (MIT Licensed)\n*\n* uPlot.js (μPlot)\n* A small, fast chart for time series, lines, areas, ohlc & bars\n* https://github.com/leeoniya/uPlot (v1.6.22)\n*/\n\nconst FEAT_TIME          = true;\n\nconst pre = \"u-\";\n\nconst UPLOT          =       \"uplot\";\nconst ORI_HZ         = pre + \"hz\";\nconst ORI_VT         = pre + \"vt\";\nconst TITLE          = pre + \"title\";\nconst WRAP           = pre + \"wrap\";\nconst UNDER          = pre + \"under\";\nconst OVER           = pre + \"over\";\nconst AXIS           = pre + \"axis\";\nconst OFF            = pre + \"off\";\nconst SELECT         = pre + \"select\";\nconst CURSOR_X       = pre + \"cursor-x\";\nconst CURSOR_Y       = pre + \"cursor-y\";\nconst CURSOR_PT      = pre + \"cursor-pt\";\nconst LEGEND         = pre + \"legend\";\nconst LEGEND_LIVE    = pre + \"live\";\nconst LEGEND_INLINE  = pre + \"inline\";\nconst LEGEND_THEAD   = pre + \"thead\";\nconst LEGEND_SERIES  = pre + \"series\";\nconst LEGEND_MARKER  = pre + \"marker\";\nconst LEGEND_LABEL   = pre + \"label\";\nconst LEGEND_VALUE   = pre + \"value\";\n\nconst WIDTH       = \"width\";\nconst HEIGHT      = \"height\";\nconst TOP         = \"top\";\nconst BOTTOM      = \"bottom\";\nconst LEFT        = \"left\";\nconst RIGHT       = \"right\";\nconst hexBlack    = \"#000\";\nconst transparent = hexBlack + \"0\";\n\nconst mousemove   = \"mousemove\";\nconst mousedown   = \"mousedown\";\nconst mouseup     = \"mouseup\";\nconst mouseenter  = \"mouseenter\";\nconst mouseleave  = \"mouseleave\";\nconst dblclick    = \"dblclick\";\nconst resize      = \"resize\";\nconst scroll      = \"scroll\";\n\nconst change      = \"change\";\nconst dppxchange  = \"dppxchange\";\n\nconst domEnv = typeof window != 'undefined';\n\nconst doc = domEnv ? document  : null;\nconst win = domEnv ? window    : null;\nconst nav = domEnv ? navigator : null;\n\nlet pxRatio;\n\nlet query;\n\nfunction setPxRatio() {\n\tlet _pxRatio = devicePixelRatio;\n\n\t// during print preview, Chrome fires off these dppx queries even without changes\n\tif (pxRatio != _pxRatio) {\n\t\tpxRatio = _pxRatio;\n\n\t\tquery && off(change, query, setPxRatio);\n\t\tquery = matchMedia(`(min-resolution: ${pxRatio - 0.001}dppx) and (max-resolution: ${pxRatio + 0.001}dppx)`);\n\t\ton(change, query, setPxRatio);\n\n\t\twin.dispatchEvent(new CustomEvent(dppxchange));\n\t}\n}\n\nfunction addClass(el, c) {\n\tif (c != null) {\n\t\tlet cl = el.classList;\n\t\t!cl.contains(c) && cl.add(c);\n\t}\n}\n\nfunction remClass(el, c) {\n\tlet cl = el.classList;\n\tcl.contains(c) && cl.remove(c);\n}\n\nfunction setStylePx(el, name, value) {\n\tel.style[name] = value + \"px\";\n}\n\nfunction placeTag(tag, cls, targ, refEl) {\n\tlet el = doc.createElement(tag);\n\n\tif (cls != null)\n\t\taddClass(el, cls);\n\n\tif (targ != null)\n\t\ttarg.insertBefore(el, refEl);\n\n\treturn el;\n}\n\nfunction placeDiv(cls, targ) {\n\treturn placeTag(\"div\", cls, targ);\n}\n\nconst xformCache = new WeakMap();\n\nfunction elTrans(el, xPos, yPos, xMax, yMax) {\n\tlet xform = \"translate(\" + xPos + \"px,\" + yPos + \"px)\";\n\tlet xformOld = xformCache.get(el);\n\n\tif (xform != xformOld) {\n\t\tel.style.transform = xform;\n\t\txformCache.set(el, xform);\n\n\t\tif (xPos < 0 || yPos < 0 || xPos > xMax || yPos > yMax)\n\t\t\taddClass(el, OFF);\n\t\telse\n\t\t\tremClass(el, OFF);\n\t}\n}\n\nconst colorCache = new WeakMap();\n\nfunction elColor(el, background, borderColor) {\n\tlet newColor = background + borderColor;\n\tlet oldColor = colorCache.get(el);\n\n\tif (newColor != oldColor) {\n\t\tcolorCache.set(el, newColor);\n\t\tel.style.background = background;\n\t\tel.style.borderColor = borderColor;\n\t}\n}\n\nconst sizeCache = new WeakMap();\n\nfunction elSize(el, newWid, newHgt, centered) {\n\tlet newSize = newWid + \"\" + newHgt;\n\tlet oldSize = sizeCache.get(el);\n\n\tif (newSize != oldSize) {\n\t\tsizeCache.set(el, newSize);\n\t\tel.style.height = newHgt + \"px\";\n\t\tel.style.width = newWid + \"px\";\n\t\tel.style.marginLeft = centered ? -newWid/2 + \"px\" : 0;\n\t\tel.style.marginTop = centered ? -newHgt/2 + \"px\" : 0;\n\t}\n}\n\nconst evOpts = {passive: true};\nconst evOpts2 = {...evOpts, capture: true};\n\nfunction on(ev, el, cb, capt) {\n\tel.addEventListener(ev, cb, capt ? evOpts2 : evOpts);\n}\n\nfunction off(ev, el, cb, capt) {\n\tel.removeEventListener(ev, cb, capt ? evOpts2 : evOpts);\n}\n\ndomEnv && setPxRatio();\n\n// binary search for index of closest value\nfunction closestIdx(num, arr, lo, hi) {\n\tlet mid;\n\tlo = lo || 0;\n\thi = hi || arr.length - 1;\n\tlet bitwise = hi <= 2147483647;\n\n\twhile (hi - lo > 1) {\n\t\tmid = bitwise ? (lo + hi) >> 1 : floor((lo + hi) / 2);\n\n\t\tif (arr[mid] < num)\n\t\t\tlo = mid;\n\t\telse\n\t\t\thi = mid;\n\t}\n\n\tif (num - arr[lo] <= arr[hi] - num)\n\t\treturn lo;\n\n\treturn hi;\n}\n\nfunction nonNullIdx(data, _i0, _i1, dir) {\n\tfor (let i = dir == 1 ? _i0 : _i1; i >= _i0 && i <= _i1; i += dir) {\n\t\tif (data[i] != null)\n\t\t\treturn i;\n\t}\n\n\treturn -1;\n}\n\nfunction getMinMax(data, _i0, _i1, sorted) {\n//\tconsole.log(\"getMinMax()\");\n\n\tlet _min = inf;\n\tlet _max = -inf;\n\n\tif (sorted == 1) {\n\t\t_min = data[_i0];\n\t\t_max = data[_i1];\n\t}\n\telse if (sorted == -1) {\n\t\t_min = data[_i1];\n\t\t_max = data[_i0];\n\t}\n\telse {\n\t\tfor (let i = _i0; i <= _i1; i++) {\n\t\t\tif (data[i] != null) {\n\t\t\t\t_min = min(_min, data[i]);\n\t\t\t\t_max = max(_max, data[i]);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn [_min, _max];\n}\n\nfunction getMinMaxLog(data, _i0, _i1) {\n//\tconsole.log(\"getMinMax()\");\n\n\tlet _min = inf;\n\tlet _max = -inf;\n\n\tfor (let i = _i0; i <= _i1; i++) {\n\t\tif (data[i] > 0) {\n\t\t\t_min = min(_min, data[i]);\n\t\t\t_max = max(_max, data[i]);\n\t\t}\n\t}\n\n\treturn [\n\t\t_min ==  inf ?  1 : _min,\n\t\t_max == -inf ? 10 : _max,\n\t];\n}\n\nfunction rangeLog(min, max, base, fullMags) {\n\tlet minSign = sign(min);\n\tlet maxSign = sign(max);\n\n\tlet logFn = base == 10 ? log10 : log2;\n\n\tif (min == max) {\n\t\tif (minSign == -1) {\n\t\t\tmin *= base;\n\t\t\tmax /= base;\n\t\t}\n\t\telse {\n\t\t\tmin /= base;\n\t\t\tmax *= base;\n\t\t}\n\t}\n\n\tlet growMinAbs = minSign == 1 ? floor : ceil;\n\tlet growMaxAbs = maxSign == 1 ? ceil : floor;\n\n\tlet minExp = growMinAbs(logFn(abs(min)));\n\tlet maxExp = growMaxAbs(logFn(abs(max)));\n\n\tlet minIncr = pow(base, minExp);\n\tlet maxIncr = pow(base, maxExp);\n\n\t// fix values like Math.pow(10, -5) === 0.000009999999999999999\n\tif (minExp < 0)\n\t\tminIncr = roundDec(minIncr, -minExp);\n\tif (maxExp < 0)\n\t\tmaxIncr = roundDec(maxIncr, -maxExp);\n\n\tif (fullMags) {\n\t\tmin = minIncr * minSign;\n\t\tmax = maxIncr * maxSign;\n\t}\n\telse {\n\t\tmin = incrRoundDn(min, minIncr);\n\t\tmax = incrRoundUp(max, maxIncr);\n\t}\n\n\treturn [min, max];\n}\n\nfunction rangeAsinh(min, max, base, fullMags) {\n\tlet minMax = rangeLog(min, max, base, fullMags);\n\n\tif (min == 0)\n\t\tminMax[0] = 0;\n\n\tif (max == 0)\n\t\tminMax[1] = 0;\n\n\treturn minMax;\n}\n\nconst rangePad = 0.1;\n\nconst autoRangePart = {\n\tmode: 3,\n\tpad: rangePad,\n};\n\nconst _eqRangePart = {\n\tpad:  0,\n\tsoft: null,\n\tmode: 0,\n};\n\nconst _eqRange = {\n\tmin: _eqRangePart,\n\tmax: _eqRangePart,\n};\n\n// this ensures that non-temporal/numeric y-axes get multiple-snapped padding added above/below\n// TODO: also account for incrs when snapping to ensure top of axis gets a tick & value\nfunction rangeNum(_min, _max, mult, extra) {\n\tif (isObj(mult))\n\t\treturn _rangeNum(_min, _max, mult);\n\n\t_eqRangePart.pad  = mult;\n\t_eqRangePart.soft = extra ? 0 : null;\n\t_eqRangePart.mode = extra ? 3 : 0;\n\n\treturn _rangeNum(_min, _max, _eqRange);\n}\n\n// nullish coalesce\nfunction ifNull(lh, rh) {\n\treturn lh == null ? rh : lh;\n}\n\n// checks if given index range in an array contains a non-null value\n// aka a range-bounded Array.some()\nfunction hasData(data, idx0, idx1) {\n\tidx0 = ifNull(idx0, 0);\n\tidx1 = ifNull(idx1, data.length - 1);\n\n\twhile (idx0 <= idx1) {\n\t\tif (data[idx0] != null)\n\t\t\treturn true;\n\t\tidx0++;\n\t}\n\n\treturn false;\n}\n\nfunction _rangeNum(_min, _max, cfg) {\n\tlet cmin = cfg.min;\n\tlet cmax = cfg.max;\n\n\tlet padMin = ifNull(cmin.pad, 0);\n\tlet padMax = ifNull(cmax.pad, 0);\n\n\tlet hardMin = ifNull(cmin.hard, -inf);\n\tlet hardMax = ifNull(cmax.hard,  inf);\n\n\tlet softMin = ifNull(cmin.soft,  inf);\n\tlet softMax = ifNull(cmax.soft, -inf);\n\n\tlet softMinMode = ifNull(cmin.mode, 0);\n\tlet softMaxMode = ifNull(cmax.mode, 0);\n\n\tlet delta = _max - _min;\n\tlet deltaMag = log10(delta);\n\n\tlet scalarMax = max(abs(_min), abs(_max));\n\tlet scalarMag = log10(scalarMax);\n\n\tlet scalarMagDelta = abs(scalarMag - deltaMag);\n\n\t// this handles situations like 89.7, 89.69999999999999\n\t// by assuming 0.001x deltas are precision errors\n//\tif (delta > 0 && delta < abs(_max) / 1e3)\n//\t\tdelta = 0;\n\n\t// treat data as flat if delta is less than 1 billionth\n\t// or range is 11+ orders of magnitude below raw values, e.g. 99999999.99999996 - 100000000.00000004\n\tif (delta < 1e-9 || scalarMagDelta > 10) {\n\t\tdelta = 0;\n\n\t\t// if soft mode is 2 and all vals are flat at 0, avoid the 0.1 * 1e3 fallback\n\t\t// this prevents 0,0,0 from ranging to -100,100 when softMin/softMax are -1,1\n\t\tif (_min == 0 || _max == 0) {\n\t\t\tdelta = 1e-9;\n\n\t\t\tif (softMinMode == 2 && softMin != inf)\n\t\t\t\tpadMin = 0;\n\n\t\t\tif (softMaxMode == 2 && softMax != -inf)\n\t\t\t\tpadMax = 0;\n\t\t}\n\t}\n\n\tlet nonZeroDelta = delta || scalarMax || 1e3;\n\tlet mag          = log10(nonZeroDelta);\n\tlet base         = pow(10, floor(mag));\n\n\tlet _padMin  = nonZeroDelta * (delta == 0 ? (_min == 0 ? .1 : 1) : padMin);\n\tlet _newMin  = roundDec(incrRoundDn(_min - _padMin, base/10), 9);\n\tlet _softMin = _min >= softMin && (softMinMode == 1 || softMinMode == 3 && _newMin <= softMin || softMinMode == 2 && _newMin >= softMin) ? softMin : inf;\n\tlet minLim   = max(hardMin, _newMin < _softMin && _min >= _softMin ? _softMin : min(_softMin, _newMin));\n\n\tlet _padMax  = nonZeroDelta * (delta == 0 ? (_max == 0 ? .1 : 1) : padMax);\n\tlet _newMax  = roundDec(incrRoundUp(_max + _padMax, base/10), 9);\n\tlet _softMax = _max <= softMax && (softMaxMode == 1 || softMaxMode == 3 && _newMax >= softMax || softMaxMode == 2 && _newMax <= softMax) ? softMax : -inf;\n\tlet maxLim   = min(hardMax, _newMax > _softMax && _max <= _softMax ? _softMax : max(_softMax, _newMax));\n\n\tif (minLim == maxLim && minLim == 0)\n\t\tmaxLim = 100;\n\n\treturn [minLim, maxLim];\n}\n\n// alternative: https://stackoverflow.com/a/2254896\nconst numFormatter = new Intl.NumberFormat(domEnv ? nav.language : 'en-US');\nconst fmtNum = val => numFormatter.format(val);\n\nconst M = Math;\n\nconst PI = M.PI;\nconst abs = M.abs;\nconst floor = M.floor;\nconst round = M.round;\nconst ceil = M.ceil;\nconst min = M.min;\nconst max = M.max;\nconst pow = M.pow;\nconst sign = M.sign;\nconst log10 = M.log10;\nconst log2 = M.log2;\n// TODO: seems like this needs to match asinh impl if the passed v is tweaked?\nconst sinh =  (v, linthresh = 1) => M.sinh(v) * linthresh;\nconst asinh = (v, linthresh = 1) => M.asinh(v / linthresh);\n\nconst inf = Infinity;\n\nfunction numIntDigits(x) {\n\treturn (log10((x ^ (x >> 31)) - (x >> 31)) | 0) + 1;\n}\n\nfunction incrRound(num, incr) {\n\treturn round(num/incr)*incr;\n}\n\nfunction clamp(num, _min, _max) {\n\treturn min(max(num, _min), _max);\n}\n\nfunction fnOrSelf(v) {\n\treturn typeof v == \"function\" ? v : () => v;\n}\n\nconst noop = () => {};\n\nconst retArg0 = _0 => _0;\n\nconst retArg1 = (_0, _1) => _1;\n\nconst retNull = _ => null;\n\nconst retTrue = _ => true;\n\nconst retEq = (a, b) => a == b;\n\nfunction incrRoundUp(num, incr) {\n\treturn ceil(num/incr)*incr;\n}\n\nfunction incrRoundDn(num, incr) {\n\treturn floor(num/incr)*incr;\n}\n\n// https://stackoverflow.com/a/48764436\n// rounds half away from zero\nfunction roundDec(val, dec = 0) {\n\tif (isInt(val))\n\t\treturn val;\n//\telse if (dec == 0)\n//\t\treturn round(val);\n\n\tlet p = 10 ** dec;\n\tlet n = (val * p) * (1 + Number.EPSILON);\n\treturn round(n) / p;\n}\n\nconst fixedDec = new Map();\n\nfunction guessDec(num) {\n\treturn ((\"\"+num).split(\".\")[1] || \"\").length;\n}\n\nfunction genIncrs(base, minExp, maxExp, mults) {\n\tlet incrs = [];\n\n\tlet multDec = mults.map(guessDec);\n\n\tfor (let exp = minExp; exp < maxExp; exp++) {\n\t\tlet expa = abs(exp);\n\t\tlet mag = roundDec(pow(base, exp), expa);\n\n\t\tfor (let i = 0; i < mults.length; i++) {\n\t\t\tlet _incr = mults[i] * mag;\n\t\t\tlet dec = (_incr >= 0 && exp >= 0 ? 0 : expa) + (exp >= multDec[i] ? 0 : multDec[i]);\n\t\t\tlet incr = roundDec(_incr, dec);\n\t\t\tincrs.push(incr);\n\t\t\tfixedDec.set(incr, dec);\n\t\t}\n\t}\n\n\treturn incrs;\n}\n\n//export const assign = Object.assign;\n\nconst EMPTY_OBJ = {};\nconst EMPTY_ARR = [];\n\nconst nullNullTuple = [null, null];\n\nconst isArr = Array.isArray;\nconst isInt = Number.isInteger;\n\nfunction isStr(v) {\n\treturn typeof v == 'string';\n}\n\nfunction isObj(v) {\n\tlet is = false;\n\n\tif (v != null) {\n\t\tlet c = v.constructor;\n\t\tis = c == null || c == Object;\n\t}\n\n\treturn is;\n}\n\nfunction fastIsObj(v) {\n\treturn v != null && typeof v == 'object';\n}\n\nconst TypedArray = Object.getPrototypeOf(Uint8Array);\n\nfunction copy(o, _isObj = isObj) {\n\tlet out;\n\n\tif (isArr(o)) {\n\t\tlet val = o.find(v => v != null);\n\n\t\tif (isArr(val) || _isObj(val)) {\n\t\t\tout = Array(o.length);\n\t\t\tfor (let i = 0; i < o.length; i++)\n\t\t\t\tout[i] = copy(o[i], _isObj);\n\t\t}\n\t\telse\n\t\t\tout = o.slice();\n\t}\n\telse if (o instanceof TypedArray) // also (ArrayBuffer.isView(o) && !(o instanceof DataView))\n\t\tout = o.slice();\n\telse if (_isObj(o)) {\n\t\tout = {};\n\t\tfor (let k in o)\n\t\t\tout[k] = copy(o[k], _isObj);\n\t}\n\telse\n\t\tout = o;\n\n\treturn out;\n}\n\nfunction assign(targ) {\n\tlet args = arguments;\n\n\tfor (let i = 1; i < args.length; i++) {\n\t\tlet src = args[i];\n\n\t\tfor (let key in src) {\n\t\t\tif (isObj(targ[key]))\n\t\t\t\tassign(targ[key], copy(src[key]));\n\t\t\telse\n\t\t\t\ttarg[key] = copy(src[key]);\n\t\t}\n\t}\n\n\treturn targ;\n}\n\n// nullModes\nconst NULL_REMOVE = 0;  // nulls are converted to undefined (e.g. for spanGaps: true)\nconst NULL_RETAIN = 1;  // nulls are retained, with alignment artifacts set to undefined (default)\nconst NULL_EXPAND = 2;  // nulls are expanded to include any adjacent alignment artifacts\n\n// sets undefined values to nulls when adjacent to existing nulls (minesweeper)\nfunction nullExpand(yVals, nullIdxs, alignedLen) {\n\tfor (let i = 0, xi, lastNullIdx = -1; i < nullIdxs.length; i++) {\n\t\tlet nullIdx = nullIdxs[i];\n\n\t\tif (nullIdx > lastNullIdx) {\n\t\t\txi = nullIdx - 1;\n\t\t\twhile (xi >= 0 && yVals[xi] == null)\n\t\t\t\tyVals[xi--] = null;\n\n\t\t\txi = nullIdx + 1;\n\t\t\twhile (xi < alignedLen && yVals[xi] == null)\n\t\t\t\tyVals[lastNullIdx = xi++] = null;\n\t\t}\n\t}\n}\n\n// nullModes is a tables-matched array indicating how to treat nulls in each series\n// output is sorted ASC on the joined field (table[0]) and duplicate join values are collapsed\nfunction join(tables, nullModes) {\n\tlet xVals = new Set();\n\n\tfor (let ti = 0; ti < tables.length; ti++) {\n\t\tlet t = tables[ti];\n\t\tlet xs = t[0];\n\t\tlet len = xs.length;\n\n\t\tfor (let i = 0; i < len; i++)\n\t\t\txVals.add(xs[i]);\n\t}\n\n\tlet data = [Array.from(xVals).sort((a, b) => a - b)];\n\n\tlet alignedLen = data[0].length;\n\n\tlet xIdxs = new Map();\n\n\tfor (let i = 0; i < alignedLen; i++)\n\t\txIdxs.set(data[0][i], i);\n\n\tfor (let ti = 0; ti < tables.length; ti++) {\n\t\tlet t = tables[ti];\n\t\tlet xs = t[0];\n\n\t\tfor (let si = 1; si < t.length; si++) {\n\t\t\tlet ys = t[si];\n\n\t\t\tlet yVals = Array(alignedLen).fill(undefined);\n\n\t\t\tlet nullMode = nullModes ? nullModes[ti][si] : NULL_RETAIN;\n\n\t\t\tlet nullIdxs = [];\n\n\t\t\tfor (let i = 0; i < ys.length; i++) {\n\t\t\t\tlet yVal = ys[i];\n\t\t\t\tlet alignedIdx = xIdxs.get(xs[i]);\n\n\t\t\t\tif (yVal === null) {\n\t\t\t\t\tif (nullMode != NULL_REMOVE) {\n\t\t\t\t\t\tyVals[alignedIdx] = yVal;\n\n\t\t\t\t\t\tif (nullMode == NULL_EXPAND)\n\t\t\t\t\t\t\tnullIdxs.push(alignedIdx);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tyVals[alignedIdx] = yVal;\n\t\t\t}\n\n\t\t\tnullExpand(yVals, nullIdxs, alignedLen);\n\n\t\t\tdata.push(yVals);\n\t\t}\n\t}\n\n\treturn data;\n}\n\nconst microTask = typeof queueMicrotask == \"undefined\" ? fn => Promise.resolve().then(fn) : queueMicrotask;\n\nconst months = [\n\t\"January\",\n\t\"February\",\n\t\"March\",\n\t\"April\",\n\t\"May\",\n\t\"June\",\n\t\"July\",\n\t\"August\",\n\t\"September\",\n\t\"October\",\n\t\"November\",\n\t\"December\",\n];\n\nconst days = [\n\t\"Sunday\",\n\t\"Monday\",\n\t\"Tuesday\",\n\t\"Wednesday\",\n\t\"Thursday\",\n\t\"Friday\",\n\t\"Saturday\",\n];\n\nfunction slice3(str) {\n\treturn str.slice(0, 3);\n}\n\nconst days3 = days.map(slice3);\n\nconst months3 = months.map(slice3);\n\nconst engNames = {\n\tMMMM: months,\n\tMMM:  months3,\n\tWWWW: days,\n\tWWW:  days3,\n};\n\nfunction zeroPad2(int) {\n\treturn (int < 10 ? '0' : '') + int;\n}\n\nfunction zeroPad3(int) {\n\treturn (int < 10 ? '00' : int < 100 ? '0' : '') + int;\n}\n\n/*\nfunction suffix(int) {\n\tlet mod10 = int % 10;\n\n\treturn int + (\n\t\tmod10 == 1 && int != 11 ? \"st\" :\n\t\tmod10 == 2 && int != 12 ? \"nd\" :\n\t\tmod10 == 3 && int != 13 ? \"rd\" : \"th\"\n\t);\n}\n*/\n\nconst subs = {\n\t// 2019\n\tYYYY:\td => d.getFullYear(),\n\t// 19\n\tYY:\t\td => (d.getFullYear()+'').slice(2),\n\t// July\n\tMMMM:\t(d, names) => names.MMMM[d.getMonth()],\n\t// Jul\n\tMMM:\t(d, names) => names.MMM[d.getMonth()],\n\t// 07\n\tMM:\t\td => zeroPad2(d.getMonth()+1),\n\t// 7\n\tM:\t\td => d.getMonth()+1,\n\t// 09\n\tDD:\t\td => zeroPad2(d.getDate()),\n\t// 9\n\tD:\t\td => d.getDate(),\n\t// Monday\n\tWWWW:\t(d, names) => names.WWWW[d.getDay()],\n\t// Mon\n\tWWW:\t(d, names) => names.WWW[d.getDay()],\n\t// 03\n\tHH:\t\td => zeroPad2(d.getHours()),\n\t// 3\n\tH:\t\td => d.getHours(),\n\t// 9 (12hr, unpadded)\n\th:\t\td => {let h = d.getHours(); return h == 0 ? 12 : h > 12 ? h - 12 : h;},\n\t// AM\n\tAA:\t\td => d.getHours() >= 12 ? 'PM' : 'AM',\n\t// am\n\taa:\t\td => d.getHours() >= 12 ? 'pm' : 'am',\n\t// a\n\ta:\t\td => d.getHours() >= 12 ? 'p' : 'a',\n\t// 09\n\tmm:\t\td => zeroPad2(d.getMinutes()),\n\t// 9\n\tm:\t\td => d.getMinutes(),\n\t// 09\n\tss:\t\td => zeroPad2(d.getSeconds()),\n\t// 9\n\ts:\t\td => d.getSeconds(),\n\t// 374\n\tfff:\td => zeroPad3(d.getMilliseconds()),\n};\n\nfunction fmtDate(tpl, names) {\n\tnames = names || engNames;\n\tlet parts = [];\n\n\tlet R = /\\{([a-z]+)\\}|[^{]+/gi, m;\n\n\twhile (m = R.exec(tpl))\n\t\tparts.push(m[0][0] == '{' ? subs[m[1]] : m[0]);\n\n\treturn d => {\n\t\tlet out = '';\n\n\t\tfor (let i = 0; i < parts.length; i++)\n\t\t\tout += typeof parts[i] == \"string\" ? parts[i] : parts[i](d, names);\n\n\t\treturn out;\n\t}\n}\n\nconst localTz = new Intl.DateTimeFormat().resolvedOptions().timeZone;\n\n// https://stackoverflow.com/questions/15141762/how-to-initialize-a-javascript-date-to-a-particular-time-zone/53652131#53652131\nfunction tzDate(date, tz) {\n\tlet date2;\n\n\t// perf optimization\n\tif (tz == 'UTC' || tz == 'Etc/UTC')\n\t\tdate2 = new Date(+date + date.getTimezoneOffset() * 6e4);\n\telse if (tz == localTz)\n\t\tdate2 = date;\n\telse {\n\t\tdate2 = new Date(date.toLocaleString('en-US', {timeZone: tz}));\n\t\tdate2.setMilliseconds(date.getMilliseconds());\n\t}\n\n\treturn date2;\n}\n\n//export const series = [];\n\n// default formatters:\n\nconst onlyWhole = v => v % 1 == 0;\n\nconst allMults = [1,2,2.5,5];\n\n// ...0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5\nconst decIncrs = genIncrs(10, -16, 0, allMults);\n\n// 1, 2, 2.5, 5, 10, 20, 25, 50...\nconst oneIncrs = genIncrs(10, 0, 16, allMults);\n\n// 1, 2,      5, 10, 20, 25, 50...\nconst wholeIncrs = oneIncrs.filter(onlyWhole);\n\nconst numIncrs = decIncrs.concat(oneIncrs);\n\nconst NL = \"\\n\";\n\nconst yyyy    = \"{YYYY}\";\nconst NLyyyy  = NL + yyyy;\nconst md      = \"{M}/{D}\";\nconst NLmd    = NL + md;\nconst NLmdyy  = NLmd + \"/{YY}\";\n\nconst aa      = \"{aa}\";\nconst hmm     = \"{h}:{mm}\";\nconst hmmaa   = hmm + aa;\nconst NLhmmaa = NL + hmmaa;\nconst ss      = \":{ss}\";\n\nconst _ = null;\n\nfunction genTimeStuffs(ms) {\n\tlet\ts  = ms * 1e3,\n\t\tm  = s  * 60,\n\t\th  = m  * 60,\n\t\td  = h  * 24,\n\t\tmo = d  * 30,\n\t\ty  = d  * 365;\n\n\t// min of 1e-3 prevents setting a temporal x ticks too small since Date objects cannot advance ticks smaller than 1ms\n\tlet subSecIncrs = ms == 1 ? genIncrs(10, 0, 3, allMults).filter(onlyWhole) : genIncrs(10, -3, 0, allMults);\n\n\tlet timeIncrs = subSecIncrs.concat([\n\t\t// minute divisors (# of secs)\n\t\ts,\n\t\ts * 5,\n\t\ts * 10,\n\t\ts * 15,\n\t\ts * 30,\n\t\t// hour divisors (# of mins)\n\t\tm,\n\t\tm * 5,\n\t\tm * 10,\n\t\tm * 15,\n\t\tm * 30,\n\t\t// day divisors (# of hrs)\n\t\th,\n\t\th * 2,\n\t\th * 3,\n\t\th * 4,\n\t\th * 6,\n\t\th * 8,\n\t\th * 12,\n\t\t// month divisors TODO: need more?\n\t\td,\n\t\td * 2,\n\t\td * 3,\n\t\td * 4,\n\t\td * 5,\n\t\td * 6,\n\t\td * 7,\n\t\td * 8,\n\t\td * 9,\n\t\td * 10,\n\t\td * 15,\n\t\t// year divisors (# months, approx)\n\t\tmo,\n\t\tmo * 2,\n\t\tmo * 3,\n\t\tmo * 4,\n\t\tmo * 6,\n\t\t// century divisors\n\t\ty,\n\t\ty * 2,\n\t\ty * 5,\n\t\ty * 10,\n\t\ty * 25,\n\t\ty * 50,\n\t\ty * 100,\n\t]);\n\n\t// [0]:   minimum num secs in the tick incr\n\t// [1]:   default tick format\n\t// [2-7]: rollover tick formats\n\t// [8]:   mode: 0: replace [1] -> [2-7], 1: concat [1] + [2-7]\n\tconst _timeAxisStamps = [\n\t//   tick incr    default          year                    month   day                   hour    min       sec   mode\n\t\t[y,           yyyy,            _,                      _,      _,                    _,      _,        _,       1],\n\t\t[d * 28,      \"{MMM}\",         NLyyyy,                 _,      _,                    _,      _,        _,       1],\n\t\t[d,           md,              NLyyyy,                 _,      _,                    _,      _,        _,       1],\n\t\t[h,           \"{h}\" + aa,      NLmdyy,                 _,      NLmd,                 _,      _,        _,       1],\n\t\t[m,           hmmaa,           NLmdyy,                 _,      NLmd,                 _,      _,        _,       1],\n\t\t[s,           ss,              NLmdyy + \" \" + hmmaa,   _,      NLmd + \" \" + hmmaa,   _,      NLhmmaa,  _,       1],\n\t\t[ms,          ss + \".{fff}\",   NLmdyy + \" \" + hmmaa,   _,      NLmd + \" \" + hmmaa,   _,      NLhmmaa,  _,       1],\n\t];\n\n\t// the ensures that axis ticks, values & grid are aligned to logical temporal breakpoints and not an arbitrary timestamp\n\t// https://www.timeanddate.com/time/dst/\n\t// https://www.timeanddate.com/time/dst/2019.html\n\t// https://www.epochconverter.com/timezones\n\tfunction timeAxisSplits(tzDate) {\n\t\treturn (self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace) => {\n\t\t\tlet splits = [];\n\t\t\tlet isYr = foundIncr >= y;\n\t\t\tlet isMo = foundIncr >= mo && foundIncr < y;\n\n\t\t\t// get the timezone-adjusted date\n\t\t\tlet minDate = tzDate(scaleMin);\n\t\t\tlet minDateTs = roundDec(minDate * ms, 3);\n\n\t\t\t// get ts of 12am (this lands us at or before the original scaleMin)\n\t\t\tlet minMin = mkDate(minDate.getFullYear(), isYr ? 0 : minDate.getMonth(), isMo || isYr ? 1 : minDate.getDate());\n\t\t\tlet minMinTs = roundDec(minMin * ms, 3);\n\n\t\t\tif (isMo || isYr) {\n\t\t\t\tlet moIncr = isMo ? foundIncr / mo : 0;\n\t\t\t\tlet yrIncr = isYr ? foundIncr / y  : 0;\n\t\t\t//\tlet tzOffset = scaleMin - minDateTs;\t\t// needed?\n\t\t\t\tlet split = minDateTs == minMinTs ? minDateTs : roundDec(mkDate(minMin.getFullYear() + yrIncr, minMin.getMonth() + moIncr, 1) * ms, 3);\n\t\t\t\tlet splitDate = new Date(round(split / ms));\n\t\t\t\tlet baseYear = splitDate.getFullYear();\n\t\t\t\tlet baseMonth = splitDate.getMonth();\n\n\t\t\t\tfor (let i = 0; split <= scaleMax; i++) {\n\t\t\t\t\tlet next = mkDate(baseYear + yrIncr * i, baseMonth + moIncr * i, 1);\n\t\t\t\t\tlet offs = next - tzDate(roundDec(next * ms, 3));\n\n\t\t\t\t\tsplit = roundDec((+next + offs) * ms, 3);\n\n\t\t\t\t\tif (split <= scaleMax)\n\t\t\t\t\t\tsplits.push(split);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlet incr0 = foundIncr >= d ? d : foundIncr;\n\t\t\t\tlet tzOffset = floor(scaleMin) - floor(minDateTs);\n\t\t\t\tlet split = minMinTs + tzOffset + incrRoundUp(minDateTs - minMinTs, incr0);\n\t\t\t\tsplits.push(split);\n\n\t\t\t\tlet date0 = tzDate(split);\n\n\t\t\t\tlet prevHour = date0.getHours() + (date0.getMinutes() / m) + (date0.getSeconds() / h);\n\t\t\t\tlet incrHours = foundIncr / h;\n\n\t\t\t\tlet minSpace = self.axes[axisIdx]._space;\n\t\t\t\tlet pctSpace = foundSpace / minSpace;\n\n\t\t\t\twhile (1) {\n\t\t\t\t\tsplit = roundDec(split + foundIncr, ms == 1 ? 0 : 3);\n\n\t\t\t\t\tif (split > scaleMax)\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tif (incrHours > 1) {\n\t\t\t\t\t\tlet expectedHour = floor(roundDec(prevHour + incrHours, 6)) % 24;\n\t\t\t\t\t\tlet splitDate = tzDate(split);\n\t\t\t\t\t\tlet actualHour = splitDate.getHours();\n\n\t\t\t\t\t\tlet dstShift = actualHour - expectedHour;\n\n\t\t\t\t\t\tif (dstShift > 1)\n\t\t\t\t\t\t\tdstShift = -1;\n\n\t\t\t\t\t\tsplit -= dstShift * h;\n\n\t\t\t\t\t\tprevHour = (prevHour + incrHours) % 24;\n\n\t\t\t\t\t\t// add a tick only if it's further than 70% of the min allowed label spacing\n\t\t\t\t\t\tlet prevSplit = splits[splits.length - 1];\n\t\t\t\t\t\tlet pctIncr = roundDec((split - prevSplit) / foundIncr, 3);\n\n\t\t\t\t\t\tif (pctIncr * pctSpace >= .7)\n\t\t\t\t\t\t\tsplits.push(split);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tsplits.push(split);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn splits;\n\t\t}\n\t}\n\n\treturn [\n\t\ttimeIncrs,\n\t\t_timeAxisStamps,\n\t\ttimeAxisSplits,\n\t];\n}\n\nconst [ timeIncrsMs, _timeAxisStampsMs, timeAxisSplitsMs ] = genTimeStuffs(1);\nconst [ timeIncrsS,  _timeAxisStampsS,  timeAxisSplitsS  ] = genTimeStuffs(1e-3);\n\n// base 2\ngenIncrs(2, -53, 53, [1]);\n\n/*\nconsole.log({\n\tdecIncrs,\n\toneIncrs,\n\twholeIncrs,\n\tnumIncrs,\n\ttimeIncrs,\n\tfixedDec,\n});\n*/\n\nfunction timeAxisStamps(stampCfg, fmtDate) {\n\treturn stampCfg.map(s => s.map((v, i) =>\n\t\ti == 0 || i == 8 || v == null ? v : fmtDate(i == 1 || s[8] == 0 ? v : s[1] + v)\n\t));\n}\n\n// TODO: will need to accept spaces[] and pull incr into the loop when grid will be non-uniform, eg for log scales.\n// currently we ignore this for months since they're *nearly* uniform and the added complexity is not worth it\nfunction timeAxisVals(tzDate, stamps) {\n\treturn (self, splits, axisIdx, foundSpace, foundIncr) => {\n\t\tlet s = stamps.find(s => foundIncr >= s[0]) || stamps[stamps.length - 1];\n\n\t\t// these track boundaries when a full label is needed again\n\t\tlet prevYear;\n\t\tlet prevMnth;\n\t\tlet prevDate;\n\t\tlet prevHour;\n\t\tlet prevMins;\n\t\tlet prevSecs;\n\n\t\treturn splits.map(split => {\n\t\t\tlet date = tzDate(split);\n\n\t\t\tlet newYear = date.getFullYear();\n\t\t\tlet newMnth = date.getMonth();\n\t\t\tlet newDate = date.getDate();\n\t\t\tlet newHour = date.getHours();\n\t\t\tlet newMins = date.getMinutes();\n\t\t\tlet newSecs = date.getSeconds();\n\n\t\t\tlet stamp = (\n\t\t\t\tnewYear != prevYear && s[2] ||\n\t\t\t\tnewMnth != prevMnth && s[3] ||\n\t\t\t\tnewDate != prevDate && s[4] ||\n\t\t\t\tnewHour != prevHour && s[5] ||\n\t\t\t\tnewMins != prevMins && s[6] ||\n\t\t\t\tnewSecs != prevSecs && s[7] ||\n\t\t\t\t                       s[1]\n\t\t\t);\n\n\t\t\tprevYear = newYear;\n\t\t\tprevMnth = newMnth;\n\t\t\tprevDate = newDate;\n\t\t\tprevHour = newHour;\n\t\t\tprevMins = newMins;\n\t\t\tprevSecs = newSecs;\n\n\t\t\treturn stamp(date);\n\t\t});\n\t}\n}\n\n// for when axis.values is defined as a static fmtDate template string\nfunction timeAxisVal(tzDate, dateTpl) {\n\tlet stamp = fmtDate(dateTpl);\n\treturn (self, splits, axisIdx, foundSpace, foundIncr) => splits.map(split => stamp(tzDate(split)));\n}\n\nfunction mkDate(y, m, d) {\n\treturn new Date(y, m, d);\n}\n\nfunction timeSeriesStamp(stampCfg, fmtDate) {\n\treturn fmtDate(stampCfg);\n}\nconst _timeSeriesStamp = '{YYYY}-{MM}-{DD} {h}:{mm}{aa}';\n\nfunction timeSeriesVal(tzDate, stamp) {\n\treturn (self, val) => stamp(tzDate(val));\n}\n\nfunction legendStroke(self, seriesIdx) {\n\tlet s = self.series[seriesIdx];\n\treturn s.width ? s.stroke(self, seriesIdx) : s.points.width ? s.points.stroke(self, seriesIdx) : null;\n}\n\nfunction legendFill(self, seriesIdx) {\n\treturn self.series[seriesIdx].fill(self, seriesIdx);\n}\n\nconst legendOpts = {\n\tshow: true,\n\tlive: true,\n\tisolate: false,\n\tmount: noop,\n\tmarkers: {\n\t\tshow: true,\n\t\twidth: 2,\n\t\tstroke: legendStroke,\n\t\tfill: legendFill,\n\t\tdash: \"solid\",\n\t},\n\tidx: null,\n\tidxs: null,\n\tvalues: [],\n};\n\nfunction cursorPointShow(self, si) {\n\tlet o = self.cursor.points;\n\n\tlet pt = placeDiv();\n\n\tlet size = o.size(self, si);\n\tsetStylePx(pt, WIDTH, size);\n\tsetStylePx(pt, HEIGHT, size);\n\n\tlet mar = size / -2;\n\tsetStylePx(pt, \"marginLeft\", mar);\n\tsetStylePx(pt, \"marginTop\", mar);\n\n\tlet width = o.width(self, si, size);\n\twidth && setStylePx(pt, \"borderWidth\", width);\n\n\treturn pt;\n}\n\nfunction cursorPointFill(self, si) {\n\tlet sp = self.series[si].points;\n\treturn sp._fill || sp._stroke;\n}\n\nfunction cursorPointStroke(self, si) {\n\tlet sp = self.series[si].points;\n\treturn sp._stroke || sp._fill;\n}\n\nfunction cursorPointSize(self, si) {\n\tlet sp = self.series[si].points;\n\treturn ptDia(sp.width, 1);\n}\n\nfunction dataIdx(self, seriesIdx, cursorIdx) {\n\treturn cursorIdx;\n}\n\nconst moveTuple = [0,0];\n\nfunction cursorMove(self, mouseLeft1, mouseTop1) {\n\tmoveTuple[0] = mouseLeft1;\n\tmoveTuple[1] = mouseTop1;\n\treturn moveTuple;\n}\n\nfunction filtBtn0(self, targ, handle) {\n\treturn e => {\n\t\te.button == 0 && handle(e);\n\t};\n}\n\nfunction passThru(self, targ, handle) {\n\treturn handle;\n}\n\nconst cursorOpts = {\n\tshow: true,\n\tx: true,\n\ty: true,\n\tlock: false,\n\tmove: cursorMove,\n\tpoints: {\n\t\tshow:   cursorPointShow,\n\t\tsize:   cursorPointSize,\n\t\twidth:  0,\n\t\tstroke: cursorPointStroke,\n\t\tfill:   cursorPointFill,\n\t},\n\n\tbind: {\n\t\tmousedown:   filtBtn0,\n\t\tmouseup:     filtBtn0,\n\t\tclick:       filtBtn0,\n\t\tdblclick:    filtBtn0,\n\n\t\tmousemove:   passThru,\n\t\tmouseleave:  passThru,\n\t\tmouseenter:  passThru,\n\t},\n\n\tdrag: {\n\t\tsetScale: true,\n\t\tx: true,\n\t\ty: false,\n\t\tdist: 0,\n\t\tuni: null,\n\t\t_x: false,\n\t\t_y: false,\n\t},\n\n\tfocus: {\n\t\tprox: -1,\n\t},\n\n\tleft: -10,\n\ttop: -10,\n\tidx: null,\n\tdataIdx,\n\tidxs: null,\n};\n\nconst axisLines = {\n\tshow: true,\n\tstroke: \"rgba(0,0,0,0.07)\",\n\twidth: 2,\n//\tdash: [],\n};\n\nconst grid = assign({}, axisLines, {\n\tfilter: retArg1,\n});\n\nconst ticks = assign({}, grid, {\n\tsize: 10,\n});\n\nconst border = assign({}, axisLines, {\n\tshow: false,\n});\n\nconst font      = '12px system-ui, -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"';\nconst labelFont = \"bold \" + font;\nconst lineMult = 1.5;\t\t// font-size multiplier\n\nconst xAxisOpts = {\n\tshow: true,\n\tscale: \"x\",\n\tstroke: hexBlack,\n\tspace: 50,\n\tgap: 5,\n\tsize: 50,\n\tlabelGap: 0,\n\tlabelSize: 30,\n\tlabelFont,\n\tside: 2,\n//\tclass: \"x-vals\",\n//\tincrs: timeIncrs,\n//\tvalues: timeVals,\n//\tfilter: retArg1,\n\tgrid,\n\tticks,\n\tborder,\n\tfont,\n\trotate: 0,\n};\n\nconst numSeriesLabel = \"Value\";\nconst timeSeriesLabel = \"Time\";\n\nconst xSeriesOpts = {\n\tshow: true,\n\tscale: \"x\",\n\tauto: false,\n\tsorted: 1,\n//\tlabel: \"Time\",\n//\tvalue: v => stamp(new Date(v * 1e3)),\n\n\t// internal caches\n\tmin: inf,\n\tmax: -inf,\n\tidxs: [],\n};\n\nfunction numAxisVals(self, splits, axisIdx, foundSpace, foundIncr) {\n\treturn splits.map(v => v == null ? \"\" : fmtNum(v));\n}\n\nfunction numAxisSplits(self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace, forceMin) {\n\tlet splits = [];\n\n\tlet numDec = fixedDec.get(foundIncr) || 0;\n\n\tscaleMin = forceMin ? scaleMin : roundDec(incrRoundUp(scaleMin, foundIncr), numDec);\n\n\tfor (let val = scaleMin; val <= scaleMax; val = roundDec(val + foundIncr, numDec))\n\t\tsplits.push(Object.is(val, -0) ? 0 : val);\t\t// coalesces -0\n\n\treturn splits;\n}\n\n// this doesnt work for sin, which needs to come off from 0 independently in pos and neg dirs\nfunction logAxisSplits(self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace, forceMin) {\n\tconst splits = [];\n\n\tconst logBase = self.scales[self.axes[axisIdx].scale].log;\n\n\tconst logFn = logBase == 10 ? log10 : log2;\n\n\tconst exp = floor(logFn(scaleMin));\n\n\tfoundIncr = pow(logBase, exp);\n\n\tif (exp < 0)\n\t\tfoundIncr = roundDec(foundIncr, -exp);\n\n\tlet split = scaleMin;\n\n\tdo {\n\t\tsplits.push(split);\n\t\tsplit = roundDec(split + foundIncr, fixedDec.get(foundIncr));\n\n\t\tif (split >= foundIncr * logBase)\n\t\t\tfoundIncr = split;\n\n\t} while (split <= scaleMax);\n\n\treturn splits;\n}\n\nfunction asinhAxisSplits(self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace, forceMin) {\n\tlet sc = self.scales[self.axes[axisIdx].scale];\n\n\tlet linthresh = sc.asinh;\n\n\tlet posSplits = scaleMax > linthresh ? logAxisSplits(self, axisIdx, max(linthresh, scaleMin), scaleMax, foundIncr) : [linthresh];\n\tlet zero = scaleMax >= 0 && scaleMin <= 0 ? [0] : [];\n\tlet negSplits = scaleMin < -linthresh ? logAxisSplits(self, axisIdx, max(linthresh, -scaleMax), -scaleMin, foundIncr): [linthresh];\n\n\treturn negSplits.reverse().map(v => -v).concat(zero, posSplits);\n}\n\nconst RE_ALL   = /./;\nconst RE_12357 = /[12357]/;\nconst RE_125   = /[125]/;\nconst RE_1     = /1/;\n\nfunction log10AxisValsFilt(self, splits, axisIdx, foundSpace, foundIncr) {\n\tlet axis = self.axes[axisIdx];\n\tlet scaleKey = axis.scale;\n\tlet sc = self.scales[scaleKey];\n\n\tif (sc.distr == 3 && sc.log == 2)\n\t\treturn splits;\n\n\tlet valToPos = self.valToPos;\n\n\tlet minSpace = axis._space;\n\n\tlet _10 = valToPos(10, scaleKey);\n\n\tlet re = (\n\t\tvalToPos(9, scaleKey) - _10 >= minSpace ? RE_ALL :\n\t\tvalToPos(7, scaleKey) - _10 >= minSpace ? RE_12357 :\n\t\tvalToPos(5, scaleKey) - _10 >= minSpace ? RE_125 :\n\t\tRE_1\n\t);\n\n\treturn splits.map(v => ((sc.distr == 4 && v == 0) || re.test(v)) ? v : null);\n}\n\nfunction numSeriesVal(self, val) {\n\treturn val == null ? \"\" : fmtNum(val);\n}\n\nconst yAxisOpts = {\n\tshow: true,\n\tscale: \"y\",\n\tstroke: hexBlack,\n\tspace: 30,\n\tgap: 5,\n\tsize: 50,\n\tlabelGap: 0,\n\tlabelSize: 30,\n\tlabelFont,\n\tside: 3,\n//\tclass: \"y-vals\",\n//\tincrs: numIncrs,\n//\tvalues: (vals, space) => vals,\n//\tfilter: retArg1,\n\tgrid,\n\tticks,\n\tborder,\n\tfont,\n\trotate: 0,\n};\n\n// takes stroke width\nfunction ptDia(width, mult) {\n\tlet dia = 3 + (width || 1) * 2;\n\treturn roundDec(dia * mult, 3);\n}\n\nfunction seriesPointsShow(self, si) {\n\tlet { scale, idxs } = self.series[0];\n\tlet xData = self._data[0];\n\tlet p0 = self.valToPos(xData[idxs[0]], scale, true);\n\tlet p1 = self.valToPos(xData[idxs[1]], scale, true);\n\tlet dim = abs(p1 - p0);\n\n\tlet s = self.series[si];\n//\tconst dia = ptDia(s.width, pxRatio);\n\tlet maxPts = dim / (s.points.space * pxRatio);\n\treturn idxs[1] - idxs[0] <= maxPts;\n}\n\nconst facet = {\n\tscale: null,\n\tauto: true,\n\tsorted: 0,\n\n\t// internal caches\n\tmin: inf,\n\tmax: -inf,\n};\n\nconst gaps = (self, seriesIdx, idx0, idx1, nullGaps) => nullGaps;\n\nconst xySeriesOpts = {\n\tshow: true,\n\tauto: true,\n\tsorted: 0,\n\tgaps,\n\talpha: 1,\n\tfacets: [\n\t\tassign({}, facet, {scale: 'x'}),\n\t\tassign({}, facet, {scale: 'y'}),\n\t],\n};\n\nconst ySeriesOpts = {\n\tscale: \"y\",\n\tauto: true,\n\tsorted: 0,\n\tshow: true,\n\tspanGaps: false,\n\tgaps,\n\talpha: 1,\n\tpoints: {\n\t\tshow: seriesPointsShow,\n\t\tfilter: null,\n\t//  paths:\n\t//\tstroke: \"#000\",\n\t//\tfill: \"#fff\",\n\t//\twidth: 1,\n\t//\tsize: 10,\n\t},\n//\tlabel: \"Value\",\n//\tvalue: v => v,\n\tvalues: null,\n\n\t// internal caches\n\tmin: inf,\n\tmax: -inf,\n\tidxs: [],\n\n\tpath: null,\n\tclip: null,\n};\n\nfunction clampScale(self, val, scaleMin, scaleMax, scaleKey) {\n/*\n\tif (val < 0) {\n\t\tlet cssHgt = self.bbox.height / pxRatio;\n\t\tlet absPos = self.valToPos(abs(val), scaleKey);\n\t\tlet fromBtm = cssHgt - absPos;\n\t\treturn self.posToVal(cssHgt + fromBtm, scaleKey);\n\t}\n*/\n\treturn scaleMin / 10;\n}\n\nconst xScaleOpts = {\n\ttime: FEAT_TIME,\n\tauto: true,\n\tdistr: 1,\n\tlog: 10,\n\tasinh: 1,\n\tmin: null,\n\tmax: null,\n\tdir: 1,\n\tori: 0,\n};\n\nconst yScaleOpts = assign({}, xScaleOpts, {\n\ttime: false,\n\tori: 1,\n});\n\nconst syncs = {};\n\nfunction _sync(key, opts) {\n\tlet s = syncs[key];\n\n\tif (!s) {\n\t\ts = {\n\t\t\tkey,\n\t\t\tplots: [],\n\t\t\tsub(plot) {\n\t\t\t\ts.plots.push(plot);\n\t\t\t},\n\t\t\tunsub(plot) {\n\t\t\t\ts.plots = s.plots.filter(c => c != plot);\n\t\t\t},\n\t\t\tpub(type, self, x, y, w, h, i) {\n\t\t\t\tfor (let j = 0; j < s.plots.length; j++)\n\t\t\t\t\ts.plots[j] != self && s.plots[j].pub(type, self, x, y, w, h, i);\n\t\t\t},\n\t\t};\n\n\t\tif (key != null)\n\t\t\tsyncs[key] = s;\n\t}\n\n\treturn s;\n}\n\nconst BAND_CLIP_FILL   = 1 << 0;\nconst BAND_CLIP_STROKE = 1 << 1;\n\nfunction orient(u, seriesIdx, cb) {\n\tconst mode = u.mode;\n\tconst series = u.series[seriesIdx];\n\tconst data = mode == 2 ? u._data[seriesIdx] : u._data;\n\tconst scales = u.scales;\n\tconst bbox   = u.bbox;\n\n\tlet dx = data[0],\n\t\tdy = mode == 2 ? data[1] : data[seriesIdx],\n\t\tsx = mode == 2 ? scales[series.facets[0].scale] : scales[u.series[0].scale],\n\t\tsy = mode == 2 ? scales[series.facets[1].scale] : scales[series.scale],\n\t\tl = bbox.left,\n\t\tt = bbox.top,\n\t\tw = bbox.width,\n\t\th = bbox.height,\n\t\tH = u.valToPosH,\n\t\tV = u.valToPosV;\n\n\treturn (sx.ori == 0\n\t\t? cb(\n\t\t\tseries,\n\t\t\tdx,\n\t\t\tdy,\n\t\t\tsx,\n\t\t\tsy,\n\t\t\tH,\n\t\t\tV,\n\t\t\tl,\n\t\t\tt,\n\t\t\tw,\n\t\t\th,\n\t\t\tmoveToH,\n\t\t\tlineToH,\n\t\t\trectH,\n\t\t\tarcH,\n\t\t\tbezierCurveToH,\n\t\t)\n\t\t: cb(\n\t\t\tseries,\n\t\t\tdx,\n\t\t\tdy,\n\t\t\tsx,\n\t\t\tsy,\n\t\t\tV,\n\t\t\tH,\n\t\t\tt,\n\t\t\tl,\n\t\t\th,\n\t\t\tw,\n\t\t\tmoveToV,\n\t\t\tlineToV,\n\t\t\trectV,\n\t\t\tarcV,\n\t\t\tbezierCurveToV,\n\t\t)\n\t);\n}\n\nfunction bandFillClipDirs(self, seriesIdx) {\n\tlet fillDir = 0;\n\n\t// 2 bits, -1 | 1\n\tlet clipDirs = 0;\n\n\tlet bands = ifNull(self.bands, EMPTY_ARR);\n\n\tfor (let i = 0; i < bands.length; i++) {\n\t\tlet b = bands[i];\n\n\t\t// is a \"from\" band edge\n\t\tif (b.series[0] == seriesIdx)\n\t\t\tfillDir = b.dir;\n\t\t// is a \"to\" band edge\n\t\telse if (b.series[1] == seriesIdx) {\n\t\t\tif (b.dir == 1)\n\t\t\t\tclipDirs |= 1;\n\t\t\telse\n\t\t\t\tclipDirs |= 2;\n\t\t}\n\t}\n\n\treturn [\n\t\tfillDir,\n\t\t(\n\t\t\tclipDirs == 1 ? -1 : // neg only\n\t\t\tclipDirs == 2 ?  1 : // pos only\n\t\t\tclipDirs == 3 ?  2 : // both\n\t\t\t                 0   // neither\n\t\t)\n\t];\n}\n\nfunction seriesFillTo(self, seriesIdx, dataMin, dataMax, bandFillDir) {\n\tlet mode = self.mode;\n\tlet series = self.series[seriesIdx];\n\tlet scaleKey = mode == 2 ? series.facets[1].scale : series.scale;\n\tlet scale = self.scales[scaleKey];\n\n\treturn (\n\t\tbandFillDir == -1 ? scale.min :\n\t\tbandFillDir ==  1 ? scale.max :\n\t\tscale.distr ==  3 ? (\n\t\t\tscale.dir == 1 ? scale.min :\n\t\t\tscale.max\n\t\t) : 0\n\t);\n}\n\n// creates inverted band clip path (from stroke path -> yMax || yMin)\n// clipDir is always inverse of fillDir\n// default clip dir is upwards (1), since default band fill is downwards/fillBelowTo (-1) (highIdx -> lowIdx)\nfunction clipBandLine(self, seriesIdx, idx0, idx1, strokePath, clipDir) {\n\treturn orient(self, seriesIdx, (series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {\n\t\tlet pxRound = series.pxRound;\n\n\t\tconst dir = scaleX.dir * (scaleX.ori == 0 ? 1 : -1);\n\t\tconst lineTo = scaleX.ori == 0 ? lineToH : lineToV;\n\n\t\tlet frIdx, toIdx;\n\n\t\tif (dir == 1) {\n\t\t\tfrIdx = idx0;\n\t\t\ttoIdx = idx1;\n\t\t}\n\t\telse {\n\t\t\tfrIdx = idx1;\n\t\t\ttoIdx = idx0;\n\t\t}\n\n\t\t// path start\n\t\tlet x0 = pxRound(valToPosX(dataX[frIdx], scaleX, xDim, xOff));\n\t\tlet y0 = pxRound(valToPosY(dataY[frIdx], scaleY, yDim, yOff));\n\t\t// path end x\n\t\tlet x1 = pxRound(valToPosX(dataX[toIdx], scaleX, xDim, xOff));\n\t\t// upper or lower y limit\n\t\tlet yLimit = pxRound(valToPosY(clipDir == 1 ? scaleY.max : scaleY.min, scaleY, yDim, yOff));\n\n\t\tlet clip = new Path2D(strokePath);\n\n\t\tlineTo(clip, x1, yLimit);\n\t\tlineTo(clip, x0, yLimit);\n\t\tlineTo(clip, x0, y0);\n\n\t\treturn clip;\n\t});\n}\n\nfunction clipGaps(gaps, ori, plotLft, plotTop, plotWid, plotHgt) {\n\tlet clip = null;\n\n\t// create clip path (invert gaps and non-gaps)\n\tif (gaps.length > 0) {\n\t\tclip = new Path2D();\n\n\t\tconst rect = ori == 0 ? rectH : rectV;\n\n\t\tlet prevGapEnd = plotLft;\n\n\t\tfor (let i = 0; i < gaps.length; i++) {\n\t\t\tlet g = gaps[i];\n\n\t\t\tif (g[1] > g[0]) {\n\t\t\t\tlet w = g[0] - prevGapEnd;\n\n\t\t\t\tw > 0 && rect(clip, prevGapEnd, plotTop, w, plotTop + plotHgt);\n\n\t\t\t\tprevGapEnd = g[1];\n\t\t\t}\n\t\t}\n\n\t\tlet w = plotLft + plotWid - prevGapEnd;\n\n\t\tw > 0 && rect(clip, prevGapEnd, plotTop, w, plotTop + plotHgt);\n\t}\n\n\treturn clip;\n}\n\nfunction addGap(gaps, fromX, toX) {\n\tlet prevGap = gaps[gaps.length - 1];\n\n\tif (prevGap && prevGap[0] == fromX)\t\t\t// TODO: gaps must be encoded at stroke widths?\n\t\tprevGap[1] = toX;\n\telse\n\t\tgaps.push([fromX, toX]);\n}\n\nfunction findGaps(xs, ys, idx0, idx1, dir, pixelForX, align) {\n\tlet gaps = [];\n\n\tfor (let i = dir == 1 ? idx0 : idx1; i >= idx0 && i <= idx1; i += dir) {\n\t\tlet yVal = ys[i];\n\n\t\tif (yVal === null) {\n\t\t\tlet fr = i, to = i;\n\n\t\t\tif (dir == 1) {\n\t\t\t\twhile (++i <= idx1 && ys[i] === null)\n\t\t\t\t\tto = i;\n\t\t\t}\n\t\t\telse {\n\t\t\t\twhile (--i >= idx0 && ys[i] === null)\n\t\t\t\t\tto = i;\n\t\t\t}\n\n\t\t\tlet frPx = pixelForX(xs[fr]);\n\t\t\tlet toPx = to == fr ? frPx : pixelForX(xs[to]);\n\n\t\t\t// if value adjacent to edge null is same pixel, then it's partially\n\t\t\t// filled and gap should start at next pixel\n\t\t\tlet frPx2 = align <= 0 ? pixelForX(xs[fr-dir]) : frPx;\n\t\t//\tif (frPx2 == frPx)\n\t\t//\t\tfrPx++;\n\t\t//\telse\n\t\t\t\tfrPx = frPx2;\n\n\t\t\tlet toPx2 = align >= 0 ? pixelForX(xs[to+dir]) : toPx;\n\t\t//\tif (toPx2 == toPx)\n\t\t//\t\ttoPx--;\n\t\t//\telse\n\t\t\t\ttoPx = toPx2;\n\n\t\t\tif (toPx >= frPx)\n\t\t\t\tgaps.push([frPx, toPx]); // addGap\n\t\t}\n\t}\n\n\treturn gaps;\n}\n\nfunction pxRoundGen(pxAlign) {\n\treturn pxAlign == 0 ? retArg0 : pxAlign == 1 ? round : v => incrRound(v, pxAlign);\n}\n\nfunction rect(ori) {\n\tlet moveTo = ori == 0 ?\n\t\tmoveToH :\n\t\tmoveToV;\n\n\tlet arcTo = ori == 0 ?\n\t\t(p, x1, y1, x2, y2, r) => { p.arcTo(x1, y1, x2, y2, r); } :\n\t\t(p, y1, x1, y2, x2, r) => { p.arcTo(x1, y1, x2, y2, r); };\n\n\tlet rect = ori == 0 ?\n\t\t(p, x, y, w, h) => { p.rect(x, y, w, h); } :\n\t\t(p, y, x, h, w) => { p.rect(x, y, w, h); };\n\n\treturn (p, x, y, w, h, r = 0) => {\n\t\tif (r == 0)\n\t\t\trect(p, x, y, w, h);\n\t\telse {\n\t\t\tr = min(r, w / 2, h / 2);\n\n\t\t\t// adapted from https://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-using-html-canvas/7838871#7838871\n\t\t\tmoveTo(p, x + r, y);\n\t\t\tarcTo(p, x + w, y, x + w, y + h, r);\n\t\t\tarcTo(p, x + w, y + h, x, y + h, r);\n\t\t\tarcTo(p, x, y + h, x, y, r);\n\t\t\tarcTo(p, x, y, x + w, y, r);\n\t\t\tp.closePath();\n\t\t}\n\t};\n}\n\n// orientation-inverting canvas functions\nconst moveToH = (p, x, y) => { p.moveTo(x, y); };\nconst moveToV = (p, y, x) => { p.moveTo(x, y); };\nconst lineToH = (p, x, y) => { p.lineTo(x, y); };\nconst lineToV = (p, y, x) => { p.lineTo(x, y); };\nconst rectH = rect(0);\nconst rectV = rect(1);\nconst arcH = (p, x, y, r, startAngle, endAngle) => { p.arc(x, y, r, startAngle, endAngle); };\nconst arcV = (p, y, x, r, startAngle, endAngle) => { p.arc(x, y, r, startAngle, endAngle); };\nconst bezierCurveToH = (p, bp1x, bp1y, bp2x, bp2y, p2x, p2y) => { p.bezierCurveTo(bp1x, bp1y, bp2x, bp2y, p2x, p2y); };\nconst bezierCurveToV = (p, bp1y, bp1x, bp2y, bp2x, p2y, p2x) => { p.bezierCurveTo(bp1x, bp1y, bp2x, bp2y, p2x, p2y); };\n\n// TODO: drawWrap(seriesIdx, drawPoints) (save, restore, translate, clip)\nfunction points(opts) {\n\treturn (u, seriesIdx, idx0, idx1, filtIdxs) => {\n\t//\tlog(\"drawPoints()\", arguments);\n\n\t\treturn orient(u, seriesIdx, (series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {\n\t\t\tlet { pxRound, points } = series;\n\n\t\t\tlet moveTo, arc;\n\n\t\t\tif (scaleX.ori == 0) {\n\t\t\t\tmoveTo = moveToH;\n\t\t\t\tarc = arcH;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tmoveTo = moveToV;\n\t\t\t\tarc = arcV;\n\t\t\t}\n\n\t\t\tconst width = roundDec(points.width * pxRatio, 3);\n\n\t\t\tlet rad = (points.size - points.width) / 2 * pxRatio;\n\t\t\tlet dia = roundDec(rad * 2, 3);\n\n\t\t\tlet fill = new Path2D();\n\t\t\tlet clip = new Path2D();\n\n\t\t\tlet { left: lft, top: top, width: wid, height: hgt } = u.bbox;\n\n\t\t\trectH(clip,\n\t\t\t\tlft - dia,\n\t\t\t\ttop - dia,\n\t\t\t\twid + dia * 2,\n\t\t\t\thgt + dia * 2,\n\t\t\t);\n\n\t\t\tconst drawPoint = pi => {\n\t\t\t\tif (dataY[pi] != null) {\n\t\t\t\t\tlet x = pxRound(valToPosX(dataX[pi], scaleX, xDim, xOff));\n\t\t\t\t\tlet y = pxRound(valToPosY(dataY[pi], scaleY, yDim, yOff));\n\n\t\t\t\t\tmoveTo(fill, x + rad, y);\n\t\t\t\t\tarc(fill, x, y, rad, 0, PI * 2);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tif (filtIdxs)\n\t\t\t\tfiltIdxs.forEach(drawPoint);\n\t\t\telse {\n\t\t\t\tfor (let pi = idx0; pi <= idx1; pi++)\n\t\t\t\t\tdrawPoint(pi);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tstroke: width > 0 ? fill : null,\n\t\t\t\tfill,\n\t\t\t\tclip,\n\t\t\t\tflags: BAND_CLIP_FILL | BAND_CLIP_STROKE,\n\t\t\t};\n\t\t});\n\t};\n}\n\nfunction _drawAcc(lineTo) {\n\treturn (stroke, accX, minY, maxY, inY, outY) => {\n\t\tif (minY != maxY) {\n\t\t\tif (inY != minY && outY != minY)\n\t\t\t\tlineTo(stroke, accX, minY);\n\t\t\tif (inY != maxY && outY != maxY)\n\t\t\t\tlineTo(stroke, accX, maxY);\n\n\t\t\tlineTo(stroke, accX, outY);\n\t\t}\n\t};\n}\n\nconst drawAccH = _drawAcc(lineToH);\nconst drawAccV = _drawAcc(lineToV);\n\nfunction linear(opts) {\n\tconst alignGaps = ifNull(opts?.alignGaps, 0);\n\n\treturn (u, seriesIdx, idx0, idx1) => {\n\t\treturn orient(u, seriesIdx, (series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {\n\t\t\tlet pxRound = series.pxRound;\n\n\t\t\tlet pixelForX = val => pxRound(valToPosX(val, scaleX, xDim, xOff));\n\t\t\tlet pixelForY = val => pxRound(valToPosY(val, scaleY, yDim, yOff));\n\n\t\t\tlet lineTo, drawAcc;\n\n\t\t\tif (scaleX.ori == 0) {\n\t\t\t\tlineTo = lineToH;\n\t\t\t\tdrawAcc = drawAccH;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlineTo = lineToV;\n\t\t\t\tdrawAcc = drawAccV;\n\t\t\t}\n\n\t\t\tconst dir = scaleX.dir * (scaleX.ori == 0 ? 1 : -1);\n\n\t\t\tconst _paths = {stroke: new Path2D(), fill: null, clip: null, band: null, gaps: null, flags: BAND_CLIP_FILL};\n\t\t\tconst stroke = _paths.stroke;\n\n\t\t\tlet minY = inf,\n\t\t\t\tmaxY = -inf,\n\t\t\t\tinY, outY, drawnAtX;\n\n\t\t\tlet accX = pixelForX(dataX[dir == 1 ? idx0 : idx1]);\n\n\t\t\t// data edges\n\t\t\tlet lftIdx = nonNullIdx(dataY, idx0, idx1,  1 * dir);\n\t\t\tlet rgtIdx = nonNullIdx(dataY, idx0, idx1, -1 * dir);\n\t\t\tlet lftX   =  pixelForX(dataX[lftIdx]);\n\t\t\tlet rgtX   =  pixelForX(dataX[rgtIdx]);\n\n\t\t\tfor (let i = dir == 1 ? idx0 : idx1; i >= idx0 && i <= idx1; i += dir) {\n\t\t\t\tlet x = pixelForX(dataX[i]);\n\n\t\t\t\tif (x == accX) {\n\t\t\t\t\tif (dataY[i] != null) {\n\t\t\t\t\t\toutY = pixelForY(dataY[i]);\n\n\t\t\t\t\t\tif (minY == inf) {\n\t\t\t\t\t\t\tlineTo(stroke, x, outY);\n\t\t\t\t\t\t\tinY = outY;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tminY = min(outY, minY);\n\t\t\t\t\t\tmaxY = max(outY, maxY);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (minY != inf) {\n\t\t\t\t\t\tdrawAcc(stroke, accX, minY, maxY, inY, outY);\n\t\t\t\t\t\tdrawnAtX = accX;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (dataY[i] != null) {\n\t\t\t\t\t\toutY = pixelForY(dataY[i]);\n\t\t\t\t\t\tlineTo(stroke, x, outY);\n\t\t\t\t\t\tminY = maxY = inY = outY;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tminY = inf;\n\t\t\t\t\t\tmaxY = -inf;\n\t\t\t\t\t}\n\n\t\t\t\t\taccX = x;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (minY != inf && minY != maxY && drawnAtX != accX)\n\t\t\t\tdrawAcc(stroke, accX, minY, maxY, inY, outY);\n\n\t\t\tlet [ bandFillDir, bandClipDir ] = bandFillClipDirs(u, seriesIdx);\n\n\t\t\tif (series.fill != null || bandFillDir != 0) {\n\t\t\t\tlet fill = _paths.fill = new Path2D(stroke);\n\n\t\t\t\tlet fillToVal = series.fillTo(u, seriesIdx, series.min, series.max, bandFillDir);\n\t\t\t\tlet fillToY = pixelForY(fillToVal);\n\n\t\t\t\tlineTo(fill, rgtX, fillToY);\n\t\t\t\tlineTo(fill, lftX, fillToY);\n\t\t\t}\n\n\t\t\tif (!series.spanGaps) {\n\t\t\t//\tconsole.time('gaps');\n\t\t\t\tlet gaps = [];\n\n\t\t\t\tgaps.push(...findGaps(dataX, dataY, idx0, idx1, dir, pixelForX, alignGaps));\n\n\t\t\t//\tconsole.timeEnd('gaps');\n\n\t\t\t//\tconsole.log('gaps', JSON.stringify(gaps));\n\n\t\t\t\t_paths.gaps = gaps = series.gaps(u, seriesIdx, idx0, idx1, gaps);\n\n\t\t\t\t_paths.clip = clipGaps(gaps, scaleX.ori, xOff, yOff, xDim, yDim);\n\t\t\t}\n\n\t\t\tif (bandClipDir != 0) {\n\t\t\t\t_paths.band = bandClipDir == 2 ? [\n\t\t\t\t\tclipBandLine(u, seriesIdx, idx0, idx1, stroke, -1),\n\t\t\t\t\tclipBandLine(u, seriesIdx, idx0, idx1, stroke,  1),\n\t\t\t\t] : clipBandLine(u, seriesIdx, idx0, idx1, stroke, bandClipDir);\n\t\t\t}\n\n\t\t\treturn _paths;\n\t\t});\n\t};\n}\n\n// BUG: align: -1 behaves like align: 1 when scale.dir: -1\nfunction stepped(opts) {\n\tconst align = ifNull(opts.align, 1);\n\t// whether to draw ascenders/descenders at null/gap bondaries\n\tconst ascDesc = ifNull(opts.ascDesc, false);\n\tconst alignGaps = ifNull(opts.alignGaps, 0);\n\tconst extend = ifNull(opts.extend, false);\n\n\treturn (u, seriesIdx, idx0, idx1) => {\n\t\treturn orient(u, seriesIdx, (series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {\n\t\t\tlet pxRound = series.pxRound;\n\n\t\t\tlet { left, width } = u.bbox;\n\n\t\t\tlet pixelForX = val => pxRound(valToPosX(val, scaleX, xDim, xOff));\n\t\t\tlet pixelForY = val => pxRound(valToPosY(val, scaleY, yDim, yOff));\n\n\t\t\tlet lineTo = scaleX.ori == 0 ? lineToH : lineToV;\n\n\t\t\tconst _paths = {stroke: new Path2D(), fill: null, clip: null, band: null, gaps: null, flags: BAND_CLIP_FILL};\n\t\t\tconst stroke = _paths.stroke;\n\n\t\t\tconst dir = scaleX.dir * (scaleX.ori == 0 ? 1 : -1);\n\n\t\t\tidx0 = nonNullIdx(dataY, idx0, idx1,  1);\n\t\t\tidx1 = nonNullIdx(dataY, idx0, idx1, -1);\n\n\t\t\tlet prevYPos  = pixelForY(dataY[dir == 1 ? idx0 : idx1]);\n\t\t\tlet firstXPos = pixelForX(dataX[dir == 1 ? idx0 : idx1]);\n\t\t\tlet prevXPos = firstXPos;\n\n\t\t\tlet firstXPosExt = firstXPos;\n\n\t\t\tif (extend && align == -1) {\n\t\t\t\tfirstXPosExt = left;\n\t\t\t\tlineTo(stroke, firstXPosExt, prevYPos);\n\t\t\t}\n\n\t\t\tlineTo(stroke, firstXPos, prevYPos);\n\n\t\t\tfor (let i = dir == 1 ? idx0 : idx1; i >= idx0 && i <= idx1; i += dir) {\n\t\t\t\tlet yVal1 = dataY[i];\n\n\t\t\t\tif (yVal1 == null)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tlet x1 = pixelForX(dataX[i]);\n\t\t\t\tlet y1 = pixelForY(yVal1);\n\n\t\t\t\tif (align == 1)\n\t\t\t\t\tlineTo(stroke, x1, prevYPos);\n\t\t\t\telse\n\t\t\t\t\tlineTo(stroke, prevXPos, y1);\n\n\t\t\t\tlineTo(stroke, x1, y1);\n\n\t\t\t\tprevYPos = y1;\n\t\t\t\tprevXPos = x1;\n\t\t\t}\n\n\t\t\tlet prevXPosExt = prevXPos;\n\n\t\t\tif (extend && align == 1) {\n\t\t\t\tprevXPosExt = left + width;\n\t\t\t\tlineTo(stroke, prevXPosExt, prevYPos);\n\t\t\t}\n\n\t\t\tlet [ bandFillDir, bandClipDir ] = bandFillClipDirs(u, seriesIdx);\n\n\t\t\tif (series.fill != null || bandFillDir != 0) {\n\t\t\t\tlet fill = _paths.fill = new Path2D(stroke);\n\n\t\t\t\tlet fillTo = series.fillTo(u, seriesIdx, series.min, series.max, bandFillDir);\n\t\t\t\tlet fillToY = pixelForY(fillTo);\n\n\t\t\t\tlineTo(fill, prevXPosExt, fillToY);\n\t\t\t\tlineTo(fill, firstXPosExt, fillToY);\n\t\t\t}\n\n\t\t\tif (!series.spanGaps) {\n\t\t\t//\tconsole.time('gaps');\n\t\t\t\tlet gaps = [];\n\n\t\t\t\tgaps.push(...findGaps(dataX, dataY, idx0, idx1, dir, pixelForX, alignGaps));\n\n\t\t\t//\tconsole.timeEnd('gaps');\n\n\t\t\t//\tconsole.log('gaps', JSON.stringify(gaps));\n\n\t\t\t\t// expand/contract clips for ascenders/descenders\n\t\t\t\tlet halfStroke = (series.width * pxRatio) / 2;\n\t\t\t\tlet startsOffset = (ascDesc || align ==  1) ?  halfStroke : -halfStroke;\n\t\t\t\tlet endsOffset   = (ascDesc || align == -1) ? -halfStroke :  halfStroke;\n\n\t\t\t\tgaps.forEach(g => {\n\t\t\t\t\tg[0] += startsOffset;\n\t\t\t\t\tg[1] += endsOffset;\n\t\t\t\t});\n\n\t\t\t\t_paths.gaps = gaps = series.gaps(u, seriesIdx, idx0, idx1, gaps);\n\n\t\t\t\t_paths.clip = clipGaps(gaps, scaleX.ori, xOff, yOff, xDim, yDim);\n\t\t\t}\n\n\t\t\tif (bandClipDir != 0) {\n\t\t\t\t_paths.band = bandClipDir == 2 ? [\n\t\t\t\t\tclipBandLine(u, seriesIdx, idx0, idx1, stroke, -1),\n\t\t\t\t\tclipBandLine(u, seriesIdx, idx0, idx1, stroke,  1),\n\t\t\t\t] : clipBandLine(u, seriesIdx, idx0, idx1, stroke, bandClipDir);\n\t\t\t}\n\n\t\t\treturn _paths;\n\t\t});\n\t};\n}\n\nfunction bars(opts) {\n\topts = opts || EMPTY_OBJ;\n\tconst size = ifNull(opts.size, [0.6, inf, 1]);\n\tconst align = opts.align || 0;\n\tconst extraGap = (opts.gap || 0) * pxRatio;\n\n\tconst radius = ifNull(opts.radius, 0);\n\n\tconst gapFactor = 1 - size[0];\n\tconst maxWidth  = ifNull(size[1], inf) * pxRatio;\n\tconst minWidth  = ifNull(size[2], 1) * pxRatio;\n\n\tconst disp = ifNull(opts.disp, EMPTY_OBJ);\n\tconst _each = ifNull(opts.each, _ => {});\n\n\tconst { fill: dispFills, stroke: dispStrokes } = disp;\n\n\treturn (u, seriesIdx, idx0, idx1) => {\n\t\treturn orient(u, seriesIdx, (series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {\n\t\t\tlet pxRound = series.pxRound;\n\n\t\t\tconst _dirX = scaleX.dir * (scaleX.ori == 0 ? 1 : -1);\n\t\t\tconst _dirY = scaleY.dir * (scaleY.ori == 1 ? 1 : -1);\n\n\t\t\tlet rect = scaleX.ori == 0 ? rectH : rectV;\n\n\t\t\tlet each = scaleX.ori == 0 ? _each : (u, seriesIdx, i, top, lft, hgt, wid) => {\n\t\t\t\t_each(u, seriesIdx, i, lft, top, wid, hgt);\n\t\t\t};\n\n\t\t\tlet [ bandFillDir, bandClipDir ] = bandFillClipDirs(u, seriesIdx);\n\n\t\t//\tlet fillToY = series.fillTo(u, seriesIdx, series.min, series.max, bandFillDir);\n\t\t\tlet fillToY = scaleY.distr == 3 ? (bandFillDir == 1 ? scaleY.max : scaleY.min) : 0;\n\n\t\t\tlet y0Pos = valToPosY(fillToY, scaleY, yDim, yOff);\n\n\t\t\t// barWid is to center of stroke\n\t\t\tlet xShift, barWid;\n\n\t\t\tlet strokeWidth = pxRound(series.width * pxRatio);\n\n\t\t\tlet multiPath = false;\n\n\t\t\tlet fillColors = null;\n\t\t\tlet fillPaths = null;\n\t\t\tlet strokeColors = null;\n\t\t\tlet strokePaths = null;\n\n\t\t\tif (dispFills != null && (strokeWidth == 0 || dispStrokes != null)) {\n\t\t\t\tmultiPath = true;\n\n\t\t\t\tfillColors = dispFills.values(u, seriesIdx, idx0, idx1);\n\t\t\t\tfillPaths = new Map();\n\t\t\t\t(new Set(fillColors)).forEach(color => {\n\t\t\t\t\tif (color != null)\n\t\t\t\t\t\tfillPaths.set(color, new Path2D());\n\t\t\t\t});\n\n\t\t\t\tif (strokeWidth > 0) {\n\t\t\t\t\tstrokeColors = dispStrokes.values(u, seriesIdx, idx0, idx1);\n\t\t\t\t\tstrokePaths = new Map();\n\t\t\t\t\t(new Set(strokeColors)).forEach(color => {\n\t\t\t\t\t\tif (color != null)\n\t\t\t\t\t\t\tstrokePaths.set(color, new Path2D());\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet { x0, size } = disp;\n\n\t\t\tif (x0 != null && size != null) {\n\t\t\t\tdataX = x0.values(u, seriesIdx, idx0, idx1);\n\n\t\t\t\tif (x0.unit == 2)\n\t\t\t\t\tdataX = dataX.map(pct => u.posToVal(xOff + pct * xDim, scaleX.key, true));\n\n\t\t\t\t// assumes uniform sizes, for now\n\t\t\t\tlet sizes = size.values(u, seriesIdx, idx0, idx1);\n\n\t\t\t\tif (size.unit == 2)\n\t\t\t\t\tbarWid = sizes[0] * xDim;\n\t\t\t\telse\n\t\t\t\t\tbarWid = valToPosX(sizes[0], scaleX, xDim, xOff) - valToPosX(0, scaleX, xDim, xOff); // assumes linear scale (delta from 0)\n\n\t\t\t\tbarWid = pxRound(barWid - strokeWidth);\n\n\t\t\t\txShift = (_dirX == 1 ? -strokeWidth / 2 : barWid + strokeWidth / 2);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlet colWid = xDim;\n\n\t\t\t\tif (dataX.length > 1) {\n\t\t\t\t\t// prior index with non-undefined y data\n\t\t\t\t\tlet prevIdx = null;\n\n\t\t\t\t\t// scan full dataset for smallest adjacent delta\n\t\t\t\t\t// will not work properly for non-linear x scales, since does not do expensive valToPosX calcs till end\n\t\t\t\t\tfor (let i = 0, minDelta = Infinity; i < dataX.length; i++) {\n\t\t\t\t\t\tif (dataY[i] !== undefined) {\n\t\t\t\t\t\t\tif (prevIdx != null) {\n\t\t\t\t\t\t\t\tlet delta = abs(dataX[i] - dataX[prevIdx]);\n\n\t\t\t\t\t\t\t\tif (delta < minDelta) {\n\t\t\t\t\t\t\t\t\tminDelta = delta;\n\t\t\t\t\t\t\t\t\tcolWid = abs(valToPosX(dataX[i], scaleX, xDim, xOff) - valToPosX(dataX[prevIdx], scaleX, xDim, xOff));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tprevIdx = i;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlet gapWid = colWid * gapFactor;\n\n\t\t\t\tbarWid = pxRound(min(maxWidth, max(minWidth, colWid - gapWid)) - strokeWidth - extraGap);\n\n\t\t\t\txShift = (align == 0 ? barWid / 2 : align == _dirX ? 0 : barWid) - align * _dirX * extraGap / 2;\n\t\t\t}\n\n\t\t\tconst _paths = {stroke: null, fill: null, clip: null, band: null, gaps: null, flags: BAND_CLIP_FILL | BAND_CLIP_STROKE};  // disp, geom\n\n\t\t\tlet yLimit;\n\n\t\t\tif (bandClipDir != 0) {\n\t\t\t\t_paths.band = new Path2D();\n\t\t\t\tyLimit = pxRound(valToPosY(bandClipDir == 1 ? scaleY.max : scaleY.min, scaleY, yDim, yOff));\n\t\t\t}\n\n\t\t\tconst stroke = multiPath ? null : new Path2D();\n\t\t\tconst band = _paths.band;\n\n\t\t\tlet { y0, y1 } = disp;\n\n\t\t\tlet dataY0 = null;\n\n\t\t\tif (y0 != null && y1 != null) {\n\t\t\t\tdataY = y1.values(u, seriesIdx, idx0, idx1);\n\t\t\t\tdataY0 = y0.values(u, seriesIdx, idx0, idx1);\n\t\t\t}\n\n\t\t\tfor (let i = _dirX == 1 ? idx0 : idx1; i >= idx0 && i <= idx1; i += _dirX) {\n\t\t\t\tlet yVal = dataY[i];\n\n\t\t\t\t// we can skip both, drawing and band clipping for alignment artifacts\n\t\t\t\tif (yVal === undefined)\n\t\t\t\t\tcontinue;\n\n\t\t\t/*\n\t\t\t\t// interpolate upwards band clips\n\t\t\t\tif (yVal == null) {\n\t\t\t\t//\tif (hasBands)\n\t\t\t\t//\t\tyVal = costlyLerp(i, idx0, idx1, _dirX, dataY);\n\t\t\t\t//\telse\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t*/\n\n\t\t\t\tlet xVal = scaleX.distr != 2 || disp != null ? dataX[i] : i;\n\n\t\t\t\t// TODO: all xPos can be pre-computed once for all series in aligned set\n\t\t\t\tlet xPos = valToPosX(xVal, scaleX, xDim, xOff);\n\t\t\t\tlet yPos = valToPosY(ifNull(yVal, fillToY), scaleY, yDim, yOff);\n\n\t\t\t\tif (dataY0 != null && yVal != null)\n\t\t\t\t\ty0Pos = valToPosY(dataY0[i], scaleY, yDim, yOff);\n\n\t\t\t\tlet lft = pxRound(xPos - xShift);\n\t\t\t\tlet btm = pxRound(max(yPos, y0Pos));\n\t\t\t\tlet top = pxRound(min(yPos, y0Pos));\n\t\t\t\t// this includes the stroke\n\t\t\t\tlet barHgt = btm - top;\n\n\t\t\t\tlet r = radius * barWid;\n\n\t\t\t\tif (yVal != null) {  // && yVal != fillToY (0 height bar)\n\t\t\t\t\tif (multiPath) {\n\t\t\t\t\t\tif (strokeWidth > 0 && strokeColors[i] != null)\n\t\t\t\t\t\t\trect(strokePaths.get(strokeColors[i]), lft, top + floor(strokeWidth / 2), barWid, max(0, barHgt - strokeWidth), r);\n\n\t\t\t\t\t\tif (fillColors[i] != null)\n\t\t\t\t\t\t\trect(fillPaths.get(fillColors[i]), lft, top + floor(strokeWidth / 2), barWid, max(0, barHgt - strokeWidth), r);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\trect(stroke, lft, top + floor(strokeWidth / 2), barWid, max(0, barHgt - strokeWidth), r);\n\n\t\t\t\t\teach(u, seriesIdx, i,\n\t\t\t\t\t\tlft    - strokeWidth / 2,\n\t\t\t\t\t\ttop,\n\t\t\t\t\t\tbarWid + strokeWidth,\n\t\t\t\t\t\tbarHgt,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (bandClipDir != 0) {\n\t\t\t\t\tif (_dirY * bandClipDir == 1) {\n\t\t\t\t\t\tbtm = top;\n\t\t\t\t\t\ttop = yLimit;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\ttop = btm;\n\t\t\t\t\t\tbtm = yLimit;\n\t\t\t\t\t}\n\n\t\t\t\t\tbarHgt = btm - top;\n\n\t\t\t\t\trect(band, lft - strokeWidth / 2, top, barWid + strokeWidth, max(0, barHgt), 0);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (strokeWidth > 0)\n\t\t\t\t_paths.stroke = multiPath ? strokePaths : stroke;\n\n\t\t\t_paths.fill = multiPath ? fillPaths : stroke;\n\n\t\t\treturn _paths;\n\t\t});\n\t};\n}\n\nfunction splineInterp(interp, opts) {\n\tconst alignGaps = ifNull(opts?.alignGaps, 0);\n\n\treturn (u, seriesIdx, idx0, idx1) => {\n\t\treturn orient(u, seriesIdx, (series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {\n\t\t\tlet pxRound = series.pxRound;\n\n\t\t\tlet pixelForX = val => pxRound(valToPosX(val, scaleX, xDim, xOff));\n\t\t\tlet pixelForY = val => pxRound(valToPosY(val, scaleY, yDim, yOff));\n\n\t\t\tlet moveTo, bezierCurveTo, lineTo;\n\n\t\t\tif (scaleX.ori == 0) {\n\t\t\t\tmoveTo = moveToH;\n\t\t\t\tlineTo = lineToH;\n\t\t\t\tbezierCurveTo = bezierCurveToH;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tmoveTo = moveToV;\n\t\t\t\tlineTo = lineToV;\n\t\t\t\tbezierCurveTo = bezierCurveToV;\n\t\t\t}\n\n\t\t\tconst dir = scaleX.dir * (scaleX.ori == 0 ? 1 : -1);\n\n\t\t\tidx0 = nonNullIdx(dataY, idx0, idx1,  1);\n\t\t\tidx1 = nonNullIdx(dataY, idx0, idx1, -1);\n\n\t\t\tlet firstXPos = pixelForX(dataX[dir == 1 ? idx0 : idx1]);\n\t\t\tlet prevXPos = firstXPos;\n\n\t\t\tlet xCoords = [];\n\t\t\tlet yCoords = [];\n\n\t\t\tfor (let i = dir == 1 ? idx0 : idx1; i >= idx0 && i <= idx1; i += dir) {\n\t\t\t\tlet yVal = dataY[i];\n\n\t\t\t\tif (yVal != null) {\n\t\t\t\t\tlet xVal = dataX[i];\n\t\t\t\t\tlet xPos = pixelForX(xVal);\n\n\t\t\t\t\txCoords.push(prevXPos = xPos);\n\t\t\t\t\tyCoords.push(pixelForY(dataY[i]));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst _paths = {stroke: interp(xCoords, yCoords, moveTo, lineTo, bezierCurveTo, pxRound), fill: null, clip: null, band: null, gaps: null, flags: BAND_CLIP_FILL};\n\t\t\tconst stroke = _paths.stroke;\n\n\t\t\tlet [ bandFillDir, bandClipDir ] = bandFillClipDirs(u, seriesIdx);\n\n\t\t\tif (series.fill != null || bandFillDir != 0) {\n\t\t\t\tlet fill = _paths.fill = new Path2D(stroke);\n\n\t\t\t\tlet fillTo = series.fillTo(u, seriesIdx, series.min, series.max, bandFillDir);\n\t\t\t\tlet fillToY = pixelForY(fillTo);\n\n\t\t\t\tlineTo(fill, prevXPos, fillToY);\n\t\t\t\tlineTo(fill, firstXPos, fillToY);\n\t\t\t}\n\n\t\t\tif (!series.spanGaps) {\n\t\t\t//\tconsole.time('gaps');\n\t\t\t\tlet gaps = [];\n\n\t\t\t\tgaps.push(...findGaps(dataX, dataY, idx0, idx1, dir, pixelForX, alignGaps));\n\n\t\t\t//\tconsole.timeEnd('gaps');\n\n\t\t\t//\tconsole.log('gaps', JSON.stringify(gaps));\n\n\t\t\t\t_paths.gaps = gaps = series.gaps(u, seriesIdx, idx0, idx1, gaps);\n\n\t\t\t\t_paths.clip = clipGaps(gaps, scaleX.ori, xOff, yOff, xDim, yDim);\n\t\t\t}\n\n\t\t\tif (bandClipDir != 0) {\n\t\t\t\t_paths.band = bandClipDir == 2 ? [\n\t\t\t\t\tclipBandLine(u, seriesIdx, idx0, idx1, stroke, -1),\n\t\t\t\t\tclipBandLine(u, seriesIdx, idx0, idx1, stroke,  1),\n\t\t\t\t] : clipBandLine(u, seriesIdx, idx0, idx1, stroke, bandClipDir);\n\t\t\t}\n\n\t\t\treturn _paths;\n\n\t\t\t//  if FEAT_PATHS: false in rollup.config.js\n\t\t\t//\tu.ctx.save();\n\t\t\t//\tu.ctx.beginPath();\n\t\t\t//\tu.ctx.rect(u.bbox.left, u.bbox.top, u.bbox.width, u.bbox.height);\n\t\t\t//\tu.ctx.clip();\n\t\t\t//\tu.ctx.strokeStyle = u.series[sidx].stroke;\n\t\t\t//\tu.ctx.stroke(stroke);\n\t\t\t//\tu.ctx.fillStyle = u.series[sidx].fill;\n\t\t\t//\tu.ctx.fill(fill);\n\t\t\t//\tu.ctx.restore();\n\t\t\t//\treturn null;\n\t\t});\n\t};\n}\n\nfunction monotoneCubic(opts) {\n\treturn splineInterp(_monotoneCubic, opts);\n}\n\n// Monotone Cubic Spline interpolation, adapted from the Chartist.js implementation:\n// https://github.com/gionkunz/chartist-js/blob/e7e78201bffe9609915e5e53cfafa29a5d6c49f9/src/scripts/interpolation.js#L240-L369\nfunction _monotoneCubic(xs, ys, moveTo, lineTo, bezierCurveTo, pxRound) {\n\tconst n = xs.length;\n\n\tif (n < 2)\n\t\treturn null;\n\n\tconst path = new Path2D();\n\n\tmoveTo(path, xs[0], ys[0]);\n\n\tif (n == 2)\n\t\tlineTo(path, xs[1], ys[1]);\n\telse {\n\t\tlet ms  = Array(n),\n\t\t\tds  = Array(n - 1),\n\t\t\tdys = Array(n - 1),\n\t\t\tdxs = Array(n - 1);\n\n\t\t// calc deltas and derivative\n\t\tfor (let i = 0; i < n - 1; i++) {\n\t\t\tdys[i] = ys[i + 1] - ys[i];\n\t\t\tdxs[i] = xs[i + 1] - xs[i];\n\t\t\tds[i]  = dys[i] / dxs[i];\n\t\t}\n\n\t\t// determine desired slope (m) at each point using Fritsch-Carlson method\n\t\t// http://math.stackexchange.com/questions/45218/implementation-of-monotone-cubic-interpolation\n\t\tms[0] = ds[0];\n\n\t\tfor (let i = 1; i < n - 1; i++) {\n\t\t\tif (ds[i] === 0 || ds[i - 1] === 0 || (ds[i - 1] > 0) !== (ds[i] > 0))\n\t\t\t\tms[i] = 0;\n\t\t\telse {\n\t\t\t\tms[i] = 3 * (dxs[i - 1] + dxs[i]) / (\n\t\t\t\t\t(2 * dxs[i] + dxs[i - 1]) / ds[i - 1] +\n\t\t\t\t\t(dxs[i] + 2 * dxs[i - 1]) / ds[i]\n\t\t\t\t);\n\n\t\t\t\tif (!isFinite(ms[i]))\n\t\t\t\t\tms[i] = 0;\n\t\t\t}\n\t\t}\n\n\t\tms[n - 1] = ds[n - 2];\n\n\t\tfor (let i = 0; i < n - 1; i++) {\n\t\t\tbezierCurveTo(\n\t\t\t\tpath,\n\t\t\t\txs[i] + dxs[i] / 3,\n\t\t\t\tys[i] + ms[i] * dxs[i] / 3,\n\t\t\t\txs[i + 1] - dxs[i] / 3,\n\t\t\t\tys[i + 1] - ms[i + 1] * dxs[i] / 3,\n\t\t\t\txs[i + 1],\n\t\t\t\tys[i + 1],\n\t\t\t);\n\t\t}\n\t}\n\n\treturn path;\n}\n\nconst cursorPlots = new Set();\n\nfunction invalidateRects() {\n\tfor (let u of cursorPlots)\n\t\tu.syncRect(true);\n}\n\nif (domEnv) {\n\ton(resize, win, invalidateRects);\n\ton(scroll, win, invalidateRects, true);\n\ton(dppxchange, win, () => { uPlot.pxRatio = pxRatio; });\n}\n\nconst linearPath = linear() ;\nconst pointsPath = points() ;\n\nfunction setDefaults(d, xo, yo, initY) {\n\tlet d2 = initY ? [d[0], d[1]].concat(d.slice(2)) : [d[0]].concat(d.slice(1));\n\treturn d2.map((o, i) => setDefault(o, i, xo, yo));\n}\n\nfunction setDefaults2(d, xyo) {\n\treturn d.map((o, i) => i == 0 ? null : assign({}, xyo, o));  // todo: assign() will not merge facet arrays\n}\n\nfunction setDefault(o, i, xo, yo) {\n\treturn assign({}, (i == 0 ? xo : yo), o);\n}\n\nfunction snapNumX(self, dataMin, dataMax) {\n\treturn dataMin == null ? nullNullTuple : [dataMin, dataMax];\n}\n\nconst snapTimeX = snapNumX;\n\n// this ensures that non-temporal/numeric y-axes get multiple-snapped padding added above/below\n// TODO: also account for incrs when snapping to ensure top of axis gets a tick & value\nfunction snapNumY(self, dataMin, dataMax) {\n\treturn dataMin == null ? nullNullTuple : rangeNum(dataMin, dataMax, rangePad, true);\n}\n\nfunction snapLogY(self, dataMin, dataMax, scale) {\n\treturn dataMin == null ? nullNullTuple : rangeLog(dataMin, dataMax, self.scales[scale].log, false);\n}\n\nconst snapLogX = snapLogY;\n\nfunction snapAsinhY(self, dataMin, dataMax, scale) {\n\treturn dataMin == null ? nullNullTuple : rangeAsinh(dataMin, dataMax, self.scales[scale].log, false);\n}\n\nconst snapAsinhX = snapAsinhY;\n\n// dim is logical (getClientBoundingRect) pixels, not canvas pixels\nfunction findIncr(minVal, maxVal, incrs, dim, minSpace) {\n\tlet intDigits = max(numIntDigits(minVal), numIntDigits(maxVal));\n\n\tlet delta = maxVal - minVal;\n\n\tlet incrIdx = closestIdx((minSpace / dim) * delta, incrs);\n\n\tdo {\n\t\tlet foundIncr = incrs[incrIdx];\n\t\tlet foundSpace = dim * foundIncr / delta;\n\n\t\tif (foundSpace >= minSpace && intDigits + (foundIncr < 5 ? fixedDec.get(foundIncr) : 0) <= 17)\n\t\t\treturn [foundIncr, foundSpace];\n\t} while (++incrIdx < incrs.length);\n\n\treturn [0, 0];\n}\n\nfunction pxRatioFont(font) {\n\tlet fontSize, fontSizeCss;\n\tfont = font.replace(/(\\d+)px/, (m, p1) => (fontSize = round((fontSizeCss = +p1) * pxRatio)) + 'px');\n\treturn [font, fontSize, fontSizeCss];\n}\n\nfunction syncFontSize(axis) {\n\tif (axis.show) {\n\t\t[axis.font, axis.labelFont].forEach(f => {\n\t\t\tlet size = roundDec(f[2] * pxRatio, 1);\n\t\t\tf[0] = f[0].replace(/[0-9.]+px/, size + 'px');\n\t\t\tf[1] = size;\n\t\t});\n\t}\n}\n\nfunction uPlot(opts, data, then) {\n\tconst self = {\n\t\tmode: ifNull(opts.mode, 1),\n\t};\n\n\tconst mode = self.mode;\n\n\t// TODO: cache denoms & mins scale.cache = {r, min, }\n\tfunction getValPct(val, scale) {\n\t\tlet _val = (\n\t\t\tscale.distr == 3 ? log10(val > 0 ? val : scale.clamp(self, val, scale.min, scale.max, scale.key)) :\n\t\t\tscale.distr == 4 ? asinh(val, scale.asinh) :\n\t\t\tval\n\t\t);\n\n\t\treturn (_val - scale._min) / (scale._max - scale._min);\n\t}\n\n\tfunction getHPos(val, scale, dim, off) {\n\t\tlet pct = getValPct(val, scale);\n\t\treturn off + dim * (scale.dir == -1 ? (1 - pct) : pct);\n\t}\n\n\tfunction getVPos(val, scale, dim, off) {\n\t\tlet pct = getValPct(val, scale);\n\t\treturn off + dim * (scale.dir == -1 ? pct : (1 - pct));\n\t}\n\n\tfunction getPos(val, scale, dim, off) {\n\t\treturn scale.ori == 0 ? getHPos(val, scale, dim, off) : getVPos(val, scale, dim, off);\n\t}\n\n\tself.valToPosH = getHPos;\n\tself.valToPosV = getVPos;\n\n\tlet ready = false;\n\tself.status = 0;\n\n\tconst root = self.root = placeDiv(UPLOT);\n\n\tif (opts.id != null)\n\t\troot.id = opts.id;\n\n\taddClass(root, opts.class);\n\n\tif (opts.title) {\n\t\tlet title = placeDiv(TITLE, root);\n\t\ttitle.textContent = opts.title;\n\t}\n\n\tconst can = placeTag(\"canvas\");\n\tconst ctx = self.ctx = can.getContext(\"2d\");\n\n\tconst wrap = placeDiv(WRAP, root);\n\tconst under = self.under = placeDiv(UNDER, wrap);\n\twrap.appendChild(can);\n\tconst over = self.over = placeDiv(OVER, wrap);\n\n\topts = copy(opts);\n\n\tconst pxAlign = +ifNull(opts.pxAlign, 1);\n\n\tconst pxRound = pxRoundGen(pxAlign);\n\n\t(opts.plugins || []).forEach(p => {\n\t\tif (p.opts)\n\t\t\topts = p.opts(self, opts) || opts;\n\t});\n\n\tconst ms = opts.ms || 1e-3;\n\n\tconst series  = self.series = mode == 1 ?\n\t\tsetDefaults(opts.series || [], xSeriesOpts, ySeriesOpts, false) :\n\t\tsetDefaults2(opts.series || [null], xySeriesOpts);\n\tconst axes    = self.axes   = setDefaults(opts.axes   || [], xAxisOpts,   yAxisOpts,    true);\n\tconst scales  = self.scales = {};\n\tconst bands   = self.bands  = opts.bands || [];\n\n\tbands.forEach(b => {\n\t\tb.fill = fnOrSelf(b.fill || null);\n\t\tb.dir = ifNull(b.dir, -1);\n\t});\n\n\tconst xScaleKey = mode == 2 ? series[1].facets[0].scale : series[0].scale;\n\n\tconst drawOrderMap = {\n\t\taxes: drawAxesGrid,\n\t\tseries: drawSeries,\n\t};\n\n\tconst drawOrder = (opts.drawOrder || [\"axes\", \"series\"]).map(key => drawOrderMap[key]);\n\n\tfunction initScale(scaleKey) {\n\t\tlet sc = scales[scaleKey];\n\n\t\tif (sc == null) {\n\t\t\tlet scaleOpts = (opts.scales || EMPTY_OBJ)[scaleKey] || EMPTY_OBJ;\n\n\t\t\tif (scaleOpts.from != null) {\n\t\t\t\t// ensure parent is initialized\n\t\t\t\tinitScale(scaleOpts.from);\n\t\t\t\t// dependent scales inherit\n\t\t\t\tscales[scaleKey] = assign({}, scales[scaleOpts.from], scaleOpts, {key: scaleKey});\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsc = scales[scaleKey] = assign({}, (scaleKey == xScaleKey ? xScaleOpts : yScaleOpts), scaleOpts);\n\n\t\t\t\tsc.key = scaleKey;\n\n\t\t\t\tlet isTime = sc.time;\n\n\t\t\t\tlet rn = sc.range;\n\n\t\t\t\tlet rangeIsArr = isArr(rn);\n\n\t\t\t\tif (scaleKey != xScaleKey || (mode == 2 && !isTime)) {\n\t\t\t\t\t// if range array has null limits, it should be auto\n\t\t\t\t\tif (rangeIsArr && (rn[0] == null || rn[1] == null)) {\n\t\t\t\t\t\trn = {\n\t\t\t\t\t\t\tmin: rn[0] == null ? autoRangePart : {\n\t\t\t\t\t\t\t\tmode: 1,\n\t\t\t\t\t\t\t\thard: rn[0],\n\t\t\t\t\t\t\t\tsoft: rn[0],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tmax: rn[1] == null ? autoRangePart : {\n\t\t\t\t\t\t\t\tmode: 1,\n\t\t\t\t\t\t\t\thard: rn[1],\n\t\t\t\t\t\t\t\tsoft: rn[1],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t\trangeIsArr = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!rangeIsArr && isObj(rn)) {\n\t\t\t\t\t\tlet cfg = rn;\n\t\t\t\t\t\t// this is similar to snapNumY\n\t\t\t\t\t\trn = (self, dataMin, dataMax) => dataMin == null ? nullNullTuple : rangeNum(dataMin, dataMax, cfg);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tsc.range = fnOrSelf(rn || (isTime ? snapTimeX : scaleKey == xScaleKey ?\n\t\t\t\t\t(sc.distr == 3 ? snapLogX : sc.distr == 4 ? snapAsinhX : snapNumX) :\n\t\t\t\t\t(sc.distr == 3 ? snapLogY : sc.distr == 4 ? snapAsinhY : snapNumY)\n\t\t\t\t));\n\n\t\t\t\tsc.auto = fnOrSelf(rangeIsArr ? false : sc.auto);\n\n\t\t\t\tsc.clamp = fnOrSelf(sc.clamp || clampScale);\n\n\t\t\t\t// caches for expensive ops like asinh() & log()\n\t\t\t\tsc._min = sc._max = null;\n\t\t\t}\n\t\t}\n\t}\n\n\tinitScale(\"x\");\n\tinitScale(\"y\");\n\n\t// TODO: init scales from facets in mode: 2\n\tif (mode == 1) {\n\t\tseries.forEach(s => {\n\t\t\tinitScale(s.scale);\n\t\t});\n\t}\n\n\taxes.forEach(a => {\n\t\tinitScale(a.scale);\n\t});\n\n\tfor (let k in opts.scales)\n\t\tinitScale(k);\n\n\tconst scaleX = scales[xScaleKey];\n\n\tconst xScaleDistr = scaleX.distr;\n\n\tlet valToPosX, valToPosY;\n\n\tif (scaleX.ori == 0) {\n\t\taddClass(root, ORI_HZ);\n\t\tvalToPosX = getHPos;\n\t\tvalToPosY = getVPos;\n\t\t/*\n\t\tupdOriDims = () => {\n\t\t\txDimCan = plotWid;\n\t\t\txOffCan = plotLft;\n\t\t\tyDimCan = plotHgt;\n\t\t\tyOffCan = plotTop;\n\n\t\t\txDimCss = plotWidCss;\n\t\t\txOffCss = plotLftCss;\n\t\t\tyDimCss = plotHgtCss;\n\t\t\tyOffCss = plotTopCss;\n\t\t};\n\t\t*/\n\t}\n\telse {\n\t\taddClass(root, ORI_VT);\n\t\tvalToPosX = getVPos;\n\t\tvalToPosY = getHPos;\n\t\t/*\n\t\tupdOriDims = () => {\n\t\t\txDimCan = plotHgt;\n\t\t\txOffCan = plotTop;\n\t\t\tyDimCan = plotWid;\n\t\t\tyOffCan = plotLft;\n\n\t\t\txDimCss = plotHgtCss;\n\t\t\txOffCss = plotTopCss;\n\t\t\tyDimCss = plotWidCss;\n\t\t\tyOffCss = plotLftCss;\n\t\t};\n\t\t*/\n\t}\n\n\tconst pendScales = {};\n\n\t// explicitly-set initial scales\n\tfor (let k in scales) {\n\t\tlet sc = scales[k];\n\n\t\tif (sc.min != null || sc.max != null) {\n\t\t\tpendScales[k] = {min: sc.min, max: sc.max};\n\t\t\tsc.min = sc.max = null;\n\t\t}\n\t}\n\n//\tself.tz = opts.tz || Intl.DateTimeFormat().resolvedOptions().timeZone;\n\tconst _tzDate  = (opts.tzDate || (ts => new Date(round(ts / ms))));\n\tconst _fmtDate = (opts.fmtDate || fmtDate);\n\n\tconst _timeAxisSplits = (ms == 1 ? timeAxisSplitsMs(_tzDate) : timeAxisSplitsS(_tzDate));\n\tconst _timeAxisVals   = timeAxisVals(_tzDate, timeAxisStamps((ms == 1 ? _timeAxisStampsMs : _timeAxisStampsS), _fmtDate));\n\tconst _timeSeriesVal  = timeSeriesVal(_tzDate, timeSeriesStamp(_timeSeriesStamp, _fmtDate));\n\n\tconst activeIdxs = [];\n\n\tconst legend     = (self.legend = assign({}, legendOpts, opts.legend));\n\tconst showLegend = legend.show;\n\tconst markers    = legend.markers;\n\n\t{\n\t\tlegend.idxs = activeIdxs;\n\n\t\tmarkers.width  = fnOrSelf(markers.width);\n\t\tmarkers.dash   = fnOrSelf(markers.dash);\n\t\tmarkers.stroke = fnOrSelf(markers.stroke);\n\t\tmarkers.fill   = fnOrSelf(markers.fill);\n\t}\n\n\tlet legendEl;\n\tlet legendRows = [];\n\tlet legendCells = [];\n\tlet legendCols;\n\tlet multiValLegend = false;\n\tlet NULL_LEGEND_VALUES = {};\n\n\tif (legend.live) {\n\t\tconst getMultiVals = series[1] ? series[1].values : null;\n\t\tmultiValLegend = getMultiVals != null;\n\t\tlegendCols = multiValLegend ? getMultiVals(self, 1, 0) : {_: 0};\n\n\t\tfor (let k in legendCols)\n\t\t\tNULL_LEGEND_VALUES[k] = \"--\";\n\t}\n\n\tif (showLegend) {\n\t\tlegendEl = placeTag(\"table\", LEGEND, root);\n\n\t\tlegend.mount(self, legendEl);\n\n\t\tif (multiValLegend) {\n\t\t\tlet head = placeTag(\"tr\", LEGEND_THEAD, legendEl);\n\t\t\tplaceTag(\"th\", null, head);\n\n\t\t\tfor (var key in legendCols)\n\t\t\t\tplaceTag(\"th\", LEGEND_LABEL, head).textContent = key;\n\t\t}\n\t\telse {\n\t\t\taddClass(legendEl, LEGEND_INLINE);\n\t\t\tlegend.live && addClass(legendEl, LEGEND_LIVE);\n\t\t}\n\t}\n\n\tconst son  = {show: true};\n\tconst soff = {show: false};\n\n\tfunction initLegendRow(s, i) {\n\t\tif (i == 0 && (multiValLegend || !legend.live || mode == 2))\n\t\t\treturn nullNullTuple;\n\n\t\tlet cells = [];\n\n\t\tlet row = placeTag(\"tr\", LEGEND_SERIES, legendEl, legendEl.childNodes[i]);\n\n\t\taddClass(row, s.class);\n\n\t\tif (!s.show)\n\t\t\taddClass(row, OFF);\n\n\t\tlet label = placeTag(\"th\", null, row);\n\n\t\tif (markers.show) {\n\t\t\tlet indic = placeDiv(LEGEND_MARKER, label);\n\n\t\t\tif (i > 0) {\n\t\t\t\tlet width  = markers.width(self, i);\n\n\t\t\t\tif (width)\n\t\t\t\t\tindic.style.border = width + \"px \" + markers.dash(self, i) + \" \" + markers.stroke(self, i);\n\n\t\t\t\tindic.style.background = markers.fill(self, i);\n\t\t\t}\n\t\t}\n\n\t\tlet text = placeDiv(LEGEND_LABEL, label);\n\t\ttext.textContent = s.label;\n\n\t\tif (i > 0) {\n\t\t\tif (!markers.show)\n\t\t\t\ttext.style.color = s.width > 0 ? markers.stroke(self, i) : markers.fill(self, i);\n\n\t\t\tonMouse(\"click\", label, e => {\n\t\t\t\tif (cursor._lock)\n\t\t\t\t\treturn;\n\n\t\t\t\tlet seriesIdx = series.indexOf(s);\n\n\t\t\t\tif ((e.ctrlKey || e.metaKey) != legend.isolate) {\n\t\t\t\t\t// if any other series is shown, isolate this one. else show all\n\t\t\t\t\tlet isolate = series.some((s, i) => i > 0 && i != seriesIdx && s.show);\n\n\t\t\t\t\tseries.forEach((s, i) => {\n\t\t\t\t\t\ti > 0 && setSeries(i, isolate ? (i == seriesIdx ? son : soff) : son, true, syncOpts.setSeries);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tsetSeries(seriesIdx, {show: !s.show}, true, syncOpts.setSeries);\n\t\t\t});\n\n\t\t\tif (cursorFocus) {\n\t\t\t\tonMouse(mouseenter, label, e => {\n\t\t\t\t\tif (cursor._lock)\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\tsetSeries(series.indexOf(s), FOCUS_TRUE, true, syncOpts.setSeries);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tfor (var key in legendCols) {\n\t\t\tlet v = placeTag(\"td\", LEGEND_VALUE, row);\n\t\t\tv.textContent = \"--\";\n\t\t\tcells.push(v);\n\t\t}\n\n\t\treturn [row, cells];\n\t}\n\n\tconst mouseListeners = new Map();\n\n\tfunction onMouse(ev, targ, fn) {\n\t\tconst targListeners = mouseListeners.get(targ) || {};\n\t\tconst listener = cursor.bind[ev](self, targ, fn);\n\n\t\tif (listener) {\n\t\t\ton(ev, targ, targListeners[ev] = listener);\n\t\t\tmouseListeners.set(targ, targListeners);\n\t\t}\n\t}\n\n\tfunction offMouse(ev, targ, fn) {\n\t\tconst targListeners = mouseListeners.get(targ) || {};\n\n\t\tfor (let k in targListeners) {\n\t\t\tif (ev == null || k == ev) {\n\t\t\t\toff(k, targ, targListeners[k]);\n\t\t\t\tdelete targListeners[k];\n\t\t\t}\n\t\t}\n\n\t\tif (ev == null)\n\t\t\tmouseListeners.delete(targ);\n\t}\n\n\tlet fullWidCss = 0;\n\tlet fullHgtCss = 0;\n\n\tlet plotWidCss = 0;\n\tlet plotHgtCss = 0;\n\n\t// plot margins to account for axes\n\tlet plotLftCss = 0;\n\tlet plotTopCss = 0;\n\n\tlet plotLft = 0;\n\tlet plotTop = 0;\n\tlet plotWid = 0;\n\tlet plotHgt = 0;\n\n\tself.bbox = {};\n\n\tlet shouldSetScales = false;\n\tlet shouldSetSize = false;\n\tlet shouldConvergeSize = false;\n\tlet shouldSetCursor = false;\n\tlet shouldSetSelect = false;\n\tlet shouldSetLegend = false;\n\n\tfunction _setSize(width, height, force) {\n\t\tif (force || (width != self.width || height != self.height))\n\t\t\tcalcSize(width, height);\n\n\t\tresetYSeries(false);\n\n\t\tshouldConvergeSize = true;\n\t\tshouldSetSize = true;\n\n\t\tif (cursor.left >= 0)\n\t\t\tshouldSetCursor = shouldSetLegend = true;\n\n\t\tcommit();\n\t}\n\n\tfunction calcSize(width, height) {\n\t//\tlog(\"calcSize()\", arguments);\n\n\t\tself.width  = fullWidCss = plotWidCss = width;\n\t\tself.height = fullHgtCss = plotHgtCss = height;\n\t\tplotLftCss  = plotTopCss = 0;\n\n\t\tcalcPlotRect();\n\t\tcalcAxesRects();\n\n\t\tlet bb = self.bbox;\n\n\t\tplotLft = bb.left   = incrRound(plotLftCss * pxRatio, 0.5);\n\t\tplotTop = bb.top    = incrRound(plotTopCss * pxRatio, 0.5);\n\t\tplotWid = bb.width  = incrRound(plotWidCss * pxRatio, 0.5);\n\t\tplotHgt = bb.height = incrRound(plotHgtCss * pxRatio, 0.5);\n\n\t//\tupdOriDims();\n\t}\n\n\t// ensures size calc convergence\n\tconst CYCLE_LIMIT = 3;\n\n\tfunction convergeSize() {\n\t\tlet converged = false;\n\n\t\tlet cycleNum = 0;\n\n\t\twhile (!converged) {\n\t\t\tcycleNum++;\n\n\t\t\tlet axesConverged = axesCalc(cycleNum);\n\t\t\tlet paddingConverged = paddingCalc(cycleNum);\n\n\t\t\tconverged = cycleNum == CYCLE_LIMIT || (axesConverged && paddingConverged);\n\n\t\t\tif (!converged) {\n\t\t\t\tcalcSize(self.width, self.height);\n\t\t\t\tshouldSetSize = true;\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction setSize({width, height}) {\n\t\t_setSize(width, height);\n\t}\n\n\tself.setSize = setSize;\n\n\t// accumulate axis offsets, reduce canvas width\n\tfunction calcPlotRect() {\n\t\t// easements for edge labels\n\t\tlet hasTopAxis = false;\n\t\tlet hasBtmAxis = false;\n\t\tlet hasRgtAxis = false;\n\t\tlet hasLftAxis = false;\n\n\t\taxes.forEach((axis, i) => {\n\t\t\tif (axis.show && axis._show) {\n\t\t\t\tlet {side, _size} = axis;\n\t\t\t\tlet isVt = side % 2;\n\t\t\t\tlet labelSize = axis.label != null ? axis.labelSize : 0;\n\n\t\t\t\tlet fullSize = _size + labelSize;\n\n\t\t\t\tif (fullSize > 0) {\n\t\t\t\t\tif (isVt) {\n\t\t\t\t\t\tplotWidCss -= fullSize;\n\n\t\t\t\t\t\tif (side == 3) {\n\t\t\t\t\t\t\tplotLftCss += fullSize;\n\t\t\t\t\t\t\thasLftAxis = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\thasRgtAxis = true;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tplotHgtCss -= fullSize;\n\n\t\t\t\t\t\tif (side == 0) {\n\t\t\t\t\t\t\tplotTopCss += fullSize;\n\t\t\t\t\t\t\thasTopAxis = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\thasBtmAxis = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tsidesWithAxes[0] = hasTopAxis;\n\t\tsidesWithAxes[1] = hasRgtAxis;\n\t\tsidesWithAxes[2] = hasBtmAxis;\n\t\tsidesWithAxes[3] = hasLftAxis;\n\n\t\t// hz padding\n\t\tplotWidCss -= _padding[1] + _padding[3];\n\t\tplotLftCss += _padding[3];\n\n\t\t// vt padding\n\t\tplotHgtCss -= _padding[2] + _padding[0];\n\t\tplotTopCss += _padding[0];\n\t}\n\n\tfunction calcAxesRects() {\n\t\t// will accum +\n\t\tlet off1 = plotLftCss + plotWidCss;\n\t\tlet off2 = plotTopCss + plotHgtCss;\n\t\t// will accum -\n\t\tlet off3 = plotLftCss;\n\t\tlet off0 = plotTopCss;\n\n\t\tfunction incrOffset(side, size) {\n\t\t\tswitch (side) {\n\t\t\t\tcase 1: off1 += size; return off1 - size;\n\t\t\t\tcase 2: off2 += size; return off2 - size;\n\t\t\t\tcase 3: off3 -= size; return off3 + size;\n\t\t\t\tcase 0: off0 -= size; return off0 + size;\n\t\t\t}\n\t\t}\n\n\t\taxes.forEach((axis, i) => {\n\t\t\tif (axis.show && axis._show) {\n\t\t\t\tlet side = axis.side;\n\n\t\t\t\taxis._pos = incrOffset(side, axis._size);\n\n\t\t\t\tif (axis.label != null)\n\t\t\t\t\taxis._lpos = incrOffset(side, axis.labelSize);\n\t\t\t}\n\t\t});\n\t}\n\n\tconst cursor = (self.cursor = assign({}, cursorOpts, {drag: {y: mode == 2}}, opts.cursor));\n\n\t{\n\t\tcursor.idxs = activeIdxs;\n\n\t\tcursor._lock = false;\n\n\t\tlet points = cursor.points;\n\n\t\tpoints.show   = fnOrSelf(points.show);\n\t\tpoints.size   = fnOrSelf(points.size);\n\t\tpoints.stroke = fnOrSelf(points.stroke);\n\t\tpoints.width  = fnOrSelf(points.width);\n\t\tpoints.fill   = fnOrSelf(points.fill);\n\t}\n\n\tconst focus = self.focus = assign({}, opts.focus || {alpha: 0.3}, cursor.focus);\n\tconst cursorFocus = focus.prox >= 0;\n\n\t// series-intersection markers\n\tlet cursorPts = [null];\n\n\tfunction initCursorPt(s, si) {\n\t\tif (si > 0) {\n\t\t\tlet pt = cursor.points.show(self, si);\n\n\t\t\tif (pt) {\n\t\t\t\taddClass(pt, CURSOR_PT);\n\t\t\t\taddClass(pt, s.class);\n\t\t\t\telTrans(pt, -10, -10, plotWidCss, plotHgtCss);\n\t\t\t\tover.insertBefore(pt, cursorPts[si]);\n\n\t\t\t\treturn pt;\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction initSeries(s, i) {\n\t\tif (mode == 1 || i > 0) {\n\t\t\tlet isTime = mode == 1 && scales[s.scale].time;\n\n\t\t\tlet sv = s.value;\n\t\t\ts.value = isTime ? (isStr(sv) ? timeSeriesVal(_tzDate, timeSeriesStamp(sv, _fmtDate)) : sv || _timeSeriesVal) : sv || numSeriesVal;\n\t\t\ts.label = s.label || (isTime ? timeSeriesLabel : numSeriesLabel);\n\t\t}\n\n\t\tif (i > 0) {\n\t\t\ts.width  = s.width == null ? 1 : s.width;\n\t\t\ts.paths  = s.paths || linearPath || retNull;\n\t\t\ts.fillTo = fnOrSelf(s.fillTo || seriesFillTo);\n\t\t\ts.pxAlign = +ifNull(s.pxAlign, pxAlign);\n\t\t\ts.pxRound = pxRoundGen(s.pxAlign);\n\n\t\t\ts.stroke = fnOrSelf(s.stroke || null);\n\t\t\ts.fill   = fnOrSelf(s.fill || null);\n\t\t\ts._stroke = s._fill = s._paths = s._focus = null;\n\n\t\t\tlet _ptDia = ptDia(s.width, 1);\n\t\t\tlet points = s.points = assign({}, {\n\t\t\t\tsize: _ptDia,\n\t\t\t\twidth: max(1, _ptDia * .2),\n\t\t\t\tstroke: s.stroke,\n\t\t\t\tspace: _ptDia * 2,\n\t\t\t\tpaths: pointsPath,\n\t\t\t\t_stroke: null,\n\t\t\t\t_fill: null,\n\t\t\t}, s.points);\n\t\t\tpoints.show   = fnOrSelf(points.show);\n\t\t\tpoints.filter = fnOrSelf(points.filter);\n\t\t\tpoints.fill   = fnOrSelf(points.fill);\n\t\t\tpoints.stroke = fnOrSelf(points.stroke);\n\t\t\tpoints.paths  = fnOrSelf(points.paths);\n\t\t\tpoints.pxAlign = s.pxAlign;\n\t\t}\n\n\t\tif (showLegend) {\n\t\t\tlet rowCells = initLegendRow(s, i);\n\t\t\tlegendRows.splice(i, 0, rowCells[0]);\n\t\t\tlegendCells.splice(i, 0, rowCells[1]);\n\t\t\tlegend.values.push(null);\t// NULL_LEGEND_VALS not yet avil here :(\n\t\t}\n\n\t\tif (cursor.show) {\n\t\t\tactiveIdxs.splice(i, 0, null);\n\n\t\t\tlet pt = initCursorPt(s, i);\n\t\t\tpt && cursorPts.splice(i, 0, pt);\n\t\t}\n\n\t\tfire(\"addSeries\", i);\n\t}\n\n\tfunction addSeries(opts, si) {\n\t\tsi = si == null ? series.length : si;\n\n\t\topts = mode == 1 ? setDefault(opts, si, xSeriesOpts, ySeriesOpts) : setDefault(opts, si, null, xySeriesOpts);\n\n\t\tseries.splice(si, 0, opts);\n\t\tinitSeries(series[si], si);\n\t}\n\n\tself.addSeries = addSeries;\n\n\tfunction delSeries(i) {\n\t\tseries.splice(i, 1);\n\n\t\tif (showLegend) {\n\t\t\tlegend.values.splice(i, 1);\n\n\t\t\tlegendCells.splice(i, 1);\n\t\t\tlet tr = legendRows.splice(i, 1)[0];\n\t\t\toffMouse(null, tr.firstChild);\n\t\t\ttr.remove();\n\t\t}\n\n\t\tif (cursor.show) {\n\t\t\tactiveIdxs.splice(i, 1);\n\n\t\t\tcursorPts.length > 1 && cursorPts.splice(i, 1)[0].remove();\n\t\t}\n\n\t\t// TODO: de-init no-longer-needed scales?\n\n\t\tfire(\"delSeries\", i);\n\t}\n\n\tself.delSeries = delSeries;\n\n\tconst sidesWithAxes = [false, false, false, false];\n\n\tfunction initAxis(axis, i) {\n\t\taxis._show = axis.show;\n\n\t\tif (axis.show) {\n\t\t\tlet isVt = axis.side % 2;\n\n\t\t\tlet sc = scales[axis.scale];\n\n\t\t\t// this can occur if all series specify non-default scales\n\t\t\tif (sc == null) {\n\t\t\t\taxis.scale = isVt ? series[1].scale : xScaleKey;\n\t\t\t\tsc = scales[axis.scale];\n\t\t\t}\n\n\t\t\t// also set defaults for incrs & values based on axis distr\n\t\t\tlet isTime = sc.time;\n\n\t\t\taxis.size   = fnOrSelf(axis.size);\n\t\t\taxis.space  = fnOrSelf(axis.space);\n\t\t\taxis.rotate = fnOrSelf(axis.rotate);\n\t\t\taxis.incrs  = fnOrSelf(axis.incrs  || (          sc.distr == 2 ? wholeIncrs : (isTime ? (ms == 1 ? timeIncrsMs : timeIncrsS) : numIncrs)));\n\t\t\taxis.splits = fnOrSelf(axis.splits || (isTime && sc.distr == 1 ? _timeAxisSplits : sc.distr == 3 ? logAxisSplits : sc.distr == 4 ? asinhAxisSplits : numAxisSplits));\n\n\t\t\taxis.stroke        = fnOrSelf(axis.stroke);\n\t\t\taxis.grid.stroke   = fnOrSelf(axis.grid.stroke);\n\t\t\taxis.ticks.stroke  = fnOrSelf(axis.ticks.stroke);\n\t\t\taxis.border.stroke = fnOrSelf(axis.border.stroke);\n\n\t\t\tlet av = axis.values;\n\n\t\t\taxis.values = (\n\t\t\t\t// static array of tick values\n\t\t\t\tisArr(av) && !isArr(av[0]) ? fnOrSelf(av) :\n\t\t\t\t// temporal\n\t\t\t\tisTime ? (\n\t\t\t\t\t// config array of fmtDate string tpls\n\t\t\t\t\tisArr(av) ?\n\t\t\t\t\t\ttimeAxisVals(_tzDate, timeAxisStamps(av, _fmtDate)) :\n\t\t\t\t\t// fmtDate string tpl\n\t\t\t\t\tisStr(av) ?\n\t\t\t\t\t\ttimeAxisVal(_tzDate, av) :\n\t\t\t\t\tav || _timeAxisVals\n\t\t\t\t) : av || numAxisVals\n\t\t\t);\n\n\t\t\taxis.filter = fnOrSelf(axis.filter || (          sc.distr >= 3 && sc.log == 10 ? log10AxisValsFilt : retArg1));\n\n\t\t\taxis.font      = pxRatioFont(axis.font);\n\t\t\taxis.labelFont = pxRatioFont(axis.labelFont);\n\n\t\t\taxis._size   = axis.size(self, null, i, 0);\n\n\t\t\taxis._space  =\n\t\t\taxis._rotate =\n\t\t\taxis._incrs  =\n\t\t\taxis._found  =\t// foundIncrSpace\n\t\t\taxis._splits =\n\t\t\taxis._values = null;\n\n\t\t\tif (axis._size > 0) {\n\t\t\t\tsidesWithAxes[i] = true;\n\t\t\t\taxis._el = placeDiv(AXIS, wrap);\n\t\t\t}\n\n\t\t\t// debug\n\t\t//\taxis._el.style.background = \"#\"  + Math.floor(Math.random()*16777215).toString(16) + '80';\n\t\t}\n\t}\n\n\tfunction autoPadSide(self, side, sidesWithAxes, cycleNum) {\n\t\tlet [hasTopAxis, hasRgtAxis, hasBtmAxis, hasLftAxis] = sidesWithAxes;\n\n\t\tlet ori = side % 2;\n\t\tlet size = 0;\n\n\t\tif (ori == 0 && (hasLftAxis || hasRgtAxis))\n\t\t\tsize = (side == 0 && !hasTopAxis || side == 2 && !hasBtmAxis ? round(xAxisOpts.size / 3) : 0);\n\t\tif (ori == 1 && (hasTopAxis || hasBtmAxis))\n\t\t\tsize = (side == 1 && !hasRgtAxis || side == 3 && !hasLftAxis ? round(yAxisOpts.size / 2) : 0);\n\n\t\treturn size;\n\t}\n\n\tconst padding = self.padding = (opts.padding || [autoPadSide,autoPadSide,autoPadSide,autoPadSide]).map(p => fnOrSelf(ifNull(p, autoPadSide)));\n\tconst _padding = self._padding = padding.map((p, i) => p(self, i, sidesWithAxes, 0));\n\n\tlet dataLen;\n\n\t// rendered data window\n\tlet i0 = null;\n\tlet i1 = null;\n\tconst idxs = mode == 1 ? series[0].idxs : null;\n\n\tlet data0 = null;\n\n\tlet viaAutoScaleX = false;\n\n\tfunction setData(_data, _resetScales) {\n\t\tdata = _data == null ? [] : copy(_data, fastIsObj);\n\n\t\tif (mode == 2) {\n\t\t\tdataLen = 0;\n\t\t\tfor (let i = 1; i < series.length; i++)\n\t\t\t\tdataLen += data[i][0].length;\n\t\t\tself.data = data = _data;\n\t\t}\n\t\telse {\n\t\t\tif (data[0] == null)\n\t\t\t\tdata[0] = [];\n\n\t\t\tself.data = data.slice();\n\n\t\t\tdata0 = data[0];\n\t\t\tdataLen = data0.length;\n\n\t\t\tif (xScaleDistr == 2) {\n\t\t\t\tdata[0] = Array(dataLen);\n\t\t\t\tfor (let i = 0; i < dataLen; i++)\n\t\t\t\t\tdata[0][i] = i;\n\t\t\t}\n\t\t}\n\n\t\tself._data = data;\n\n\t\tresetYSeries(true);\n\n\t\tfire(\"setData\");\n\n\t\t// forces x axis tick values to re-generate when neither x scale nor y scale changes\n\t\t// in ordinal mode, scale range is by index, so will not change if new data has same length, but tick values are from data\n\t\tif (xScaleDistr == 2) {\n\t\t\tshouldConvergeSize = true;\n\n\t\t\t/* or somewhat cheaper, and uglier:\n\t\t\tif (ready) {\n\t\t\t\t// logic extracted from axesCalc()\n\t\t\t\tlet i = 0;\n\t\t\t\tlet axis = axes[i];\n\t\t\t\tlet _splits = axis._splits.map(i => data0[i]);\n\t\t\t\tlet [_incr, _space] = axis._found;\n\t\t\t\tlet incr = data0[_splits[1]] - data0[_splits[0]];\n\t\t\t\taxis._values = axis.values(self, axis.filter(self, _splits, i, _space, incr), i, _space, incr);\n\t\t\t}\n\t\t\t*/\n\t\t}\n\n\t\tif (_resetScales !== false) {\n\t\t\tlet xsc = scaleX;\n\n\t\t\tif (xsc.auto(self, viaAutoScaleX))\n\t\t\t\tautoScaleX();\n\t\t\telse\n\t\t\t\t_setScale(xScaleKey, xsc.min, xsc.max);\n\n\t\t\tshouldSetCursor = cursor.left >= 0;\n\t\t\tshouldSetLegend = true;\n\t\t\tcommit();\n\t\t}\n\t}\n\n\tself.setData = setData;\n\n\tfunction autoScaleX() {\n\t\tviaAutoScaleX = true;\n\n\t\tlet _min, _max;\n\n\t\tif (mode == 1) {\n\t\t\tif (dataLen > 0) {\n\t\t\t\ti0 = idxs[0] = 0;\n\t\t\t\ti1 = idxs[1] = dataLen - 1;\n\n\t\t\t\t_min = data[0][i0];\n\t\t\t\t_max = data[0][i1];\n\n\t\t\t\tif (xScaleDistr == 2) {\n\t\t\t\t\t_min = i0;\n\t\t\t\t\t_max = i1;\n\t\t\t\t}\n\t\t\t\telse if (dataLen == 1) {\n\t\t\t\t\tif (xScaleDistr == 3)\n\t\t\t\t\t\t[_min, _max] = rangeLog(_min, _min, scaleX.log, false);\n\t\t\t\t\telse if (xScaleDistr == 4)\n\t\t\t\t\t\t[_min, _max] = rangeAsinh(_min, _min, scaleX.log, false);\n\t\t\t\t\telse if (scaleX.time)\n\t\t\t\t\t\t_max = _min + round(86400 / ms);\n\t\t\t\t\telse\n\t\t\t\t\t\t[_min, _max] = rangeNum(_min, _max, rangePad, true);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\ti0 = idxs[0] = _min = null;\n\t\t\t\ti1 = idxs[1] = _max = null;\n\t\t\t}\n\t\t}\n\n\t\t_setScale(xScaleKey, _min, _max);\n\t}\n\n\tlet ctxStroke, ctxFill, ctxWidth, ctxDash, ctxJoin, ctxCap, ctxFont, ctxAlign, ctxBaseline;\n\tlet ctxAlpha;\n\n\tfunction setCtxStyle(stroke, width, dash, cap, fill, join) {\n\t\tstroke ??= transparent;\n\t\tdash   ??= EMPTY_ARR;\n\t\tcap    ??= \"butt\"; // (‿|‿)\n\t\tfill   ??= transparent;\n\t\tjoin   ??= \"round\";\n\n\t\tif (stroke != ctxStroke)\n\t\t\tctx.strokeStyle = ctxStroke = stroke;\n\t\tif (fill != ctxFill)\n\t\t\tctx.fillStyle = ctxFill = fill;\n\t\tif (width != ctxWidth)\n\t\t\tctx.lineWidth = ctxWidth = width;\n\t\tif (join != ctxJoin)\n\t\t\tctx.lineJoin = ctxJoin = join;\n\t\tif (cap != ctxCap)\n\t\t\tctx.lineCap = ctxCap = cap;\n\t\tif (dash != ctxDash)\n\t\t\tctx.setLineDash(ctxDash = dash);\n\t}\n\n\tfunction setFontStyle(font, fill, align, baseline) {\n\t\tif (fill != ctxFill)\n\t\t\tctx.fillStyle = ctxFill = fill;\n\t\tif (font != ctxFont)\n\t\t\tctx.font = ctxFont = font;\n\t\tif (align != ctxAlign)\n\t\t\tctx.textAlign = ctxAlign = align;\n\t\tif (baseline != ctxBaseline)\n\t\t\tctx.textBaseline = ctxBaseline = baseline;\n\t}\n\n\tfunction accScale(wsc, psc, facet, data, sorted = 0) {\n\t\tif (data.length > 0 && wsc.auto(self, viaAutoScaleX) && (psc == null || psc.min == null)) {\n\t\t\tlet _i0 = ifNull(i0, 0);\n\t\t\tlet _i1 = ifNull(i1, data.length - 1);\n\n\t\t\t// only run getMinMax() for invalidated series data, else reuse\n\t\t\tlet minMax = facet.min == null ? (wsc.distr == 3 ? getMinMaxLog(data, _i0, _i1) : getMinMax(data, _i0, _i1, sorted)) : [facet.min, facet.max];\n\n\t\t\t// initial min/max\n\t\t\twsc.min = min(wsc.min, facet.min = minMax[0]);\n\t\t\twsc.max = max(wsc.max, facet.max = minMax[1]);\n\t\t}\n\t}\n\n\tfunction setScales() {\n\t//\tlog(\"setScales()\", arguments);\n\n\t\t// wip scales\n\t\tlet wipScales = copy(scales, fastIsObj);\n\n\t\tfor (let k in wipScales) {\n\t\t\tlet wsc = wipScales[k];\n\t\t\tlet psc = pendScales[k];\n\n\t\t\tif (psc != null && psc.min != null) {\n\t\t\t\tassign(wsc, psc);\n\n\t\t\t\t// explicitly setting the x-scale invalidates everything (acts as redraw)\n\t\t\t\tif (k == xScaleKey)\n\t\t\t\t\tresetYSeries(true);\n\t\t\t}\n\t\t\telse if (k != xScaleKey || mode == 2) {\n\t\t\t\tif (dataLen == 0 && wsc.from == null) {\n\t\t\t\t\tlet minMax = wsc.range(self, null, null, k);\n\t\t\t\t\twsc.min = minMax[0];\n\t\t\t\t\twsc.max = minMax[1];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\twsc.min = inf;\n\t\t\t\t\twsc.max = -inf;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (dataLen > 0) {\n\t\t\t// pre-range y-scales from y series' data values\n\t\t\tseries.forEach((s, i) => {\n\t\t\t\tif (mode == 1) {\n\t\t\t\t\tlet k = s.scale;\n\t\t\t\t\tlet wsc = wipScales[k];\n\t\t\t\t\tlet psc = pendScales[k];\n\n\t\t\t\t\tif (i == 0) {\n\t\t\t\t\t\tlet minMax = wsc.range(self, wsc.min, wsc.max, k);\n\n\t\t\t\t\t\twsc.min = minMax[0];\n\t\t\t\t\t\twsc.max = minMax[1];\n\n\t\t\t\t\t\ti0 = closestIdx(wsc.min, data[0]);\n\t\t\t\t\t\ti1 = closestIdx(wsc.max, data[0]);\n\n\t\t\t\t\t\t// closest indices can be outside of view\n\t\t\t\t\t\tif (data[0][i0] < wsc.min)\n\t\t\t\t\t\t\ti0++;\n\t\t\t\t\t\tif (data[0][i1] > wsc.max)\n\t\t\t\t\t\t\ti1--;\n\n\t\t\t\t\t\ts.min = data0[i0];\n\t\t\t\t\t\ts.max = data0[i1];\n\t\t\t\t\t}\n\t\t\t\t\telse if (s.show && s.auto)\n\t\t\t\t\t\taccScale(wsc, psc, s, data[i], s.sorted);\n\n\t\t\t\t\ts.idxs[0] = i0;\n\t\t\t\t\ts.idxs[1] = i1;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (i > 0) {\n\t\t\t\t\t\tif (s.show && s.auto) {\n\t\t\t\t\t\t\t// TODO: only handles, assumes and requires facets[0] / 'x' scale, and facets[1] / 'y' scale\n\t\t\t\t\t\t\tlet [ xFacet, yFacet ] = s.facets;\n\t\t\t\t\t\t\tlet xScaleKey = xFacet.scale;\n\t\t\t\t\t\t\tlet yScaleKey = yFacet.scale;\n\t\t\t\t\t\t\tlet [ xData, yData ] = data[i];\n\n\t\t\t\t\t\t\taccScale(wipScales[xScaleKey], pendScales[xScaleKey], xFacet, xData, xFacet.sorted);\n\t\t\t\t\t\t\taccScale(wipScales[yScaleKey], pendScales[yScaleKey], yFacet, yData, yFacet.sorted);\n\n\t\t\t\t\t\t\t// temp\n\t\t\t\t\t\t\ts.min = yFacet.min;\n\t\t\t\t\t\t\ts.max = yFacet.max;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// range independent scales\n\t\t\tfor (let k in wipScales) {\n\t\t\t\tlet wsc = wipScales[k];\n\t\t\t\tlet psc = pendScales[k];\n\n\t\t\t\tif (wsc.from == null && (psc == null || psc.min == null)) {\n\t\t\t\t\tlet minMax = wsc.range(\n\t\t\t\t\t\tself,\n\t\t\t\t\t\twsc.min ==  inf ? null : wsc.min,\n\t\t\t\t\t\twsc.max == -inf ? null : wsc.max,\n\t\t\t\t\t\tk\n\t\t\t\t\t);\n\t\t\t\t\twsc.min = minMax[0];\n\t\t\t\t\twsc.max = minMax[1];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// range dependent scales\n\t\tfor (let k in wipScales) {\n\t\t\tlet wsc = wipScales[k];\n\n\t\t\tif (wsc.from != null) {\n\t\t\t\tlet base = wipScales[wsc.from];\n\n\t\t\t\tif (base.min == null)\n\t\t\t\t\twsc.min = wsc.max = null;\n\t\t\t\telse {\n\t\t\t\t\tlet minMax = wsc.range(self, base.min, base.max, k);\n\t\t\t\t\twsc.min = minMax[0];\n\t\t\t\t\twsc.max = minMax[1];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet changed = {};\n\t\tlet anyChanged = false;\n\n\t\tfor (let k in wipScales) {\n\t\t\tlet wsc = wipScales[k];\n\t\t\tlet sc = scales[k];\n\n\t\t\tif (sc.min != wsc.min || sc.max != wsc.max) {\n\t\t\t\tsc.min = wsc.min;\n\t\t\t\tsc.max = wsc.max;\n\n\t\t\t\tlet distr = sc.distr;\n\n\t\t\t\tsc._min = distr == 3 ? log10(sc.min) : distr == 4 ? asinh(sc.min, sc.asinh) : sc.min;\n\t\t\t\tsc._max = distr == 3 ? log10(sc.max) : distr == 4 ? asinh(sc.max, sc.asinh) : sc.max;\n\n\t\t\t\tchanged[k] = anyChanged = true;\n\t\t\t}\n\t\t}\n\n\t\tif (anyChanged) {\n\t\t\t// invalidate paths of all series on changed scales\n\t\t\tseries.forEach((s, i) => {\n\t\t\t\tif (mode == 2) {\n\t\t\t\t\tif (i > 0 && changed.y)\n\t\t\t\t\t\ts._paths = null;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (changed[s.scale])\n\t\t\t\t\t\ts._paths = null;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tfor (let k in changed) {\n\t\t\t\tshouldConvergeSize = true;\n\t\t\t\tfire(\"setScale\", k);\n\t\t\t}\n\n\t\t\tif (cursor.show && cursor.left >= 0)\n\t\t\t\tshouldSetCursor = shouldSetLegend = true;\n\t\t}\n\n\t\tfor (let k in pendScales)\n\t\t\tpendScales[k] = null;\n\t}\n\n\t// grabs the nearest indices with y data outside of x-scale limits\n\tfunction getOuterIdxs(ydata) {\n\t\tlet _i0 = clamp(i0 - 1, 0, dataLen - 1);\n\t\tlet _i1 = clamp(i1 + 1, 0, dataLen - 1);\n\n\t\twhile (ydata[_i0] == null && _i0 > 0)\n\t\t\t_i0--;\n\n\t\twhile (ydata[_i1] == null && _i1 < dataLen - 1)\n\t\t\t_i1++;\n\n\t\treturn [_i0, _i1];\n\t}\n\n\tfunction drawSeries() {\n\t\tif (dataLen > 0) {\n\t\t\tseries.forEach((s, i) => {\n\t\t\t\tif (i > 0 && s.show && s._paths == null) {\n\t\t\t\t\tlet _idxs = mode == 2 ? [0, data[i][0].length - 1] : getOuterIdxs(data[i]);\n\t\t\t\t\ts._paths = s.paths(self, i, _idxs[0], _idxs[1]);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tseries.forEach((s, i) => {\n\t\t\t\tif (i > 0 && s.show) {\n\t\t\t\t\tif (ctxAlpha != s.alpha)\n\t\t\t\t\t\tctx.globalAlpha = ctxAlpha = s.alpha;\n\n\t\t\t\t\t{\n\t\t\t\t\t\tcacheStrokeFill(i, false);\n\t\t\t\t\t\ts._paths && drawPath(i, false);\n\t\t\t\t\t}\n\n\t\t\t\t\t{\n\t\t\t\t\t\tcacheStrokeFill(i, true);\n\n\t\t\t\t\t\tlet _gaps = s._paths ? s._paths.gaps : null;\n\n\t\t\t\t\t\tlet show = s.points.show(self, i, i0, i1, _gaps);\n\t\t\t\t\t\tlet idxs = s.points.filter(self, i, show, _gaps);\n\n\t\t\t\t\t\tif (show || idxs) {\n\t\t\t\t\t\t\ts.points._paths = s.points.paths(self, i, i0, i1, idxs);\n\t\t\t\t\t\t\tdrawPath(i, true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (ctxAlpha != 1)\n\t\t\t\t\t\tctx.globalAlpha = ctxAlpha = 1;\n\n\t\t\t\t\tfire(\"drawSeries\", i);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tfunction cacheStrokeFill(si, _points) {\n\t\tlet s = _points ? series[si].points : series[si];\n\n\t\ts._stroke = s.stroke(self, si);\n\t\ts._fill   = s.fill(self, si);\n\t}\n\n\tfunction drawPath(si, _points) {\n\t\tlet s = _points ? series[si].points : series[si];\n\n\t\tlet strokeStyle = s._stroke;\n\t\tlet fillStyle   = s._fill;\n\n\t\tlet { stroke, fill, clip: gapsClip, flags } = s._paths;\n\t\tlet boundsClip = null;\n\t\tlet width = roundDec(s.width * pxRatio, 3);\n\t\tlet offset = (width % 2) / 2;\n\n\t\tif (_points && fillStyle == null)\n\t\t\tfillStyle = width > 0 ? \"#fff\" : strokeStyle;\n\n\t\tlet _pxAlign = s.pxAlign == 1;\n\n\t\t_pxAlign && ctx.translate(offset, offset);\n\n\t\tif (!_points) {\n\t\t\tlet lft = plotLft,\n\t\t\t\ttop = plotTop,\n\t\t\t\twid = plotWid,\n\t\t\t\thgt = plotHgt;\n\n\t\t\tlet halfWid = width * pxRatio / 2;\n\n\t\t\tif (s.min == 0)\n\t\t\t\thgt += halfWid;\n\n\t\t\tif (s.max == 0) {\n\t\t\t\ttop -= halfWid;\n\t\t\t\thgt += halfWid;\n\t\t\t}\n\n\t\t\tboundsClip = new Path2D();\n\t\t\tboundsClip.rect(lft, top, wid, hgt);\n\t\t}\n\n\t\t// the points pathbuilder's gapsClip is its boundsClip, since points dont need gaps clipping, and bounds depend on point size\n\t\tif (_points)\n\t\t\tstrokeFill(strokeStyle, width, s.dash, s.cap, fillStyle, stroke, fill, flags, gapsClip);\n\t\telse\n\t\t\tfillStroke(si, strokeStyle, width, s.dash, s.cap, fillStyle, stroke, fill, flags, boundsClip, gapsClip);\n\n\t\t_pxAlign && ctx.translate(-offset, -offset);\n\t}\n\n\tfunction fillStroke(si, strokeStyle, lineWidth, lineDash, lineCap, fillStyle, strokePath, fillPath, flags, boundsClip, gapsClip) {\n\t\tlet didStrokeFill = false;\n\n\t\t// for all bands where this series is the top edge, create upwards clips using the bottom edges\n\t\t// and apply clips + fill with band fill or dfltFill\n\t\tbands.forEach((b, bi) => {\n\t\t\t// isUpperEdge?\n\t\t\tif (b.series[0] == si) {\n\t\t\t\tlet lowerEdge = series[b.series[1]];\n\t\t\t\tlet lowerData = data[b.series[1]];\n\n\t\t\t\tlet bandClip = (lowerEdge._paths || EMPTY_OBJ).band;\n\n\t\t\t\tif (isArr(bandClip))\n\t\t\t\t\tbandClip = b.dir == 1 ? bandClip[0] : bandClip[1];\n\n\t\t\t\tlet gapsClip2;\n\n\t\t\t\tlet _fillStyle = null;\n\n\t\t\t\t// hasLowerEdge?\n\t\t\t\tif (lowerEdge.show && bandClip && hasData(lowerData, i0, i1)) {\n\t\t\t\t\t_fillStyle = b.fill(self, bi) || fillStyle;\n\t\t\t\t\tgapsClip2 = lowerEdge._paths.clip;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tbandClip = null;\n\n\t\t\t\tstrokeFill(strokeStyle, lineWidth, lineDash, lineCap, _fillStyle, strokePath, fillPath, flags, boundsClip, gapsClip, gapsClip2, bandClip);\n\n\t\t\t\tdidStrokeFill = true;\n\t\t\t}\n\t\t});\n\n\t\tif (!didStrokeFill)\n\t\t\tstrokeFill(strokeStyle, lineWidth, lineDash, lineCap, fillStyle, strokePath, fillPath, flags, boundsClip, gapsClip);\n\t}\n\n\tconst CLIP_FILL_STROKE = BAND_CLIP_FILL | BAND_CLIP_STROKE;\n\n\tfunction strokeFill(strokeStyle, lineWidth, lineDash, lineCap, fillStyle, strokePath, fillPath, flags, boundsClip, gapsClip, gapsClip2, bandClip) {\n\t\tsetCtxStyle(strokeStyle, lineWidth, lineDash, lineCap, fillStyle);\n\n\t\tif (boundsClip || gapsClip || bandClip) {\n\t\t\tctx.save();\n\t\t\tboundsClip && ctx.clip(boundsClip);\n\t\t\tgapsClip && ctx.clip(gapsClip);\n\t\t}\n\n\t\tif (bandClip) {\n\t\t\tif ((flags & CLIP_FILL_STROKE) == CLIP_FILL_STROKE) {\n\t\t\t\tctx.clip(bandClip);\n\t\t\t\tgapsClip2 && ctx.clip(gapsClip2);\n\t\t\t\tdoFill(fillStyle, fillPath);\n\t\t\t\tdoStroke(strokeStyle, strokePath, lineWidth);\n\t\t\t}\n\t\t\telse if (flags & BAND_CLIP_STROKE) {\n\t\t\t\tdoFill(fillStyle, fillPath);\n\t\t\t\tctx.clip(bandClip);\n\t\t\t\tdoStroke(strokeStyle, strokePath, lineWidth);\n\t\t\t}\n\t\t\telse if (flags & BAND_CLIP_FILL) {\n\t\t\t\tctx.save();\n\t\t\t\tctx.clip(bandClip);\n\t\t\t\tgapsClip2 && ctx.clip(gapsClip2);\n\t\t\t\tdoFill(fillStyle, fillPath);\n\t\t\t\tctx.restore();\n\t\t\t\tdoStroke(strokeStyle, strokePath, lineWidth);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tdoFill(fillStyle, fillPath);\n\t\t\tdoStroke(strokeStyle, strokePath, lineWidth);\n\t\t}\n\n\t\tif (boundsClip || gapsClip || bandClip)\n\t\t\tctx.restore();\n\t}\n\n\tfunction doStroke(strokeStyle, strokePath, lineWidth) {\n\t\tif (lineWidth > 0) {\n\t\t\tif (strokePath instanceof Map) {\n\t\t\t\tstrokePath.forEach((strokePath, strokeStyle) => {\n\t\t\t\t\tctx.strokeStyle = ctxStroke = strokeStyle;\n\t\t\t\t\tctx.stroke(strokePath);\n\t\t\t\t});\n\t\t\t}\n\t\t\telse\n\t\t\t\tstrokePath != null && strokeStyle && ctx.stroke(strokePath);\n\t\t}\n\t}\n\n\tfunction doFill(fillStyle, fillPath) {\n\t\tif (fillPath instanceof Map) {\n\t\t\tfillPath.forEach((fillPath, fillStyle) => {\n\t\t\t\tctx.fillStyle = ctxFill = fillStyle;\n\t\t\t\tctx.fill(fillPath);\n\t\t\t});\n\t\t}\n\t\telse\n\t\t\tfillPath != null && fillStyle && ctx.fill(fillPath);\n\t}\n\n\tfunction getIncrSpace(axisIdx, min, max, fullDim) {\n\t\tlet axis = axes[axisIdx];\n\n\t\tlet incrSpace;\n\n\t\tif (fullDim <= 0)\n\t\t\tincrSpace = [0, 0];\n\t\telse {\n\t\t\tlet minSpace = axis._space = axis.space(self, axisIdx, min, max, fullDim);\n\t\t\tlet incrs    = axis._incrs = axis.incrs(self, axisIdx, min, max, fullDim, minSpace);\n\t\t\tincrSpace    = findIncr(min, max, incrs, fullDim, minSpace);\n\t\t}\n\n\t\treturn (axis._found = incrSpace);\n\t}\n\n\tfunction drawOrthoLines(offs, filts, ori, side, pos0, len, width, stroke, dash, cap) {\n\t\tlet offset = (width % 2) / 2;\n\n\t\tpxAlign == 1 && ctx.translate(offset, offset);\n\n\t\tsetCtxStyle(stroke, width, dash, cap, stroke);\n\n\t\tctx.beginPath();\n\n\t\tlet x0, y0, x1, y1, pos1 = pos0 + (side == 0 || side == 3 ? -len : len);\n\n\t\tif (ori == 0) {\n\t\t\ty0 = pos0;\n\t\t\ty1 = pos1;\n\t\t}\n\t\telse {\n\t\t\tx0 = pos0;\n\t\t\tx1 = pos1;\n\t\t}\n\n\t\tfor (let i = 0; i < offs.length; i++) {\n\t\t\tif (filts[i] != null) {\n\t\t\t\tif (ori == 0)\n\t\t\t\t\tx0 = x1 = offs[i];\n\t\t\t\telse\n\t\t\t\t\ty0 = y1 = offs[i];\n\n\t\t\t\tctx.moveTo(x0, y0);\n\t\t\t\tctx.lineTo(x1, y1);\n\t\t\t}\n\t\t}\n\n\t\tctx.stroke();\n\n\t\tpxAlign == 1 && ctx.translate(-offset, -offset);\n\t}\n\n\tfunction axesCalc(cycleNum) {\n\t//\tlog(\"axesCalc()\", arguments);\n\n\t\tlet converged = true;\n\n\t\taxes.forEach((axis, i) => {\n\t\t\tif (!axis.show)\n\t\t\t\treturn;\n\n\t\t\tlet scale = scales[axis.scale];\n\n\t\t\tif (scale.min == null) {\n\t\t\t\tif (axis._show) {\n\t\t\t\t\tconverged = false;\n\t\t\t\t\taxis._show = false;\n\t\t\t\t\tresetYSeries(false);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (!axis._show) {\n\t\t\t\t\tconverged = false;\n\t\t\t\t\taxis._show = true;\n\t\t\t\t\tresetYSeries(false);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet side = axis.side;\n\t\t\tlet ori = side % 2;\n\n\t\t\tlet {min, max} = scale;\t\t// \t\t// should this toggle them ._show = false\n\n\t\t\tlet [_incr, _space] = getIncrSpace(i, min, max, ori == 0 ? plotWidCss : plotHgtCss);\n\n\t\t\tif (_space == 0)\n\t\t\t\treturn;\n\n\t\t\t// if we're using index positions, force first tick to match passed index\n\t\t\tlet forceMin = scale.distr == 2;\n\n\t\t\tlet _splits = axis._splits = axis.splits(self, i, min, max, _incr, _space, forceMin);\n\n\t\t\t// tick labels\n\t\t\t// BOO this assumes a specific data/series\n\t\t\tlet splits = scale.distr == 2 ? _splits.map(i => data0[i]) : _splits;\n\t\t\tlet incr   = scale.distr == 2 ? data0[_splits[1]] - data0[_splits[0]] : _incr;\n\n\t\t\tlet values = axis._values = axis.values(self, axis.filter(self, splits, i, _space, incr), i, _space, incr);\n\n\t\t\t// rotating of labels only supported on bottom x axis\n\t\t\taxis._rotate = side == 2 ? axis.rotate(self, values, i, _space) : 0;\n\n\t\t\tlet oldSize = axis._size;\n\n\t\t\taxis._size = ceil(axis.size(self, values, i, cycleNum));\n\n\t\t\tif (oldSize != null && axis._size != oldSize)\t\t\t// ready && ?\n\t\t\t\tconverged = false;\n\t\t});\n\n\t\treturn converged;\n\t}\n\n\tfunction paddingCalc(cycleNum) {\n\t\tlet converged = true;\n\n\t\tpadding.forEach((p, i) => {\n\t\t\tlet _p = p(self, i, sidesWithAxes, cycleNum);\n\n\t\t\tif (_p != _padding[i])\n\t\t\t\tconverged = false;\n\n\t\t\t_padding[i] = _p;\n\t\t});\n\n\t\treturn converged;\n\t}\n\n\tfunction drawAxesGrid() {\n\t\tfor (let i = 0; i < axes.length; i++) {\n\t\t\tlet axis = axes[i];\n\n\t\t\tif (!axis.show || !axis._show)\n\t\t\t\tcontinue;\n\n\t\t\tlet side = axis.side;\n\t\t\tlet ori = side % 2;\n\n\t\t\tlet x, y;\n\n\t\t\tlet fillStyle = axis.stroke(self, i);\n\n\t\t\tlet shiftDir = side == 0 || side == 3 ? -1 : 1;\n\n\t\t\t// axis label\n\t\t\tif (axis.label) {\n\t\t\t\tlet shiftAmt = axis.labelGap * shiftDir;\n\t\t\t\tlet baseLpos = round((axis._lpos + shiftAmt) * pxRatio);\n\n\t\t\t\tsetFontStyle(axis.labelFont[0], fillStyle, \"center\", side == 2 ? TOP : BOTTOM);\n\n\t\t\t\tctx.save();\n\n\t\t\t\tif (ori == 1) {\n\t\t\t\t\tx = y = 0;\n\n\t\t\t\t\tctx.translate(\n\t\t\t\t\t\tbaseLpos,\n\t\t\t\t\t\tround(plotTop + plotHgt / 2),\n\t\t\t\t\t);\n\t\t\t\t\tctx.rotate((side == 3 ? -PI : PI) / 2);\n\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tx = round(plotLft + plotWid / 2);\n\t\t\t\t\ty = baseLpos;\n\t\t\t\t}\n\n\t\t\t\tctx.fillText(axis.label, x, y);\n\n\t\t\t\tctx.restore();\n\t\t\t}\n\n\t\t\tlet [_incr, _space] = axis._found;\n\n\t\t\tif (_space == 0)\n\t\t\t\tcontinue;\n\n\t\t\tlet scale = scales[axis.scale];\n\n\t\t\tlet plotDim = ori == 0 ? plotWid : plotHgt;\n\t\t\tlet plotOff = ori == 0 ? plotLft : plotTop;\n\n\t\t\tlet axisGap = round(axis.gap * pxRatio);\n\n\t\t\tlet _splits = axis._splits;\n\n\t\t\t// tick labels\n\t\t\t// BOO this assumes a specific data/series\n\t\t\tlet splits = scale.distr == 2 ? _splits.map(i => data0[i]) : _splits;\n\t\t\tlet incr   = scale.distr == 2 ? data0[_splits[1]] - data0[_splits[0]] : _incr;\n\n\t\t\tlet ticks = axis.ticks;\n\t\t\tlet border = axis.border;\n\t\t\tlet tickSize = ticks.show ? round(ticks.size * pxRatio) : 0;\n\n\t\t\t// rotating of labels only supported on bottom x axis\n\t\t\tlet angle = axis._rotate * -PI/180;\n\n\t\t\tlet basePos  = pxRound(axis._pos * pxRatio);\n\t\t\tlet shiftAmt = (tickSize + axisGap) * shiftDir;\n\t\t\tlet finalPos = basePos + shiftAmt;\n\t\t\t    y        = ori == 0 ? finalPos : 0;\n\t\t\t    x        = ori == 1 ? finalPos : 0;\n\n\t\t\tlet font         = axis.font[0];\n\t\t\tlet textAlign    = axis.align == 1 ? LEFT :\n\t\t\t                   axis.align == 2 ? RIGHT :\n\t\t\t                   angle > 0 ? LEFT :\n\t\t\t                   angle < 0 ? RIGHT :\n\t\t\t                   ori == 0 ? \"center\" : side == 3 ? RIGHT : LEFT;\n\t\t\tlet textBaseline = angle ||\n\t\t\t                   ori == 1 ? \"middle\" : side == 2 ? TOP   : BOTTOM;\n\n\t\t\tsetFontStyle(font, fillStyle, textAlign, textBaseline);\n\n\t\t\tlet lineHeight = axis.font[1] * lineMult;\n\n\t\t\tlet canOffs = _splits.map(val => pxRound(getPos(val, scale, plotDim, plotOff)));\n\n\t\t\tlet _values = axis._values;\n\n\t\t\tfor (let i = 0; i < _values.length; i++) {\n\t\t\t\tlet val = _values[i];\n\n\t\t\t\tif (val != null) {\n\t\t\t\t\tif (ori == 0)\n\t\t\t\t\t\tx = canOffs[i];\n\t\t\t\t\telse\n\t\t\t\t\t\ty = canOffs[i];\n\n\t\t\t\t\tval = \"\" + val;\n\n\t\t\t\t\tlet _parts = val.indexOf(\"\\n\") == -1 ? [val] : val.split(/\\n/gm);\n\n\t\t\t\t\tfor (let j = 0; j < _parts.length; j++) {\n\t\t\t\t\t\tlet text = _parts[j];\n\n\t\t\t\t\t\tif (angle) {\n\t\t\t\t\t\t\tctx.save();\n\t\t\t\t\t\t\tctx.translate(x, y + j * lineHeight); // can this be replaced with position math?\n\t\t\t\t\t\t\tctx.rotate(angle); // can this be done once?\n\t\t\t\t\t\t\tctx.fillText(text, 0, 0);\n\t\t\t\t\t\t\tctx.restore();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tctx.fillText(text, x, y + j * lineHeight);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// ticks\n\t\t\tif (ticks.show) {\n\t\t\t\tdrawOrthoLines(\n\t\t\t\t\tcanOffs,\n\t\t\t\t\tticks.filter(self, splits, i, _space, incr),\n\t\t\t\t\tori,\n\t\t\t\t\tside,\n\t\t\t\t\tbasePos,\n\t\t\t\t\ttickSize,\n\t\t\t\t\troundDec(ticks.width * pxRatio, 3),\n\t\t\t\t\tticks.stroke(self, i),\n\t\t\t\t\tticks.dash,\n\t\t\t\t\tticks.cap,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// grid\n\t\t\tlet grid = axis.grid;\n\n\t\t\tif (grid.show) {\n\t\t\t\tdrawOrthoLines(\n\t\t\t\t\tcanOffs,\n\t\t\t\t\tgrid.filter(self, splits, i, _space, incr),\n\t\t\t\t\tori,\n\t\t\t\t\tori == 0 ? 2 : 1,\n\t\t\t\t\tori == 0 ? plotTop : plotLft,\n\t\t\t\t\tori == 0 ? plotHgt : plotWid,\n\t\t\t\t\troundDec(grid.width * pxRatio, 3),\n\t\t\t\t\tgrid.stroke(self, i),\n\t\t\t\t\tgrid.dash,\n\t\t\t\t\tgrid.cap,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (border.show) {\n\t\t\t\tdrawOrthoLines(\n\t\t\t\t\t[basePos],\n\t\t\t\t\t[1],\n\t\t\t\t\tori == 0 ? 1 : 0,\n\t\t\t\t\tori == 0 ? 1 : 2,\n\t\t\t\t\tori == 1 ? plotTop : plotLft,\n\t\t\t\t\tori == 1 ? plotHgt : plotWid,\n\t\t\t\t\troundDec(border.width * pxRatio, 3),\n\t\t\t\t\tborder.stroke(self, i),\n\t\t\t\t\tborder.dash,\n\t\t\t\t\tborder.cap,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tfire(\"drawAxes\");\n\t}\n\n\tfunction resetYSeries(minMax) {\n\t//\tlog(\"resetYSeries()\", arguments);\n\n\t\tseries.forEach((s, i) => {\n\t\t\tif (i > 0) {\n\t\t\t\ts._paths = null;\n\n\t\t\t\tif (minMax) {\n\t\t\t\t\tif (mode == 1) {\n\t\t\t\t\t\ts.min = null;\n\t\t\t\t\t\ts.max = null;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\ts.facets.forEach(f => {\n\t\t\t\t\t\t\tf.min = null;\n\t\t\t\t\t\t\tf.max = null;\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tlet queuedCommit = false;\n\n\tfunction commit() {\n\t\tif (!queuedCommit) {\n\t\t\tmicroTask(_commit);\n\t\t\tqueuedCommit = true;\n\t\t}\n\t}\n\n\tfunction _commit() {\n\t//\tlog(\"_commit()\", arguments);\n\n\t\tif (shouldSetScales) {\n\t\t\tsetScales();\n\t\t\tshouldSetScales = false;\n\t\t}\n\n\t\tif (shouldConvergeSize) {\n\t\t\tconvergeSize();\n\t\t\tshouldConvergeSize = false;\n\t\t}\n\n\t\tif (shouldSetSize) {\n\t\t\tsetStylePx(under, LEFT,   plotLftCss);\n\t\t\tsetStylePx(under, TOP,    plotTopCss);\n\t\t\tsetStylePx(under, WIDTH,  plotWidCss);\n\t\t\tsetStylePx(under, HEIGHT, plotHgtCss);\n\n\t\t\tsetStylePx(over, LEFT,    plotLftCss);\n\t\t\tsetStylePx(over, TOP,     plotTopCss);\n\t\t\tsetStylePx(over, WIDTH,   plotWidCss);\n\t\t\tsetStylePx(over, HEIGHT,  plotHgtCss);\n\n\t\t\tsetStylePx(wrap, WIDTH,   fullWidCss);\n\t\t\tsetStylePx(wrap, HEIGHT,  fullHgtCss);\n\n\t\t\t// NOTE: mutating this during print preview in Chrome forces transparent\n\t\t\t// canvas pixels to white, even when followed up with clearRect() below\n\t\t\tcan.width  = round(fullWidCss * pxRatio);\n\t\t\tcan.height = round(fullHgtCss * pxRatio);\n\n\t\t\taxes.forEach(({ _el, _show, _size, _pos, side }) => {\n\t\t\t\tif (_el != null) {\n\t\t\t\t\tif (_show) {\n\t\t\t\t\t\tlet posOffset = (side === 3 || side === 0 ? _size : 0);\n\t\t\t\t\t\tlet isVt = side % 2 == 1;\n\n\t\t\t\t\t\tsetStylePx(_el, isVt ? \"left\"   : \"top\",    _pos - posOffset);\n\t\t\t\t\t\tsetStylePx(_el, isVt ? \"width\"  : \"height\", _size);\n\t\t\t\t\t\tsetStylePx(_el, isVt ? \"top\"    : \"left\",   isVt ? plotTopCss : plotLftCss);\n\t\t\t\t\t\tsetStylePx(_el, isVt ? \"height\" : \"width\",  isVt ? plotHgtCss : plotWidCss);\n\n\t\t\t\t\t\tremClass(_el, OFF);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\taddClass(_el, OFF);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// invalidate ctx style cache\n\t\t\tctxStroke = ctxFill = ctxWidth = ctxJoin = ctxCap = ctxFont = ctxAlign = ctxBaseline = ctxDash = null;\n\t\t\tctxAlpha = 1;\n\n\t\t\tsyncRect(true);\n\n\t\t\tfire(\"setSize\");\n\n\t\t\tshouldSetSize = false;\n\t\t}\n\n\t\tif (fullWidCss > 0 && fullHgtCss > 0) {\n\t\t\tctx.clearRect(0, 0, can.width, can.height);\n\t\t\tfire(\"drawClear\");\n\t\t\tdrawOrder.forEach(fn => fn());\n\t\t\tfire(\"draw\");\n\t\t}\n\n\t\tif (select.show && shouldSetSelect) {\n\t\t\tsetSelect(select);\n\t\t\tshouldSetSelect = false;\n\t\t}\n\n\t\tif (cursor.show && shouldSetCursor) {\n\t\t\tupdateCursor(null, true, false);\n\t\t\tshouldSetCursor = false;\n\t\t}\n\n\t//\tif (FEAT_LEGEND && legend.show && legend.live && shouldSetLegend) {}\n\n\t\tif (!ready) {\n\t\t\tready = true;\n\t\t\tself.status = 1;\n\n\t\t\tfire(\"ready\");\n\t\t}\n\n\t\tviaAutoScaleX = false;\n\n\t\tqueuedCommit = false;\n\t}\n\n\tself.redraw = (rebuildPaths, recalcAxes) => {\n\t\tshouldConvergeSize = recalcAxes || false;\n\n\t\tif (rebuildPaths !== false)\n\t\t\t_setScale(xScaleKey, scaleX.min, scaleX.max);\n\t\telse\n\t\t\tcommit();\n\t};\n\n\t// redraw() => setScale('x', scales.x.min, scales.x.max);\n\n\t// explicit, never re-ranged (is this actually true? for x and y)\n\tfunction setScale(key, opts) {\n\t\tlet sc = scales[key];\n\n\t\tif (sc.from == null) {\n\t\t\tif (dataLen == 0) {\n\t\t\t\tlet minMax = sc.range(self, opts.min, opts.max, key);\n\t\t\t\topts.min = minMax[0];\n\t\t\t\topts.max = minMax[1];\n\t\t\t}\n\n\t\t\tif (opts.min > opts.max) {\n\t\t\t\tlet _min = opts.min;\n\t\t\t\topts.min = opts.max;\n\t\t\t\topts.max = _min;\n\t\t\t}\n\n\t\t\tif (dataLen > 1 && opts.min != null && opts.max != null && opts.max - opts.min < 1e-16)\n\t\t\t\treturn;\n\n\t\t\tif (key == xScaleKey) {\n\t\t\t\tif (sc.distr == 2 && dataLen > 0) {\n\t\t\t\t\topts.min = closestIdx(opts.min, data[0]);\n\t\t\t\t\topts.max = closestIdx(opts.max, data[0]);\n\n\t\t\t\t\tif (opts.min == opts.max)\n\t\t\t\t\t\topts.max++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t//\tlog(\"setScale()\", arguments);\n\n\t\t\tpendScales[key] = opts;\n\n\t\t\tshouldSetScales = true;\n\t\t\tcommit();\n\t\t}\n\t}\n\n\tself.setScale = setScale;\n\n//\tINTERACTION\n\n\tlet xCursor;\n\tlet yCursor;\n\tlet vCursor;\n\tlet hCursor;\n\n\t// starting position before cursor.move\n\tlet rawMouseLeft0;\n\tlet rawMouseTop0;\n\n\t// starting position\n\tlet mouseLeft0;\n\tlet mouseTop0;\n\n\t// current position before cursor.move\n\tlet rawMouseLeft1;\n\tlet rawMouseTop1;\n\n\t// current position\n\tlet mouseLeft1;\n\tlet mouseTop1;\n\n\tlet dragging = false;\n\n\tconst drag = cursor.drag;\n\n\tlet dragX = drag.x;\n\tlet dragY = drag.y;\n\n\tif (cursor.show) {\n\t\tif (cursor.x)\n\t\t\txCursor = placeDiv(CURSOR_X, over);\n\t\tif (cursor.y)\n\t\t\tyCursor = placeDiv(CURSOR_Y, over);\n\n\t\tif (scaleX.ori == 0) {\n\t\t\tvCursor = xCursor;\n\t\t\thCursor = yCursor;\n\t\t}\n\t\telse {\n\t\t\tvCursor = yCursor;\n\t\t\thCursor = xCursor;\n\t\t}\n\n\t\tmouseLeft1 = cursor.left;\n\t\tmouseTop1 = cursor.top;\n\t}\n\n\tconst select = self.select = assign({\n\t\tshow:   true,\n\t\tover:   true,\n\t\tleft:   0,\n\t\twidth:  0,\n\t\ttop:    0,\n\t\theight: 0,\n\t}, opts.select);\n\n\tconst selectDiv = select.show ? placeDiv(SELECT, select.over ? over : under) : null;\n\n\tfunction setSelect(opts, _fire) {\n\t\tif (select.show) {\n\t\t\tfor (let prop in opts) {\n\t\t\t\tselect[prop] = opts[prop];\n\n\t\t\t\tif (prop in _hideProps)\n\t\t\t\t\tsetStylePx(selectDiv, prop, opts[prop]);\n\t\t\t}\n\n\t\t\t_fire !== false && fire(\"setSelect\");\n\t\t}\n\t}\n\n\tself.setSelect = setSelect;\n\n\tfunction toggleDOM(i, onOff) {\n\t\tlet s = series[i];\n\t\tlet label = showLegend ? legendRows[i] : null;\n\n\t\tif (s.show)\n\t\t\tlabel && remClass(label, OFF);\n\t\telse {\n\t\t\tlabel && addClass(label, OFF);\n\t\t\tcursorPts.length > 1 && elTrans(cursorPts[i], -10, -10, plotWidCss, plotHgtCss);\n\t\t}\n\t}\n\n\tfunction _setScale(key, min, max) {\n\t\tsetScale(key, {min, max});\n\t}\n\n\tfunction setSeries(i, opts, _fire, _pub) {\n\t//\tlog(\"setSeries()\", arguments);\n\n\t\tif (opts.focus != null)\n\t\t\tsetFocus(i);\n\n\t\tif (opts.show != null) {\n\t\t\tseries.forEach((s, si) => {\n\t\t\t\tif (si > 0 && (i == si || i == null)) {\n\t\t\t\t\ts.show = opts.show;\n\t\t\t\t\ttoggleDOM(si, opts.show);\n\n\t\t\t\t\t_setScale(mode == 2 ? s.facets[1].scale : s.scale, null, null);\n\t\t\t\t\tcommit();\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t_fire !== false && fire(\"setSeries\", i, opts);\n\n\t\t_pub && pubSync(\"setSeries\", self, i, opts);\n\t}\n\n\tself.setSeries = setSeries;\n\n\tfunction setBand(bi, opts) {\n\t\tassign(bands[bi], opts);\n\t}\n\n\tfunction addBand(opts, bi) {\n\t\topts.fill = fnOrSelf(opts.fill || null);\n\t\topts.dir = ifNull(opts.dir, -1);\n\t\tbi = bi == null ? bands.length : bi;\n\t\tbands.splice(bi, 0, opts);\n\t}\n\n\tfunction delBand(bi) {\n\t\tif (bi == null)\n\t\t\tbands.length = 0;\n\t\telse\n\t\t\tbands.splice(bi, 1);\n\t}\n\n\tself.addBand = addBand;\n\tself.setBand = setBand;\n\tself.delBand = delBand;\n\n\tfunction setAlpha(i, value) {\n\t\tseries[i].alpha = value;\n\n\t\tif (cursor.show && cursorPts[i])\n\t\t\tcursorPts[i].style.opacity = value;\n\n\t\tif (showLegend && legendRows[i])\n\t\t\tlegendRows[i].style.opacity = value;\n\t}\n\n\t// y-distance\n\tlet closestDist;\n\tlet closestSeries;\n\tlet focusedSeries;\n\tconst FOCUS_TRUE  = {focus: true};\n\n\tfunction setFocus(i) {\n\t\tif (i != focusedSeries) {\n\t\t//\tlog(\"setFocus()\", arguments);\n\n\t\t\tlet allFocused = i == null;\n\n\t\t\tlet _setAlpha = focus.alpha != 1;\n\n\t\t\tseries.forEach((s, i2) => {\n\t\t\t\tlet isFocused = allFocused || i2 == 0 || i2 == i;\n\t\t\t\ts._focus = allFocused ? null : isFocused;\n\t\t\t\t_setAlpha && setAlpha(i2, isFocused ? 1 : focus.alpha);\n\t\t\t});\n\n\t\t\tfocusedSeries = i;\n\t\t\t_setAlpha && commit();\n\t\t}\n\t}\n\n\tif (showLegend && cursorFocus) {\n\t\ton(mouseleave, legendEl, e => {\n\t\t\tif (cursor._lock)\n\t\t\t\treturn;\n\n\t\t\tif (focusedSeries != null)\n\t\t\t\tsetSeries(null, FOCUS_TRUE, true, syncOpts.setSeries);\n\t\t});\n\t}\n\n\tfunction posToVal(pos, scale, can) {\n\t\tlet sc = scales[scale];\n\n\t\tif (can)\n\t\t\tpos = pos / pxRatio - (sc.ori == 1 ? plotTopCss : plotLftCss);\n\n\t\tlet dim = plotWidCss;\n\n\t\tif (sc.ori == 1) {\n\t\t\tdim = plotHgtCss;\n\t\t\tpos = dim - pos;\n\t\t}\n\n\t\tif (sc.dir == -1)\n\t\t\tpos = dim - pos;\n\n\t\tlet _min = sc._min,\n\t\t\t_max = sc._max,\n\t\t\tpct = pos / dim;\n\n\t\tlet sv = _min + (_max - _min) * pct;\n\n\t\tlet distr = sc.distr;\n\n\t\treturn (\n\t\t\tdistr == 3 ? pow(10, sv) :\n\t\t\tdistr == 4 ? sinh(sv, sc.asinh) :\n\t\t\tsv\n\t\t);\n\t}\n\n\tfunction closestIdxFromXpos(pos, can) {\n\t\tlet v = posToVal(pos, xScaleKey, can);\n\t\treturn closestIdx(v, data[0], i0, i1);\n\t}\n\n\tself.valToIdx = val => closestIdx(val, data[0]);\n\tself.posToIdx = closestIdxFromXpos;\n\tself.posToVal = posToVal;\n\tself.valToPos = (val, scale, can) => (\n\t\tscales[scale].ori == 0 ?\n\t\tgetHPos(val, scales[scale],\n\t\t\tcan ? plotWid : plotWidCss,\n\t\t\tcan ? plotLft : 0,\n\t\t) :\n\t\tgetVPos(val, scales[scale],\n\t\t\tcan ? plotHgt : plotHgtCss,\n\t\t\tcan ? plotTop : 0,\n\t\t)\n\t);\n\n\t// defers calling expensive functions\n\tfunction batch(fn) {\n\t\tfn(self);\n\t\tcommit();\n\t}\n\n\tself.batch = batch;\n\n\t(self.setCursor = (opts, _fire, _pub) => {\n\t\tmouseLeft1 = opts.left;\n\t\tmouseTop1 = opts.top;\n\t//\tassign(cursor, opts);\n\t\tupdateCursor(null, _fire, _pub);\n\t});\n\n\tfunction setSelH(off, dim) {\n\t\tsetStylePx(selectDiv, LEFT,  select.left = off);\n\t\tsetStylePx(selectDiv, WIDTH, select.width = dim);\n\t}\n\n\tfunction setSelV(off, dim) {\n\t\tsetStylePx(selectDiv, TOP,    select.top = off);\n\t\tsetStylePx(selectDiv, HEIGHT, select.height = dim);\n\t}\n\n\tlet setSelX = scaleX.ori == 0 ? setSelH : setSelV;\n\tlet setSelY = scaleX.ori == 1 ? setSelH : setSelV;\n\n\tfunction syncLegend() {\n\t\tif (showLegend && legend.live) {\n\t\t\tfor (let i = mode == 2 ? 1 : 0; i < series.length; i++) {\n\t\t\t\tif (i == 0 && multiValLegend)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tlet vals = legend.values[i];\n\n\t\t\t\tlet j = 0;\n\n\t\t\t\tfor (let k in vals)\n\t\t\t\t\tlegendCells[i][j++].firstChild.nodeValue = vals[k];\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction setLegend(opts, _fire) {\n\t\tif (opts != null) {\n\t\t\tlet idx = opts.idx;\n\n\t\t\tlegend.idx = idx;\n\t\t\tseries.forEach((s, sidx) => {\n\t\t\t\t(sidx > 0 || !multiValLegend) && setLegendValues(sidx, idx);\n\t\t\t});\n\t\t}\n\n\t\tif (showLegend && legend.live)\n\t\t\tsyncLegend();\n\n\t\tshouldSetLegend = false;\n\n\t\t_fire !== false && fire(\"setLegend\");\n\t}\n\n\tself.setLegend = setLegend;\n\n\tfunction setLegendValues(sidx, idx) {\n\t\tlet val;\n\n\t\tif (idx == null)\n\t\t\tval = NULL_LEGEND_VALUES;\n\t\telse {\n\t\t\tlet s = series[sidx];\n\t\t\tlet src = sidx == 0 && xScaleDistr == 2 ? data0 : data[sidx];\n\t\t\tval = multiValLegend ? s.values(self, sidx, idx) : {_: s.value(self, src[idx], sidx, idx)};\n\t\t}\n\n\t\tlegend.values[sidx] = val;\n\t}\n\n\tfunction updateCursor(src, _fire, _pub) {\n\t//\tts == null && log(\"updateCursor()\", arguments);\n\n\t\trawMouseLeft1 = mouseLeft1;\n\t\trawMouseTop1 = mouseTop1;\n\n\t\t[mouseLeft1, mouseTop1] = cursor.move(self, mouseLeft1, mouseTop1);\n\n\t\tif (cursor.show) {\n\t\t\tvCursor && elTrans(vCursor, round(mouseLeft1), 0, plotWidCss, plotHgtCss);\n\t\t\thCursor && elTrans(hCursor, 0, round(mouseTop1), plotWidCss, plotHgtCss);\n\t\t}\n\n\t\tlet idx;\n\n\t\t// when zooming to an x scale range between datapoints the binary search\n\t\t// for nearest min/max indices results in this condition. cheap hack :D\n\t\tlet noDataInRange = i0 > i1; // works for mode 1 only\n\n\t\tclosestDist = inf;\n\n\t\t// TODO: extract\n\t\tlet xDim = scaleX.ori == 0 ? plotWidCss : plotHgtCss;\n\t\tlet yDim = scaleX.ori == 1 ? plotWidCss : plotHgtCss;\n\n\t\t// if cursor hidden, hide points & clear legend vals\n\t\tif (mouseLeft1 < 0 || dataLen == 0 || noDataInRange) {\n\t\t\tidx = null;\n\n\t\t\tfor (let i = 0; i < series.length; i++) {\n\t\t\t\tif (i > 0) {\n\t\t\t\t\tcursorPts.length > 1 && elTrans(cursorPts[i], -10, -10, plotWidCss, plotHgtCss);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (cursorFocus)\n\t\t\t\tsetSeries(null, FOCUS_TRUE, true, src == null && syncOpts.setSeries);\n\n\t\t\tif (legend.live) {\n\t\t\t\tactiveIdxs.fill(null);\n\t\t\t\tshouldSetLegend = true;\n\n\t\t\t\tfor (let i = 0; i < series.length; i++)\n\t\t\t\t\tlegend.values[i] = NULL_LEGEND_VALUES;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t//\tlet pctY = 1 - (y / rect.height);\n\n\t\t\tlet mouseXPos, valAtPosX, xPos;\n\n\t\t\tif (mode == 1) {\n\t\t\t\tmouseXPos = scaleX.ori == 0 ? mouseLeft1 : mouseTop1;\n\t\t\t\tvalAtPosX = posToVal(mouseXPos, xScaleKey);\n\t\t\t\tidx = closestIdx(valAtPosX, data[0], i0, i1);\n\t\t\t\txPos = incrRoundUp(valToPosX(data[0][idx], scaleX, xDim, 0), 0.5);\n\t\t\t}\n\n\t\t\tfor (let i = mode == 2 ? 1 : 0; i < series.length; i++) {\n\t\t\t\tlet s = series[i];\n\n\t\t\t\tlet idx1  = activeIdxs[i];\n\t\t\t\tlet yVal1 = mode == 1 ? data[i][idx1] : data[i][1][idx1];\n\n\t\t\t\tlet idx2  = cursor.dataIdx(self, i, idx, valAtPosX);\n\t\t\t\tlet yVal2 = mode == 1 ? data[i][idx2] : data[i][1][idx2];\n\n\t\t\t\tshouldSetLegend = shouldSetLegend || yVal2 != yVal1 || idx2 != idx1;\n\n\t\t\t\tactiveIdxs[i] = idx2;\n\n\t\t\t\tlet xPos2 = idx2 == idx ? xPos : incrRoundUp(valToPosX(mode == 1 ? data[0][idx2] : data[i][0][idx2], scaleX, xDim, 0), 0.5);\n\n\t\t\t\tif (i > 0 && s.show) {\n\t\t\t\t\tlet yPos = yVal2 == null ? -10 : incrRoundUp(valToPosY(yVal2, mode == 1 ? scales[s.scale] : scales[s.facets[1].scale], yDim, 0), 0.5);\n\n\t\t\t\t\tif (yPos > 0 && mode == 1) {\n\t\t\t\t\t\tlet dist = abs(yPos - mouseTop1);\n\n\t\t\t\t\t\tif (dist <= closestDist) {\n\t\t\t\t\t\t\tclosestDist = dist;\n\t\t\t\t\t\t\tclosestSeries = i;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tlet hPos, vPos;\n\n\t\t\t\t\tif (scaleX.ori == 0) {\n\t\t\t\t\t\thPos = xPos2;\n\t\t\t\t\t\tvPos = yPos;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\thPos = yPos;\n\t\t\t\t\t\tvPos = xPos2;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (shouldSetLegend && cursorPts.length > 1) {\n\t\t\t\t\t\telColor(cursorPts[i], cursor.points.fill(self, i), cursor.points.stroke(self, i));\n\n\t\t\t\t\t\tlet ptWid, ptHgt, ptLft, ptTop,\n\t\t\t\t\t\t\tcentered = true,\n\t\t\t\t\t\t\tgetBBox = cursor.points.bbox;\n\n\t\t\t\t\t\tif (getBBox != null) {\n\t\t\t\t\t\t\tcentered = false;\n\n\t\t\t\t\t\t\tlet bbox = getBBox(self, i);\n\n\t\t\t\t\t\t\tptLft = bbox.left;\n\t\t\t\t\t\t\tptTop = bbox.top;\n\t\t\t\t\t\t\tptWid = bbox.width;\n\t\t\t\t\t\t\tptHgt = bbox.height;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tptLft = hPos;\n\t\t\t\t\t\t\tptTop = vPos;\n\t\t\t\t\t\t\tptWid = ptHgt = cursor.points.size(self, i);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\telSize(cursorPts[i], ptWid, ptHgt, centered);\n\t\t\t\t\t\telTrans(cursorPts[i], ptLft, ptTop, plotWidCss, plotHgtCss);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (legend.live) {\n\t\t\t\t\tif (!shouldSetLegend || i == 0 && multiValLegend)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tsetLegendValues(i, idx2);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tcursor.idx = idx;\n\t\tcursor.left = mouseLeft1;\n\t\tcursor.top = mouseTop1;\n\n\t\tif (shouldSetLegend) {\n\t\t\tlegend.idx = idx;\n\t\t\tsetLegend();\n\t\t}\n\n\t\t// nit: cursor.drag.setSelect is assumed always true\n\t\tif (select.show && dragging) {\n\t\t\tif (src != null) {\n\t\t\t\tlet [xKey, yKey] = syncOpts.scales;\n\t\t\t\tlet [matchXKeys, matchYKeys] = syncOpts.match;\n\t\t\t\tlet [xKeySrc, yKeySrc] = src.cursor.sync.scales;\n\n\t\t\t\t// match the dragX/dragY implicitness/explicitness of src\n\t\t\t\tlet sdrag = src.cursor.drag;\n\t\t\t\tdragX = sdrag._x;\n\t\t\t\tdragY = sdrag._y;\n\n\t\t\t\tif (dragX || dragY) {\n\t\t\t\t\tlet { left, top, width, height } = src.select;\n\n\t\t\t\t\tlet sori = src.scales[xKey].ori;\n\t\t\t\t\tlet sPosToVal = src.posToVal;\n\n\t\t\t\t\tlet sOff, sDim, sc, a, b;\n\n\t\t\t\t\tlet matchingX = xKey != null && matchXKeys(xKey, xKeySrc);\n\t\t\t\t\tlet matchingY = yKey != null && matchYKeys(yKey, yKeySrc);\n\n\t\t\t\t\tif (matchingX && dragX) {\n\t\t\t\t\t\tif (sori == 0) {\n\t\t\t\t\t\t\tsOff = left;\n\t\t\t\t\t\t\tsDim = width;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tsOff = top;\n\t\t\t\t\t\t\tsDim = height;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tsc = scales[xKey];\n\n\t\t\t\t\t\ta = valToPosX(sPosToVal(sOff, xKeySrc),        sc, xDim, 0);\n\t\t\t\t\t\tb = valToPosX(sPosToVal(sOff + sDim, xKeySrc), sc, xDim, 0);\n\n\t\t\t\t\t\tsetSelX(min(a,b), abs(b-a));\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tsetSelX(0, xDim);\n\n\t\t\t\t\tif (matchingY && dragY) {\n\t\t\t\t\t\tif (sori == 1) {\n\t\t\t\t\t\t\tsOff = left;\n\t\t\t\t\t\t\tsDim = width;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tsOff = top;\n\t\t\t\t\t\t\tsDim = height;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tsc = scales[yKey];\n\n\t\t\t\t\t\ta = valToPosY(sPosToVal(sOff, yKeySrc),        sc, yDim, 0);\n\t\t\t\t\t\tb = valToPosY(sPosToVal(sOff + sDim, yKeySrc), sc, yDim, 0);\n\n\t\t\t\t\t\tsetSelY(min(a,b), abs(b-a));\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tsetSelY(0, yDim);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\thideSelect();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlet rawDX = abs(rawMouseLeft1 - rawMouseLeft0);\n\t\t\t\tlet rawDY = abs(rawMouseTop1 - rawMouseTop0);\n\n\t\t\t\tif (scaleX.ori == 1) {\n\t\t\t\t\tlet _rawDX = rawDX;\n\t\t\t\t\trawDX = rawDY;\n\t\t\t\t\trawDY = _rawDX;\n\t\t\t\t}\n\n\t\t\t\tdragX = drag.x && rawDX >= drag.dist;\n\t\t\t\tdragY = drag.y && rawDY >= drag.dist;\n\n\t\t\t\tlet uni = drag.uni;\n\n\t\t\t\tif (uni != null) {\n\t\t\t\t\t// only calc drag status if they pass the dist thresh\n\t\t\t\t\tif (dragX && dragY) {\n\t\t\t\t\t\tdragX = rawDX >= uni;\n\t\t\t\t\t\tdragY = rawDY >= uni;\n\n\t\t\t\t\t\t// force unidirectionality when both are under uni limit\n\t\t\t\t\t\tif (!dragX && !dragY) {\n\t\t\t\t\t\t\tif (rawDY > rawDX)\n\t\t\t\t\t\t\t\tdragY = true;\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tdragX = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (drag.x && drag.y && (dragX || dragY))\n\t\t\t\t\t// if omni with no uni then both dragX / dragY should be true if either is true\n\t\t\t\t\tdragX = dragY = true;\n\n\t\t\t\tlet p0, p1;\n\n\t\t\t\tif (dragX) {\n\t\t\t\t\tif (scaleX.ori == 0) {\n\t\t\t\t\t\tp0 = mouseLeft0;\n\t\t\t\t\t\tp1 = mouseLeft1;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tp0 = mouseTop0;\n\t\t\t\t\t\tp1 = mouseTop1;\n\t\t\t\t\t}\n\n\t\t\t\t\tsetSelX(min(p0, p1), abs(p1 - p0));\n\n\t\t\t\t\tif (!dragY)\n\t\t\t\t\t\tsetSelY(0, yDim);\n\t\t\t\t}\n\n\t\t\t\tif (dragY) {\n\t\t\t\t\tif (scaleX.ori == 1) {\n\t\t\t\t\t\tp0 = mouseLeft0;\n\t\t\t\t\t\tp1 = mouseLeft1;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tp0 = mouseTop0;\n\t\t\t\t\t\tp1 = mouseTop1;\n\t\t\t\t\t}\n\n\t\t\t\t\tsetSelY(min(p0, p1), abs(p1 - p0));\n\n\t\t\t\t\tif (!dragX)\n\t\t\t\t\t\tsetSelX(0, xDim);\n\t\t\t\t}\n\n\t\t\t\t// the drag didn't pass the dist requirement\n\t\t\t\tif (!dragX && !dragY) {\n\t\t\t\t\tsetSelX(0, 0);\n\t\t\t\t\tsetSelY(0, 0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tdrag._x = dragX;\n\t\tdrag._y = dragY;\n\n\t\tif (src == null) {\n\t\t\tif (_pub) {\n\t\t\t\tif (syncKey != null) {\n\t\t\t\t\tlet [xSyncKey, ySyncKey] = syncOpts.scales;\n\n\t\t\t\t\tsyncOpts.values[0] = xSyncKey != null ? posToVal(scaleX.ori == 0 ? mouseLeft1 : mouseTop1, xSyncKey) : null;\n\t\t\t\t\tsyncOpts.values[1] = ySyncKey != null ? posToVal(scaleX.ori == 1 ? mouseLeft1 : mouseTop1, ySyncKey) : null;\n\t\t\t\t}\n\n\t\t\t\tpubSync(mousemove, self, mouseLeft1, mouseTop1, plotWidCss, plotHgtCss, idx);\n\t\t\t}\n\n\t\t\tif (cursorFocus) {\n\t\t\t\tlet shouldPub = _pub && syncOpts.setSeries;\n\t\t\t\tlet p = focus.prox;\n\n\t\t\t\tif (focusedSeries == null) {\n\t\t\t\t\tif (closestDist <= p)\n\t\t\t\t\t\tsetSeries(closestSeries, FOCUS_TRUE, true, shouldPub);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (closestDist > p)\n\t\t\t\t\t\tsetSeries(null, FOCUS_TRUE, true, shouldPub);\n\t\t\t\t\telse if (closestSeries != focusedSeries)\n\t\t\t\t\t\tsetSeries(closestSeries, FOCUS_TRUE, true, shouldPub);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t_fire !== false && fire(\"setCursor\");\n\t}\n\n\tlet rect = null;\n\n\tfunction syncRect(defer) {\n\t\tif (defer === true)\n\t\t\trect = null;\n\t\telse {\n\t\t\trect = over.getBoundingClientRect();\n\t\t\tfire(\"syncRect\", rect);\n\t\t}\n\t}\n\n\tfunction mouseMove(e, src, _l, _t, _w, _h, _i) {\n\t\tif (cursor._lock)\n\t\t\treturn;\n\n\t\tcacheMouse(e, src, _l, _t, _w, _h, _i, false, e != null);\n\n\t\tif (e != null)\n\t\t\tupdateCursor(null, true, true);\n\t\telse\n\t\t\tupdateCursor(src, true, false);\n\t}\n\n\tfunction cacheMouse(e, src, _l, _t, _w, _h, _i, initial, snap) {\n\t\tif (rect == null)\n\t\t\tsyncRect(false);\n\n\t\tif (e != null) {\n\t\t\t_l = e.clientX - rect.left;\n\t\t\t_t = e.clientY - rect.top;\n\t\t}\n\t\telse {\n\t\t\tif (_l < 0 || _t < 0) {\n\t\t\t\tmouseLeft1 = -10;\n\t\t\t\tmouseTop1 = -10;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet [xKey, yKey] = syncOpts.scales;\n\n\t\t\tlet syncOptsSrc = src.cursor.sync;\n\t\t\tlet [xValSrc, yValSrc] = syncOptsSrc.values;\n\t\t\tlet [xKeySrc, yKeySrc] = syncOptsSrc.scales;\n\t\t\tlet [matchXKeys, matchYKeys] = syncOpts.match;\n\n\t\t\tlet rotSrc = src.axes[0].side % 2 == 1;\n\n\t\t\tlet xDim = scaleX.ori == 0 ? plotWidCss : plotHgtCss,\n\t\t\t\tyDim = scaleX.ori == 1 ? plotWidCss : plotHgtCss,\n\t\t\t\t_xDim = rotSrc ? _h : _w,\n\t\t\t\t_yDim = rotSrc ? _w : _h,\n\t\t\t\t_xPos = rotSrc ? _t : _l,\n\t\t\t\t_yPos = rotSrc ? _l : _t;\n\n\t\t\tif (xKeySrc != null)\n\t\t\t\t_l = matchXKeys(xKey, xKeySrc) ? getPos(xValSrc, scales[xKey], xDim, 0) : -10;\n\t\t\telse\n\t\t\t\t_l = xDim * (_xPos/_xDim);\n\n\t\t\tif (yKeySrc != null)\n\t\t\t\t_t = matchYKeys(yKey, yKeySrc) ? getPos(yValSrc, scales[yKey], yDim, 0) : -10;\n\t\t\telse\n\t\t\t\t_t = yDim * (_yPos/_yDim);\n\n\t\t\tif (scaleX.ori == 1) {\n\t\t\t\tlet __l = _l;\n\t\t\t\t_l = _t;\n\t\t\t\t_t = __l;\n\t\t\t}\n\t\t}\n\n\t\tif (snap) {\n\t\t\tif (_l <= 1 || _l >= plotWidCss - 1)\n\t\t\t\t_l = incrRound(_l, plotWidCss);\n\n\t\t\tif (_t <= 1 || _t >= plotHgtCss - 1)\n\t\t\t\t_t = incrRound(_t, plotHgtCss);\n\t\t}\n\n\t\tif (initial) {\n\t\t\trawMouseLeft0 = _l;\n\t\t\trawMouseTop0 = _t;\n\n\t\t\t[mouseLeft0, mouseTop0] = cursor.move(self, _l, _t);\n\t\t}\n\t\telse {\n\t\t\tmouseLeft1 = _l;\n\t\t\tmouseTop1 = _t;\n\t\t}\n\t}\n\n\tconst _hideProps = {\n\t\twidth: 0,\n\t\theight: 0,\n\t\tleft: 0,\n\t\ttop: 0,\n\t};\n\n\tfunction hideSelect() {\n\t\tsetSelect(_hideProps, false);\n\t}\n\n\tfunction mouseDown(e, src, _l, _t, _w, _h, _i) {\n\t\tdragging = true;\n\t\tdragX = dragY = drag._x = drag._y = false;\n\n\t\tcacheMouse(e, src, _l, _t, _w, _h, _i, true, false);\n\n\t\tif (e != null) {\n\t\t\tonMouse(mouseup, doc, mouseUp);\n\t\t\tpubSync(mousedown, self, mouseLeft0, mouseTop0, plotWidCss, plotHgtCss, null);\n\t\t}\n\t}\n\n\tfunction mouseUp(e, src, _l, _t, _w, _h, _i) {\n\t\tdragging = drag._x = drag._y = false;\n\n\t\tcacheMouse(e, src, _l, _t, _w, _h, _i, false, true);\n\n\t\tlet { left, top, width, height } = select;\n\n\t\tlet hasSelect = width > 0 || height > 0;\n\n\t\thasSelect && setSelect(select);\n\n\t\tif (drag.setScale && hasSelect) {\n\t\t//\tif (syncKey != null) {\n\t\t//\t\tdragX = drag.x;\n\t\t//\t\tdragY = drag.y;\n\t\t//\t}\n\n\t\t\tlet xOff = left,\n\t\t\t\txDim = width,\n\t\t\t\tyOff = top,\n\t\t\t\tyDim = height;\n\n\t\t\tif (scaleX.ori == 1) {\n\t\t\t\txOff = top,\n\t\t\t\txDim = height,\n\t\t\t\tyOff = left,\n\t\t\t\tyDim = width;\n\t\t\t}\n\n\t\t\tif (dragX) {\n\t\t\t\t_setScale(xScaleKey,\n\t\t\t\t\tposToVal(xOff, xScaleKey),\n\t\t\t\t\tposToVal(xOff + xDim, xScaleKey)\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (dragY) {\n\t\t\t\tfor (let k in scales) {\n\t\t\t\t\tlet sc = scales[k];\n\n\t\t\t\t\tif (k != xScaleKey && sc.from == null && sc.min != inf) {\n\t\t\t\t\t\t_setScale(k,\n\t\t\t\t\t\t\tposToVal(yOff + yDim, k),\n\t\t\t\t\t\t\tposToVal(yOff, k)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\thideSelect();\n\t\t}\n\t\telse if (cursor.lock) {\n\t\t\tcursor._lock = !cursor._lock;\n\n\t\t\tif (!cursor._lock)\n\t\t\t\tupdateCursor(null, true, false);\n\t\t}\n\n\t\tif (e != null) {\n\t\t\toffMouse(mouseup, doc);\n\t\t\tpubSync(mouseup, self, mouseLeft1, mouseTop1, plotWidCss, plotHgtCss, null);\n\t\t}\n\t}\n\n\tfunction mouseLeave(e, src, _l, _t, _w, _h, _i) {\n\t\tif (!cursor._lock) {\n\t\t\tlet _dragging = dragging;\n\n\t\t\tif (dragging) {\n\t\t\t\t// handle case when mousemove aren't fired all the way to edges by browser\n\t\t\t\tlet snapH = true;\n\t\t\t\tlet snapV = true;\n\t\t\t\tlet snapProx = 10;\n\n\t\t\t\tlet dragH, dragV;\n\n\t\t\t\tif (scaleX.ori == 0) {\n\t\t\t\t\tdragH = dragX;\n\t\t\t\t\tdragV = dragY;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tdragH = dragY;\n\t\t\t\t\tdragV = dragX;\n\t\t\t\t}\n\n\t\t\t\tif (dragH && dragV) {\n\t\t\t\t\t// maybe omni corner snap\n\t\t\t\t\tsnapH = mouseLeft1 <= snapProx || mouseLeft1 >= plotWidCss - snapProx;\n\t\t\t\t\tsnapV = mouseTop1  <= snapProx || mouseTop1  >= plotHgtCss - snapProx;\n\t\t\t\t}\n\n\t\t\t\tif (dragH && snapH)\n\t\t\t\t\tmouseLeft1 = mouseLeft1 < mouseLeft0 ? 0 : plotWidCss;\n\n\t\t\t\tif (dragV && snapV)\n\t\t\t\t\tmouseTop1 = mouseTop1 < mouseTop0 ? 0 : plotHgtCss;\n\n\t\t\t\tupdateCursor(null, true, true);\n\n\t\t\t\tdragging = false;\n\t\t\t}\n\n\t\t\tmouseLeft1 = -10;\n\t\t\tmouseTop1 = -10;\n\n\t\t\t// passing a non-null timestamp to force sync/mousemove event\n\t\t\tupdateCursor(null, true, true);\n\n\t\t\tif (_dragging)\n\t\t\t\tdragging = _dragging;\n\t\t}\n\t}\n\n\tfunction dblClick(e, src, _l, _t, _w, _h, _i) {\n\t\tautoScaleX();\n\n\t\thideSelect();\n\n\t\tif (e != null)\n\t\t\tpubSync(dblclick, self, mouseLeft1, mouseTop1, plotWidCss, plotHgtCss, null);\n\t}\n\n\tfunction syncPxRatio() {\n\t\taxes.forEach(syncFontSize);\n\t\t_setSize(self.width, self.height, true);\n\t}\n\n\ton(dppxchange, win, syncPxRatio);\n\n\t// internal pub/sub\n\tconst events = {};\n\n\tevents.mousedown = mouseDown;\n\tevents.mousemove = mouseMove;\n\tevents.mouseup = mouseUp;\n\tevents.dblclick = dblClick;\n\tevents[\"setSeries\"] = (e, src, idx, opts) => {\n\t\tsetSeries(idx, opts, true, false);\n\t};\n\n\tif (cursor.show) {\n\t\tonMouse(mousedown,  over, mouseDown);\n\t\tonMouse(mousemove,  over, mouseMove);\n\t\tonMouse(mouseenter, over, syncRect);\n\t\tonMouse(mouseleave, over, mouseLeave);\n\n\t\tonMouse(dblclick, over, dblClick);\n\n\t\tcursorPlots.add(self);\n\n\t\tself.syncRect = syncRect;\n\t}\n\n\t// external on/off\n\tconst hooks = self.hooks = opts.hooks || {};\n\n\tfunction fire(evName, a1, a2) {\n\t\tif (evName in hooks) {\n\t\t\thooks[evName].forEach(fn => {\n\t\t\t\tfn.call(null, self, a1, a2);\n\t\t\t});\n\t\t}\n\t}\n\n\t(opts.plugins || []).forEach(p => {\n\t\tfor (let evName in p.hooks)\n\t\t\thooks[evName] = (hooks[evName] || []).concat(p.hooks[evName]);\n\t});\n\n\tconst syncOpts = assign({\n\t\tkey: null,\n\t\tsetSeries: false,\n\t\tfilters: {\n\t\t\tpub: retTrue,\n\t\t\tsub: retTrue,\n\t\t},\n\t\tscales: [xScaleKey, series[1] ? series[1].scale : null],\n\t\tmatch: [retEq, retEq],\n\t\tvalues: [null, null],\n\t}, cursor.sync);\n\n\t(cursor.sync = syncOpts);\n\n\tconst syncKey = syncOpts.key;\n\n\tconst sync = _sync(syncKey);\n\n\tfunction pubSync(type, src, x, y, w, h, i) {\n\t\tif (syncOpts.filters.pub(type, src, x, y, w, h, i))\n\t\t\tsync.pub(type, src, x, y, w, h, i);\n\t}\n\n\tsync.sub(self);\n\n\tfunction pub(type, src, x, y, w, h, i) {\n\t\tif (syncOpts.filters.sub(type, src, x, y, w, h, i))\n\t\t\tevents[type](null, src, x, y, w, h, i);\n\t}\n\n\t(self.pub = pub);\n\n\tfunction destroy() {\n\t\tsync.unsub(self);\n\t\tcursorPlots.delete(self);\n\t\tmouseListeners.clear();\n\t\toff(dppxchange, win, syncPxRatio);\n\t\troot.remove();\n\t\tlegendEl?.remove(); // in case mounted outside of root\n\t\tfire(\"destroy\");\n\t}\n\n\tself.destroy = destroy;\n\n\tfunction _init() {\n\t\tfire(\"init\", opts, data);\n\n\t\tsetData(data || opts.data, false);\n\n\t\tif (pendScales[xScaleKey])\n\t\t\tsetScale(xScaleKey, pendScales[xScaleKey]);\n\t\telse\n\t\t\tautoScaleX();\n\n\t\tshouldSetSelect = select.show;\n\t\tshouldSetCursor = shouldSetLegend = true;\n\n\t\t_setSize(opts.width, opts.height);\n\t}\n\n\tseries.forEach(initSeries);\n\n\taxes.forEach(initAxis);\n\n\tif (then) {\n\t\tif (then instanceof HTMLElement) {\n\t\t\tthen.appendChild(root);\n\t\t\t_init();\n\t\t}\n\t\telse\n\t\t\tthen(self, _init);\n\t}\n\telse\n\t\t_init();\n\n\treturn self;\n}\n\nuPlot.assign = assign;\nuPlot.fmtNum = fmtNum;\nuPlot.rangeNum = rangeNum;\nuPlot.rangeLog = rangeLog;\nuPlot.rangeAsinh = rangeAsinh;\nuPlot.orient   = orient;\nuPlot.pxRatio = pxRatio;\n\n{\n\tuPlot.join = join;\n}\n\n{\n\tuPlot.fmtDate = fmtDate;\n\tuPlot.tzDate  = tzDate;\n}\n\n{\n\tuPlot.sync = _sync;\n}\n\n{\n\tuPlot.addGap = addGap;\n\tuPlot.clipGaps = clipGaps;\n\n\tlet paths = uPlot.paths = {\n\t\tpoints,\n\t};\n\n\t(paths.linear  = linear);\n\t(paths.stepped = stepped);\n\t(paths.bars    = bars);\n\t(paths.spline  = monotoneCubic);\n}\n\nexport { uPlot as default };\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/src/components/Footer.vue",
    "content": "<template>\n  <b-navbar fixed=\"bottom\" toggleable=\"lg\" type=\"light\" variant=\"light\">\n    <b-container class=\"d-block\">\n      <b-row class=\"align-items-start\">\n        <b-col v-if=\"nodeName\">\n          <BBadge variant=\"warning\" pill> {{ $t(\"SwitchedNode\") }}: {{ nodeName }}</BBadge>\n        </b-col>\n        <b-col>\n          <BBadge variant=\"secondary\" pill>{{ meta.cap?.name ?? \"CAP\" }}: {{ meta.cap?.version.substring(0, 5) }}</BBadge>\n        </b-col>\n        <b-col>\n          <BBadge variant=\"secondary\" pill> {{ $t(\"Storage\") }}: {{ meta.storage?.name }}</BBadge>\n        </b-col>\n        <b-col>\n          <BBadge variant=\"secondary\" pill> {{ $t(\"Transport\") }}: {{ meta.broker?.name }}</BBadge>\n        </b-col>\n      </b-row>\n    </b-container>\n  </b-navbar>\n</template>\n<script>\nimport axios from 'axios';\nimport { BBadge } from 'bootstrap-vue';\nexport default {\n  data() {\n    return {\n      nodeName: \"\",\n      meta: {}\n    };\n  },\n  async mounted() {\n    this.nodeName = this.getCookie(\"cap.node\");\n    await axios.get(\"/meta\").then(res => {\n      this.meta = res.data;\n    });\n  },\n  methods: {\n    getCookie(cname) {\n      var name = cname + \"=\";\n      var decodedCookie = decodeURIComponent(document.cookie);\n      var ca = decodedCookie.split(\";\");\n      for (var i = 0; i < ca.length; i++) {\n        var c = ca[i];\n        while (c.charAt(0) == \" \") {\n          c = c.substring(1);\n        }\n        if (c.indexOf(name) == 0) {\n          return c.substring(name.length, c.length);\n        }\n      }\n      return \"\";\n    }\n  },\n  components: { BBadge }\n}\n</script>\n<style scoped>\n.d-block {\n  color: rgba(255, 255, 255, 0.6);\n}\n</style>"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/src/components/Navigation.vue",
    "content": "<template>\n  <div>\n    <b-navbar toggleable=\"lg\" type=\"dark\" sticky variant=\"dark\">\n      <b-container>\n\n        <b-navbar-toggle target=\"nav-collapse\"></b-navbar-toggle>\n\n        <b-collapse id=\"nav-collapse\" is-nav>\n          <b-navbar-brand to=\"/\">\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" height=\"30\" class=\"d-inline-block align-top\"\n              viewBox=\"0 0 192.13 196.72\">\n              <g>\n                <g>\n                  <path\n                    d=\"M166.87 100.62a71.54 71.54 0 0 1-70.81 70.8c-38.86.33-70.48-32.43-70.8-70.8-.14-16.28-25.4-16.3-25.26 0a98 98 0 0 0 26.75 66.51c16.88 18 40.66 28 65.06 29.44 24.86 1.46 49.1-8 67.83-24s29.43-39.31 32.07-63.53c.3-2.8.39-5.63.42-8.44.13-16.3-25.12-16.28-25.26 0z\"\n                    fill=\"#4a5699\"></path>\n                  <path\n                    d=\"M25.26 96.07a71.54 71.54 0 0 1 70.8-70.81c16.28-.14 16.3-25.4 0-25.26a97.79 97.79 0 0 0-67.45 27.67C10.25 45.46.21 70.65 0 96.07c-.14 16.29 25.12 16.27 25.26 0z\"\n                    fill=\"#c45fa0\"></path>\n                  <path\n                    d=\"M73.83 118.81c-10.58-14.11-9-30.09 4.14-41.46 12.31-10.62 30.52-6.6 40.93 6.34 4.33 5.37 13.39 4.48 17.86 0 5.26-5.25 4.31-12.5 0-17.86-17.42-21.65-50.71-25.9-73-9.21C40.58 74 34.26 107.87 52 131.56c4.12 5.5 10.82 8.31 17.28 4.53 5.42-3.18 8.66-11.76 4.53-17.28z\"\n                    fill=\"#e5594f\"></path>\n                  <path\n                    d=\"M118.3 82.91c6 8 7.54 14 6.68 23.29.14-1.14.08-.93-.18.62-.26 1.32-.64 2.62-1 3.91a14.07 14.07 0 0 1-1.9 4.44c-2.34 4.43-4.59 6.68-8.84 10.1-5.38 4.32-4.48 13.39 0 17.86 5.25 5.26 12.5 4.31 17.85 0 21.66-17.42 25.91-50.71 9.22-73-4.12-5.5-10.82-8.31-17.28-4.53-5.43 3.18-8.67 11.76-4.53 17.28z\"\n                    fill=\"#f39a2b\"></path>\n                </g>\n              </g>\n            </svg>\n            {{ $t(brandTitle) }}\n          </b-navbar-brand>\n          <b-navbar-nav>\n            <b-nav-item v-for=\"menu in menus\" :to=\"menu.path\" :key=\"menu.name\" active-class=\"active\">\n              {{ $t(menu.name) }}\n              <b-badge :variant=\"menu.variant\" v-if=\"onMetric[menu.badge]\"> {{ onMetric[menu.badge] }}</b-badge>\n            </b-nav-item>\n          </b-navbar-nav>\n        </b-collapse>\n\n        <b-navbar-nav class=\"ml-auto flex-row\">\n          <b-nav-item>\n            <b-dropdown size=\"sm\" id=\"dlLang\" text=\"secondary\" variant=\"secondary\" :text=\"$t('LanguageName')\">\n              <b-dropdown-item v-for=\"lang in languages\" class=\"text-secondary drop-active\" :key=\"lang.code\"\n                :active=\"checkCurrentLang(lang.code)\" @click=\"changeLang(lang.code)\">{{ lang.name }}</b-dropdown-item>\n            </b-dropdown>\n          </b-nav-item>\n\n          <b-nav-item href=\"https://github.com/dotnetcore/CAP\" target=\"_blank\" title=\"Github\">\n            <b-icon-github style=\"width:24px;height:24px\"></b-icon-github>\n          </b-nav-item>\n        </b-navbar-nav>\n      </b-container>\n    </b-navbar>\n  </div>\n</template>\n<script>\nimport { BIconGithub } from 'bootstrap-vue';\nexport default {\n  name: \"Navigation\",\n  components: {\n    BIconGithub\n  },\n  computed: {\n    onMetric() {\n      return this.$store.getters.getMetric;\n    }\n  },\n  methods: {\n    changeLang(langCode) {\n      localStorage.setItem('lang', langCode);\n      this.$i18n.locale = langCode;\n    },\n    checkCurrentLang(langCode) {\n      return this.$i18n.locale == langCode;\n    }\n  },\n  data() {\n    return {\n      i18nPrefix: \"_.Navigation.\",\n      brandTitle: \"CAP Dashboard\",\n      languages: [\n        { name: \"English\", code: \"en-us\", active: true },\n        { name: \"简体中文\", code: \"zh-cn\", active: false }\n      ],\n      menus: [\n        { name: \"Published\", path: \"/published\", variant: \"danger\", badge: \"publishedFailed\" },\n        { name: \"Received\", path: \"/received\", variant: \"danger\", badge: \"receivedFailed\" },\n        { name: \"Subscriber\", path: \"/subscriber\", variant: \"info\", badge: \"subscribers\" },\n        { name: \"Nodes\", path: \"/nodes\", variant: \"light\", badge: \"servers\" },\n      ]\n    };\n  },\n\n};\n</script>\n<style scoped>\n.nav-item {\n  padding: 0 10px;\n}\n</style>\n<style>.drop-active .active {\n  background-color: black !important;\n}</style>"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/src/main.js",
    "content": "import Vue from 'vue'\nimport App from './App.vue'\nimport router from './router'\nimport BootstrapVue from 'bootstrap-vue'\nimport VueJsonPretty from 'vue-json-pretty';\nimport 'vue-json-pretty/lib/styles.css';\nimport 'bootstrap/dist/css/bootstrap.css'\nimport 'bootstrap-vue/dist/bootstrap-vue.css'\nimport store from '../src/store/store.js'\nimport axios from \"axios\";\nimport VueI18n from 'vue-i18n'\nimport * as zh from './assets/language/zh-cn'\nimport * as en from './assets/language/en-us'\n//\n\nlet baseURL = \"\";\nswitch (import.meta.env.MODE) {\n  case 'development':\n      baseURL = \"/cap/api\";\n      break\n  default:\n      baseURL = window.serverUrl;\n      break\n}\n\naxios.defaults.baseURL = baseURL;\naxios.defaults.withCredentials = true\naxios.defaults.headers.post['Content-Type'] = 'application/json';\naxios.interceptors.request.use(\n  config => {\n    let accessToken = localStorage.getItem('token');\n    if (accessToken) {\n      config.headers = Object.assign({\n        Authorization: `Bearer ${accessToken}`\n      }, config.headers);\n    }\n    return config;\n  },\n  error => {\n    return Promise.reject(error);\n  }\n);\n\n\nVue.config.productionTip = false\n\nVue.use(BootstrapVue)\nVue.component(\"vue-json-pretty\", VueJsonPretty)\nVue.use(VueI18n)\n\nconst i18n = new VueI18n({\n  locale: (function () {\n    if (localStorage.getItem('lang')) {\n      return localStorage.getItem('lang')\n    }\n    return 'en-us'\n  }()),\n  messages: {\n    'en-us': en.default,\n    'zh-cn': zh.default,\n  }\n})\n\nnew Vue({\n  router,\n  store,\n  i18n,\n  render: h => h(App)\n}).$mount('#app')"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/src/pages/Home.vue",
    "content": "<template>\n  <b-container>\n    <h2 class=\"page-line mb-4\">{{ $t(\"Dashboard\") }}</h2>\n    <b-row>\n      <b-col>\n        <h3 class=\"mb-4\">{{ $t(\"Realtime Metric Graph\") }}</h3>\n        <div id=\"realtimeGraph\"></div>\n        <p class=\"text-secondary\">{{ $t(\"SubscriberInvokeMeanTime\") }}</p>\n      </b-col>\n    </b-row>\n    <b-row>\n      <b-col>\n        <h3 class=\"mt-4\">{{ $t(\"24h History Graph\") }}</h3>\n        <div id=\"historyGraph\"></div>\n      </b-col>\n    </b-row>\n  </b-container>\n</template>\n\n<script>\n\nimport uPlot from '../assets/uPlot.esm.js';\nimport axios from 'axios';\n\nexport default {\n  data() {\n    return {\n      timer: Number\n    }\n  },\n  async mounted() {\n    const params = new Proxy(new URLSearchParams(window.location.search), {\n      get: (searchParams, prop) => searchParams.get(prop),\n    });\n    let accessToken = params.access_token;\n    if (accessToken) {\n      localStorage.setItem('token', accessToken)\n    }\n\n    const realtimeOpts = {\n      width: 960,\n      height: 400,\n      cursor: {\n        drag: {\n          setScale: false,\n        }\n      },\n      select: {\n        show: false,\n      },\n      series: [\n        {\n          value: \"{YYYY}/{MM}/{DD} {HH}:{mm}:{ss}\"\n        },\n        {\n          label: this.$t(\"Publish TPS\"),\n          show: true,\n          scale: \"s\",\n          width: 2,\n          value: (u, v) => v == null ? \"-\" : v.toFixed(1) + \"/s\",\n          stroke: \"rgba(0,255,0,0.3)\"\n        },\n        {\n          label: this.$t(\"Consume TPS\"),\n          show: true,\n          scale: \"s\",\n          width: 2,\n          value: (u, v) => v == null ? \"-\" : v.toFixed(1) + \"/s\",\n          stroke: \"rgba(255,0,0,0.3)\",\n        },\n        {\n          label: this.$t(\"Subscriber Invoke Time\"),\n          scale: \"ms\",\n          width: 1,\n          paths: u => null,\n          points: {\n            space: 0,\n            stroke: \"blue\"\n          },\n          value: (u, v) => v == null ? \"-\" : v.toFixed(0) + \"ms\",\n          stroke: \"blue\"\n        }\n      ],\n      axes: [\n        {\n          space: 30,\n          values: [\n            [1, \"{mm}:{ss}\", \"\\n{YY}/{M}/{D}/ {HH}:{mm}\", null, \"\\n{M}/{D} {HH}:{mm}\", null, \"\\n{HH}:{mm}\", null, 1],\n          ]\n        },\n        {\n          scale: \"s\",\n          label: this.$t(\"Rate (TPS)\"),\n          //space: 20,\n          ticks: {\n            show: true,\n            stroke: \"#eee\",\n            width: 10,\n            dash: [5],\n            size: 5,\n          },\n          values: (self, ticks) => ticks.map(rawValue => rawValue + \"/s\"),\n          incrs: [\n            1, 5, 10, 30, 50, 100\n          ]\n        }, {\n          side: 1,\n          scale: \"ms\",\n          //space: 20,\n          label: this.$t(\"Elpsed Time (ms)\"),\n          size: 60,\n          ticks: {\n            show: true,\n            stroke: \"#eee\",\n            width: 10,\n            dash: [5],\n            size: 5,\n          },\n          incrs: [\n            1, 10, 50, 100, 300, 500, 1000\n          ],\n          values: (u, vals, space) => vals.map(v => +v.toFixed(0) + \"ms\"),\n          grid: { show: false },\n        }\n      ]\n    };\n\n    var metricInitData = [];\n    async function reamtime() {\n      await axios.get('/metrics-realtime').then(res => {\n        metricInitData = res.data;\n      });\n    }\n    await reamtime();\n    let realtimeUplot = new uPlot(realtimeOpts, metricInitData, document.getElementById(\"realtimeGraph\"));\n\n    this.timer = setInterval(async function () {\n      await reamtime();\n      realtimeUplot.setData(metricInitData);\n    }, 1000);\n\n    // ----------------------------------- History ------------------------------------------------\n    var historyInitData = [];\n\n    await axios.get('/metrics-history').then(res => {\n      historyInitData.push(res.data.dayHour);\n      historyInitData.push(res.data.publishSuccessed);\n      historyInitData.push(res.data.subscribeSuccessed);\n      historyInitData.push(res.data.publishFailed);\n      historyInitData.push(res.data.subscribeFailed);\n    });\n\n    var historyOpts = {\n      width: 960,\n      height: 400,\n      cursor: {\n        drag: {\n          setScale: false,\n        }\n      },\n      select: {\n        show: false,\n      },\n      series: [\n        { value: \"{YYYY}/{MM}/{DD} {HH}:00\" },\n        {\n          label: this.$t(\"Publish Succeeded\"),\n          fill: \"rgba(0,255,0,0.3)\",\n        },\n        {\n          label: this.$t(\"Received Succeeded\"),\n          fill: \"rgba(0,0,255,0.3)\",\n        },\n        {\n          label: this.$t(\"Publish Failed\"),\n          fill: \"rgba(255,0,0,0.5)\",\n        },\n        {\n          label: this.$t(\"Received Failed\"),\n          fill: \"rgba(255,255,0,0.5)\",\n        },\n      ],\n      axes: [\n        {\n          space: 30,\n          values: [\n            [60, \"{HH}:00\", \"\\n{YYYY}/{M}/{D}\", null, \"\\n{M}/{D}\", null, null, null, 1],\n          ],\n        },\n        {\n          label: this.$t(\"Aggregation Count\"),\n        }\n      ]\n    };\n\n    new uPlot(historyOpts, historyInitData, document.getElementById(\"historyGraph\"));\n  },\n  destroyed() {\n    window.clearInterval(this.timer);\n  }\n}; \n</script>\n\n<style>\n@import \"/src/assets/uPlot.min.css\";\n\n.chart {\n  height: 500px;\n  width: 100%;\n}\n</style>"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/src/pages/Nodes.vue",
    "content": "<template>\n  <div>\n    <h2 class=\"text-left mb-4\">{{ $t(\"Nodes\") }}</h2>\n\n    <b-row class=\"mb-3\" v-if=\"nsList.length > 0\">\n      <b-col>\n        <b-form-select v-model=\"selected\" value-field=\"item\" text-field=\"name\" @change=\"fetchSvcs()\" :options=\"nsList\">\n          <template #first>\n            <b-form-select-option :value=\"null\" disabled>{{ $t(\"SelectNamespaces\") }}</b-form-select-option>\n          </template>\n        </b-form-select>\n      </b-col>\n      <b-col cols=\"1\">\n        <b-button variant=\"dark\" :disabled=\"selected == null || pinging\" aria-disabled=\"true\" id=\"latency\"\n          @click=\"pingSvcs()\">\n          <b-icon-speedometer2 v-if=\"!pinging\"></b-icon-speedometer2>\n          <b-icon-arrow-clockwise v-if=\"pinging\" animation=\"spin\"></b-icon-arrow-clockwise>\n        </b-button>\n      </b-col>\n    </b-row>\n\n    <b-table :fields=\"fields\" :items=\"items\" :busy=\"isBusy\" small head-variant=\"light\" show-empty striped hover responsive\n      thead-tr-class=\"text-left\" :empty-text=\"nsList.length == 0 ? $t('NonDiscovery') : $t('EmptyRecords')\">\n\n      <template #table-colgroup=\"scope\">\n        <col v-for=\"field in scope.fields\" :key=\"field.key\" :style=\"{ width: colWidth(field.key) }\">\n      </template>\n\n      <template #table-busy>\n        <div class=\"text-center text-secondary my-2\">\n          <b-spinner class=\"align-middle\"></b-spinner>\n          <strong class=\"ml-2\">{{ $t(\"Loading\") }}...</strong>\n        </div>\n      </template>\n\n      <template #empty=\"scope\">\n        <h5 class=\"alert alert-info\" role=\"alert\">\n          <b-icon-info-circle-fill /> {{ scope.emptyText }}\n        </h5>\n      </template>\n\n      <template #cell(id)=\"data\">\n        <div class=\"texts\">\n          {{ data.item.id }}\n        </div>\n      </template>\n\n      <template #cell(address)=\"data\">\n        {{ data.item.address + (data.item.port == 80 ? \"\" : \":\" + data.item.port) }}\n      </template>\n\n      <template #cell(tags)=\"data\">\n        <b-badge variant=\"info\">{{ data.item.tags.split(',')[0] }}</b-badge>\n        <b-link @click=\"data.toggleDetails\" v-if=\"data.item.tags != ''\">\n          <div class=\"ml-2\" style=\"font-size:12px;color:gray\">Show {{ data.detailsShowing ? 'Less' : 'More' }} </div>\n        </b-link>\n      </template>\n\n      <template #row-details=\"data\">\n        <b-badge class=\"mb-1 ml-2\" v-for=\"tag in data.item.tags.split(',')\" :key=\"tag\">{{ tag }}</b-badge>\n      </template>\n\n      <template #cell(latency)=\"data\">\n        <div v-if=\"data.item.latency == null\"></div>\n        <b-badge v-else-if=\"(typeof data.item.latency === 'number')\" variant=\"success\">\n          {{ data.item.latency + \" ms\" }}\n        </b-badge>\n        <b-badge pill href=\"#\" v-else v-b-popover.hover.left=\"data.item.latency\" variant=\"danger\" size=\"sm\"\n          title=\"Request failed\">\n          Error\n        </b-badge>\n      </template>\n\n      <template #cell(actions)=\"data\">\n        <b-button size=\"sm\" variant=\"dark\" @click=\"switchNode(data.item);\">\n          <b-spinner small variant=\"secondary\" v-if=\"data.item._ping\" type=\"grow\" label=\"Spinning\"></b-spinner>\n          {{ $t(\"Switch\") }}\n        </b-button>\n      </template>\n    </b-table>\n  </div>\n</template>\n<script>\nimport axios from 'axios';\nimport { BIconInfoCircleFill, BIconSpeedometer2, BIconArrowClockwise, BIconSearch } from 'bootstrap-vue';\n\nvar cancelToken = axios.CancelToken.source();\n\nexport default {\n  components: {\n    BIconInfoCircleFill,\n    BIconSpeedometer2,\n    BIconArrowClockwise,\n    BIconSearch\n  },\n  data() {\n    return {\n      pinging: false,\n      selected: null,\n      nsList: [],\n      isBusy: false,\n      items: []\n    }\n  },\n  computed: {\n    fields() {\n      return [\n        { key: \"id\", label: this.$t(\"Id\") },\n        { key: \"name\", label: this.$t(\"Node Name\"), tdClass: \"text-left\" },\n        { key: \"address\", label: this.$t(\"Ip Address\"), tdClass: \"text-left\" },\n        { key: \"tags\", label: this.$t(\"Tags\"), tdClass: \"text-left\" },\n        { key: \"latency\", label: this.$t(\"Latency\"), thClass: \"text-center\", tdClass: \"text-success\" },\n        { key: \"actions\", label: this.$t(\"Actions\"), thClass: \"text-center\" },\n      ];\n    }\n  },\n  mounted() {\n    this.fetchNsOptions();\n    this.fetchData();\n  },\n  methods: {\n    colWidth(key) {\n      switch (key) {\n        case \"address\":\n          return \"320px\";\n        case \"actions\":\n          return \"80px\";\n        case \"latency\":\n          return \"60px\";\n        default:\n          return \"\";\n      }\n    },\n    fetchNsOptions() {\n      this.isBusy = true;\n      axios.get('/list-ns').then(res => {\n        if (res.data.length > 0) {\n          this.nsList = res.data;\n        }\n      });\n      this.isBusy = false;\n      var ns = this.getCookie(\"cap.node.ns\");\n      if (ns) {\n        this.selected = ns;\n        this.fetchSvcs();\n      }\n    },\n\n    fetchSvcs() {\n      if (!this.selected) return;\n\n      this.isBusy = true;\n      var name = this.getCookie('cap.node');\n      if (this.pinging == true) {\n        cancelToken.cancel();\n        cancelToken = axios.CancelToken.source();\n      }\n      axios.get('/list-svc/' + this.selected).then(res => {\n        for (var item of res.data) {\n          if (item.name == name) {\n            item._rowVariant = 'dark'\n          }\n          item._ping = false; //add new property\n        }\n        this.items = res.data;\n        this.isBusy = false;\n      });\n\n    },\n\n    async pingSvcs() {\n      this.pinging = true;\n      for (var item of this.items) {\n        try {\n          var res = await axios.get('/ping', {\n            params: {\n              endpoint: item.address + \":\" + item.port\n            },\n            timeout: 3000,\n            cancelToken: cancelToken.token\n          });\n          item.latency = res.data;\n        } catch (err) {\n          if (axios.isCancel(err)) break;\n          item.latency = err.response?.data;\n        }\n      }\n      this.pinging = false;\n    },\n\n    fetchData() {\n      this.isBusy = true;\n      var name = this.getCookie('cap.node');\n      axios.get('/nodes').then(res => {\n        for (var item of res.data) {\n          if (item.name == name) {\n            item._rowVariant = 'dark'\n          }\n        }\n        this.items = res.data;\n        this.isBusy = false;\n      });\n    },\n\n    switchNode(item) {\n      item._ping = true;\n      axios.get('/ping', {\n        params: {\n          endpoint: item.address + \":\" + item.port\n        },\n        timeout: 3000\n      }).then(res => {\n        item.latency = res.data;\n        document.cookie = `cap.node=${escape(item.name)};`;\n        document.cookie = `cap.node.ns=${this.selected};`;\n        item._ping = false;\n        location.reload();\n      }).catch(err => {\n        if (axios.isAxiosError(err)) {\n          item.latency = err.response?.data;\n          this.$bvToast.toast(\"Switch to [\" + item.name + \"] failed! Endpoint: \" + item.address, {\n            title: \"Warning\",\n            variant: \"danger\",\n            autoHideDelay: 2000,\n            appendToast: true,\n            solid: true\n          });\n        }\n        item._ping = false;\n      });\n    },\n\n    getCookie(cname) {\n      var name = cname + \"=\";\n      var decodedCookie = decodeURIComponent(document.cookie);\n      var ca = decodedCookie.split(';');\n      for (var i = 0; i < ca.length; i++) {\n        var c = ca[i];\n        while (c.charAt(0) == ' ') {\n          c = c.substring(1);\n        }\n        if (c.indexOf(name) == 0) {\n          return c.substring(name.length, c.length);\n        }\n      }\n      return \"\";\n    }\n  }\n\n};\n</script>\n<style >\n.table-dark td {\n  border-color: #c6c8ca;\n}\n\n.texts {\n  width: 70px;\n  overflow: hidden;\n  white-space: nowrap;\n  text-overflow: ellipsis;\n}\n</style>"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/src/pages/Published.vue",
    "content": "<template>\n  <div>\n    <b-row>\n      <b-col md=\"3\">\n\n        <b-list-group>\n          <b-tooltip target=\"tooltip\" triggers=\"hover\" variant=\"warning\" custom-class=\"my-tooltip-class\"\n            placement=\"bottomright\">\n            {{ $t(\"DelayedInfo\") }}\n          </b-tooltip>\n          <router-link class=\"list-group-item text-left list-group-item-secondary list-group-item-action\"\n            v-for=\"(menu, index) of subMens\" :key=\"menu.text\" active-class=\"active\" :to=\"menu.name\">\n            {{ $t(menu.text) }}\n            <b-icon-info-circle-fill id=\"tooltip\" v-if=\"index == subMens.length - 1\">\n            </b-icon-info-circle-fill>\n            <b-badge :variant=\"menu.variant\" class=\"float-right\" pill> {{ onMetric[menu.num] }} </b-badge>\n          </router-link>\n        </b-list-group>\n      </b-col>\n\n      <b-col md=\"9\">\n        <h2 class=\"page-line mb-2\">{{ $t(\"Published Message\") }}</h2>\n\n        <b-form class=\"d-flex\">\n          <div class=\"col-sm-10\">\n            <div class=\"form-row mb-2\">\n              <label for=\"form-input-name\" class=\"sr-only\">{{ $t(\"Name\") }}</label>\n              <b-form-input v-model=\"formData.name\" id=\"form-input-name\" class=\"form-control\" :placeholder=\"$t('Name')\" />\n            </div>\n            <div class=\"form-row\">\n              <label class=\"sr-only\" for=\"inline-form-input-content\">{{ $t(\"Content\") }}</label>\n              <b-form-input v-model=\"formData.content\" id=\"inline-form-input-content\" class=\"form-control\"\n                :placeholder=\"$t('Content')\" />\n            </div>\n          </div>\n          <b-button variant=\"dark\" class=\"ml-2 align-self-end\" @click=\"onSearch\">\n            <b-icon-search></b-icon-search>\n            {{ $t(\"Search\") }}\n          </b-button>\n        </b-form>\n      </b-col>\n    </b-row>\n\n    <b-row>\n      <b-col md=\"12\">\n        <b-btn-toolbar class=\"mt-4\">\n          <b-button size=\"sm\" variant=\"dark\" @click=\"requeue\" :disabled=\"!selectedItems.length\" class=\"action-button\">\n            <b-icon-arrow-repeat aria-hidden=\"true\"></b-icon-arrow-repeat>\n            {{ requeueTitle }}\n          </b-button>\n          <b-button size=\"sm\" variant=\"danger\" @click=\"deletemsg\" :disabled=\"!selectedItems.length\" class=\"action-button\">\n            <b-icon-trash aria-hidden=\"true\"></b-icon-trash>\n            {{ $t(\"Delete\") }}\n          </b-button>\n          <div class=\"pagination\">\n            <span style=\"font-size: 14px\">{{ $t(\"Page Size\") }}:</span>\n            <b-button-group class=\"ml-2\">\n              <b-button variant=\"outline-secondary\" size=\"sm\" v-for=\"size in pageOptions\"\n                :class=\"{ active: formData.perPage == size }\" @click=\"pageSizeChange(size)\" :key=\"size\">{{ size }}\n              </b-button>\n            </b-button-group>\n          </div>\n        </b-btn-toolbar>\n        <b-table id=\"datatable\" :busy=\"isBusy\" class=\"mt-3\" striped thead-tr-class=\"text-left \" head-variant=\"light\"\n          details-td-class=\"align-middle\" tbody-tr-class=\"text-left\" small :fields=\"fields\" :items=\"items\"\n          select-mode=\"range\">\n          <template #table-busy>\n            <div class=\"text-center text-secondary my-2\">\n              <b-spinner class=\"align-middle\"></b-spinner>\n              <strong class=\"ml-2\">{{ $t(\"Loading\") }}...</strong>\n            </div>\n          </template>\n\n          <template #head(checkbox)=\"\">\n            <b-form-checkbox @change=\"selectAll\" v-model=\"isSelectedAll\"></b-form-checkbox>\n          </template>\n\n          <template #cell(checkbox)=\"data\">\n            <b-form-checkbox v-model=\"data.item.selected\" @change=\"select(data.item)\">\n            </b-form-checkbox>\n          </template>\n\n          <template #cell(id)=\"data\">\n            <b-link @click=\"info(data.item, $event.target)\">\n              {{ data.item.id }}\n            </b-link>\n            <br />\n            {{ data.item.name }}\n          </template>\n\n        </b-table>\n        <span class=\"float-left\"> {{ $t(\"Total\") }}: {{ totals }} </span>\n        <b-pagination :first-text=\"$t('First')\" :prev-text=\"$t('Prev')\" :next-text=\"$t('Next')\" :last-text=\"$t('Last')\"\n          v-model=\"formData.currentPage\" :total-rows=\"totals\" :per-page=\"formData.perPage\" class=\"capPagination\"\n          aria-controls=\"datatable\"></b-pagination>\n      </b-col>\n    </b-row>\n    <b-modal size=\"lg\" :id=\"infoModal.id\" :title=\"'Id: ' + infoModal.title\" ok-only ok-variant=\"secondary\">\n      <vue-json-pretty showSelectController :key=\"infoModal.id\" :data=\"infoModal.content\" />\n    </b-modal>\n  </div>\n</template>\n<script>\nimport axios from \"axios\";\nimport JSONBIG from \"json-bigint\";\nimport {\n  BIconInfoCircleFill,\n  BIconArrowRepeat,\n  BIconSearch, BIconTrash\n} from 'bootstrap-vue';\n\nconst formDataTpl = {\n  currentPage: 1,\n  perPage: 10,\n  name: \"\",\n  content: \"\",\n};\nexport default {\n  components: {\n    BIconTrash,\n    BIconInfoCircleFill,\n    BIconArrowRepeat,\n    BIconSearch\n  },\n  props: {\n    status: {}\n  },\n  data() {\n    return {\n      subMens: [\n        {\n          variant: \"secondary\",\n          text: \"Succeeded\",\n          num: 'publishedSucceeded',\n          name: \"/published/succeeded\",\n        },\n        {\n          variant: \"danger\",\n          text: \"Failed\",\n          name: \"/published/failed\",\n          num: 'publishedFailed',\n        },\n\n        {\n          variant: \"warning\",\n          text: \"Delayed\",\n          name: \"/published/delayed\",\n          num: 'publishedDelayed',\n        },\n      ],\n      pageOptions: [10, 20, 50, 100, 500],\n      selectedItems: [],\n      isBusy: false,\n      tableValues: [],\n      isSelectedAll: false,\n      formData: { ...formDataTpl },\n      totals: 0,\n      items: [],\n      infoModal: {\n        id: \"info-modal\",\n        title: \"\",\n        content: \"{}\",\n      },\n      expiresTitle: this.$t(\"Expires\"),\n      requeueTitle: this.$t(\"Requeue\")\n    };\n  },\n  computed: {\n    onMetric() {\n      return this.$store.getters.getMetric;\n    },\n    fields() {\n      return [{ key: \"checkbox\", label: \"\" },\n      { key: \"id\", label: this.$t(\"IdName\") },\n      { key: \"retries\", label: this.$t(\"Retries\") },\n      {\n        key: \"added\",\n        label: this.$t(\"Added\"),\n        formatter: (val) => {\n          if (val != null) return new Date(val).format(\"yyyy-MM-dd hh:mm:ss\");\n        },\n      },\n      {\n        key: \"expiresAt\",\n        label: this.expiresTitle,\n        formatter: (val) => {\n          if (val != null) return new Date(val).format(\"yyyy-MM-dd hh:mm:ss\");\n        },\n      }];\n    }\n  },\n  mounted() {\n    this.fetchData();\n    window.abc = this;\n  },\n  watch: {\n    status: function () {\n      this.fetchData();\n    },\n    \"formData.currentPage\": function () {\n      this.fetchData();\n    },\n  },\n  methods: {\n    fetchData() {\n      this.isBusy = true;\n      axios.get(`/published/${this.status}`, {\n        params: this.formData\n      }).then(res => {\n        this.items = res.data.items;\n        this.totals = res.data.totals;\n        if (this.status == \"delayed\") {\n          this.expiresTitle = this.$t(\"DelayedPublishTime\");\n          this.requeueTitle = this.$t(\"PublishNow\")\n        } else {\n          this.expiresTitle = this.$t(\"Expires\");\n          this.requeueTitle = this.$t(\"Requeue\")\n        }\n      }).finally(() => {\n        this.isBusy = false;\n      });\n    },\n    selectAll(checked) {\n      if (checked) {\n        this.selectedItems = [\n          ...this.items.map((item) => {\n            return {\n              ...item,\n              selected: true,\n            };\n          }),\n        ];\n        this.items = [...this.selectedItems];\n      } else {\n        this.selectedItems = [];\n        this.items = this.items.map((item) => {\n          return {\n            ...item,\n            selected: false,\n          };\n        });\n      }\n    },\n    select(item) {\n      const { id } = item;\n      if (!this.selectedItems.some((item) => item.id == id)) {\n        this.selectedItems.push(item);\n      } else {\n        this.selectedItems = this.selectedItems.filter((item) => item.id != id);\n      }\n      this.isSelectedAll = this.selectedItems.length == this.items.length;\n    },\n    clearSelected() {\n      this.allSelected = false;\n      this.selectedItems = [];\n    },\n    info(item, button) {\n      this.infoModal.title = item.id.toString();\n      this.infoModal.content = JSONBIG({ storeAsString: true }).parse(item.content.trim());\n      this.$root.$emit(\"bv::show::modal\", this.infoModal.id, button);\n    },\n    pageSizeChange: function (size) {\n      this.formData.perPage = size;\n      this.fetchData();\n    },\n    onSearch: function () {\n      this.fetchData();\n    },\n    requeue: function () {\n      const _this = this;\n      axios.post('/published/requeue', this.selectedItems.map((item) => item.id)).then(() => {\n        this.selectedItems.map((item) => {\n          _this.$bvToast.toast(this.$t(\"RequeueSuccess\") + \"   \" + item.id, {\n            title: \"Tips\",\n            variant: \"secondary\",\n            autoHideDelay: 1000,\n            appendToast: true,\n            solid: true\n          });\n        });\n        _this.clear();\n      });\n    },\n    deletemsg: function () {\n      const _this = this;\n      axios.post('/published/delete', this.selectedItems.map((item) => item.id)).then(() => {\n        this.selectedItems.map((item) => {\n          _this.$bvToast.toast(this.$t(\"DeleteSuccess\") + \"   \" + item.id, {\n            title: \"Tips\",\n            variant: \"secondary\",\n            autoHideDelay: 1000,\n            appendToast: true,\n            solid: true\n          });\n        });\n        _this.fetchData();\n        _this.clear();\n      });\n    },\n    clear() {\n      this.items = this.items.map((item) => {\n        return {\n          ...item,\n          selected: false,\n        };\n      });\n      this.selectedItems = [];\n      this.isSelectedAll = false;\n    },\n  },\n};\n</script>\n\n<style scoped>\n.pagination {\n  flex: 1;\n  justify-content: flex-end;\n  align-items: center;\n}\n\n.capPagination::v-deep .page-link {\n  color: #6c757d;\n  box-shadow: none;\n  border-color: #6c757d;\n}\n\n.capPagination::v-deep .page-link:hover {\n  color: #fff;\n  background-color: #6c757d;\n  border-color: #6c757d;\n}\n\n.capPagination::v-deep .active .page-link {\n  color: white;\n  background-color: black;\n}\n\n.my-align-middle {\n  vertical-align: middle;\n}\n\n.action-button {\n  margin-right: 1rem;\n}\n</style>"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/src/pages/Received.vue",
    "content": "<template>\n  <div>\n    <b-row>\n      <b-col md=\"3\" class=\"mt-4\">\n        <b-list-group>\n          <router-link class=\"list-group-item text-left list-group-item-secondary list-group-item-action\"\n            v-for=\"menu of subMens\" :key=\"menu.text\" active-class=\"active\" :to=\"menu.name\">\n            {{ $t(menu.text) }}\n            <b-badge :variant=\"menu.variant\" class=\"float-right\" pill> {{ onMetric[menu.num] }} </b-badge>\n          </router-link>\n        </b-list-group>\n      </b-col>\n      <b-col md=\"9\">\n        <h2 class=\"page-line mb-2\">{{ $t(\"Received Message\") }}</h2>\n        <b-form class=\"d-flex\">\n          <div class=\"col-sm-10\">\n            <div class=\"form-row mb-2\">\n              <label class=\"sr-only\" for=\"inline-form-input-name\">{{ $t(\"Name\") }}</label>\n              <b-form-input v-model=\"formData.name\" id=\"inline-form-input-name\" class=\"form-control col mr-4\"\n                :placeholder=\"$t('Name')\" />\n\n              <label class=\"sr-only\" for=\"inline-form-input-name\">{{ $t(\"Group\") }}</label>\n              <b-form-input v-model=\"formData.group\" id=\"inline-form-input-group\" class=\"form-control col\"\n                :placeholder=\"$t('Group')\" />\n            </div>\n            <div class=\"form-row\">\n              <label class=\"sr-only\" for=\"inline-form-input-content\">{{ $t(\"Content\") }}</label>\n              <b-form-input v-model=\"formData.content\" id=\"inline-form-input-content\" class=\"form-control\"\n                :placeholder=\"$t('Content')\" />\n            </div>\n          </div>\n          <b-button variant=\"dark\" class=\"ml-2 align-self-end\" @click=\"onSearch\">\n            <b-icon-search></b-icon-search>\n            {{ $t(\"Search\") }}\n          </b-button>\n        </b-form>\n      </b-col>\n    </b-row>\n    <b-row>\n      <b-col md=\"12\">\n        <b-btn-toolbar class=\"mt-4\">\n          <b-button size=\"sm\" variant=\"dark\" @click=\"reexecute\" :disabled=\"!selectedItems.length\" class=\"action-button\">\n            <b-icon-arrow-repeat aria-hidden=\"true\"></b-icon-arrow-repeat>\n            {{ $t(\"Re-execute\") }}\n          </b-button>\n          <b-button size=\"sm\" variant=\"danger\" @click=\"deletemsg\" :disabled=\"!selectedItems.length\" class=\"action-button\">\n            <b-icon-trash aria-hidden=\"true\"></b-icon-trash>\n            {{ $t(\"Delete\") }}\n          </b-button>\n          <div class=\"pagination\">\n            <span style=\"font-size: 14px\"> {{ $t(\"Page Size\") }}:</span>\n            <b-button-group class=\"ml-2\">\n              <b-button variant=\"outline-secondary\" size=\"sm\" v-for=\"size in pageOptions\"\n                :class=\"{ active: formData.perPage == size }\" @click=\"pageSizeChange(size)\" :key=\"size\">{{ size }}\n              </b-button>\n            </b-button-group>\n          </div>\n        </b-btn-toolbar>\n        <b-table id=\"datatable\" class=\"mt-3\" :busy=\"isBusy\" striped thead-tr-class=\"text-left\" head-variant=\"light\"\n          tbody-tr-class=\"text-left\" small :fields=\"fields\" :items=\"items\" select-mode=\"range\">\n          <template #table-busy>\n            <div class=\"text-center text-secondary my-2\">\n              <b-spinner class=\"align-middle\"></b-spinner>\n              <strong class=\"ml-2\">{{ $t(\"Loading\") }}...</strong>\n            </div>\n          </template>\n\n          <template #head(checkbox)=\"\">\n            <b-form-checkbox @change=\"selectAll\" v-model=\"isSelectedAll\"></b-form-checkbox>\n          </template>\n\n          <template #cell(checkbox)=\"data\">\n            <b-form-checkbox v-model=\"data.item.selected\" @change=\"select(data.item)\">\n            </b-form-checkbox>\n          </template>\n\n          <template #cell(id)=\"data\">\n            <b-link @click=\"info(data.item, $event.target)\">\n              {{ data.item.id }}\n            </b-link><br />\n            {{ data.item.name }}\n          </template>\n\n          <template #cell(group)=\"data\">\n            <span class=\"text-break\"> {{ data.item.group }}</span>\n          </template>\n\n        </b-table>\n        <span class=\"float-left\"> {{ $t(\"Total\") }}: {{ totals }} </span>\n        <b-pagination :first-text=\"$t('First')\" :prev-text=\"$t('Prev')\" :next-text=\"$t('Next')\" :last-text=\"$t('Last')\"\n          v-model=\"formData.currentPage\" :total-rows=\"totals\" :per-page=\"formData.perPage\" class=\"capPagination\"\n          aria-controls=\"datatable\"></b-pagination>\n      </b-col>\n    </b-row>\n    <b-modal size=\"lg\" :id=\"infoModal.id\" :title=\"'Id: ' + infoModal.title\" ok-only ok-variant=\"secondary\">\n      <vue-json-pretty showSelectController :key=\"infoModal.id\" :data=\"infoModal.content\" />\n    </b-modal>\n  </div>\n</template>\n<script>\nimport axios from \"axios\";\nimport JSONBIG from \"json-bigint\";\nimport {\n  BIconArrowRepeat,\n  BIconSearch,\n    BIconTrash,\n} from 'bootstrap-vue';\n\nconst formDataTpl = {\n  currentPage: 1,\n  perPage: 10,\n  name: \"\",\n  group: \"\",\n  content: \"\",\n};\nexport default {\n  components: {\n    BIconArrowRepeat,\n    BIconSearch,\n    BIconTrash\n  },\n  props: {\n    status: {},\n  },\n  data() {\n    return {\n      subMens: [\n        {\n          variant: \"secondary\",\n          text: \"Succeeded\",\n          num: 'receivedSucceeded',\n          name: \"/received/succeeded\",\n        },\n        {\n          variant: \"danger\",\n          text: \"Failed\",\n          name: \"/received/failed\",\n          num: 'receivedFailed',\n        },\n      ],\n      pageOptions: [10, 20, 50, 100, 500],\n      selectedItems: [],\n      isBusy: false,\n      tableValues: [],\n      isSelectedAll: false,\n      formData: { ...formDataTpl },\n      totals: 0,\n      items: [],\n      infoModal: {\n        id: \"info-modal\",\n        title: \"\",\n        content: \"{}\",\n      },\n    };\n  },\n  computed: {\n    onMetric() {\n      return this.$store.getters.getMetric;\n    },\n    fields() {\n      return [\n        { key: \"checkbox\", label: \"\" },\n        { key: \"id\", label: this.$t(\"IdName\") },\n        { key: \"group\", label: this.$t(\"Group\") },\n        { key: \"retries\", label: this.$t(\"Retries\") },\n        {\n          key: \"added\",\n          label: this.$t(\"Added\"),\n          formatter: (val) => {\n            if (val != null) return new Date(val).format(\"yyyy-MM-dd hh:mm:ss\");\n          },\n        },\n        {\n          key: \"expiresAt\",\n          label: this.$t(\"Expires\"),\n          formatter: (val) => {\n            if (val != null) return new Date(val).format(\"yyyy-MM-dd hh:mm:ss\");\n          },\n        },\n      ]\n    }\n  },\n  mounted() {\n    this.fetchData();\n  },\n  watch: {\n    status: function () {\n      this.fetchData();\n    },\n    \"formData.currentPage\": function () {\n      this.fetchData();\n    },\n  },\n  methods: {\n    fetchData() {\n      this.isBusy = true;\n      axios.get(`/received/${this.status}`, {\n        params: this.formData\n      }).then(res => {\n        this.items = res.data.items;\n        this.totals = res.data.totals;\n      }).finally(() => {\n        this.isBusy = false;\n      });\n    },\n    selectAll(checked) {\n      if (checked) {\n        this.selectedItems = [\n          ...this.items.map((item) => {\n            return {\n              ...item,\n              selected: true,\n            };\n          }),\n        ];\n        this.items = [...this.selectedItems];\n      } else {\n        this.selectedItems = [];\n        this.items = this.items.map((item) => {\n          return {\n            ...item,\n            selected: false,\n          };\n        });\n      }\n    },\n    select(item) {\n      const { id } = item;\n      if (!this.selectedItems.some((item) => item.id == id)) {\n        this.selectedItems.push(item);\n      } else {\n        this.selectedItems = this.selectedItems.filter((item) => item.id != id);\n      }\n      this.isSelectedAll = this.selectedItems.length == this.items.length;\n    },\n    clearSelected() {\n      this.allSelected = false;\n      this.selectedItems = [];\n    },\n    info(item, button) {\n      this.infoModal.title = item.id.toString();\n      this.infoModal.content = JSONBIG({ storeAsString: true }).parse(item.content.trim());\n      this.$root.$emit(\"bv::show::modal\", this.infoModal.id, button);\n    },\n    pageSizeChange: function (size) {\n      this.formData.perPage = size;\n      this.fetchData();\n    },\n    onSearch: function () {\n      this.fetchData();\n    },\n    reexecute: function () {\n      const _this = this;\n      axios.post('/received/reexecute', this.selectedItems.map((item) => item.id)).then(() => {\n        this.selectedItems.map((item) => {\n          _this.$bvToast.toast(this.$t(\"ReexecuteSuccess\") + \"   \" + item.id, {\n            title: \"Tips\",\n            variant: \"secondary\",\n            autoHideDelay: 1000,\n            appendToast: true,\n            solid: true\n          });\n        });\n        _this.fetchData();\n        _this.clear();\n      });\n    },\n    deletemsg: function () {\n      const _this = this;\n      axios.post('/received/delete', this.selectedItems.map((item) => item.id)).then(() => {\n        this.selectedItems.map((item) => {\n          _this.$bvToast.toast(this.$t(\"DeleteSuccess\") + \"   \" + item.id, {\n            title: \"Tips\",\n            variant: \"secondary\",\n            autoHideDelay: 1000,\n            appendToast: true,\n            solid: true\n          });\n        });\n        _this.fetchData();\n        _this.clear();\n      });\n    },\n    clear() {\n      this.items = this.items.map((item) => {\n        return {\n          ...item,\n          selected: false,\n        };\n      });\n      this.selectedItems = [];\n      this.isSelectedAll = false;\n    },\n  },\n};\n</script>\n\n<style scoped>\n.pagination {\n  flex: 1;\n  justify-content: flex-end;\n  align-items: center;\n}\n\n.capPagination::v-deep .page-link {\n  color: #6c757d;\n  box-shadow: none;\n  border-color: #6c757d;\n}\n\n.capPagination::v-deep .page-link:hover {\n  color: #fff;\n  background-color: #6c757d;\n  border-color: #6c757d;\n}\n\n.capPagination::v-deep .active .page-link {\n  color: white;\n  background-color: black;\n}\n\n.action-button {\n  margin-right: 1rem;\n}\n</style>"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/src/pages/Subscriber.vue",
    "content": "<template>\n  <b-row>\n    <h2 page-line mb-4>{{ $t(\"Subscriber\") }}</h2>\n\n    <b-table-simple caption-top bordered small responsive>\n      <caption>{{ $t(\"SubscriberDescription\") }}</caption>\n\n      <b-thead head-variant=\"light\">\n        <b-tr>\n          <b-th width=\"30%\" class=\"text-left\">{{ $t(\"Group\") }}</b-th>\n          <b-th class=\"text-left\">{{ $t(\"Name\") }}</b-th>\n          <b-th class=\"text-left\">{{ $t(\"Method\") }}</b-th>\n        </b-tr>\n      </b-thead>\n      <b-tbody>\n        <template v-for=\"subscriber in subscribers\">\n          <b-tr :key=\"subscriber.group + index\" v-for=\"(column, index) in subscriber.values\">\n            <b-td class=\"text-left align-middle\" v-if=\"index == 0\" :rowspan=\"subscriber.childCount\">\n              {{ subscriber.group }}\n            </b-td>\n            <b-td class=\"text-left align-middle\">\n              {{ column.topic }}\n            </b-td>\n            <b-td>\n              <div class=\"snippet-code text-left align-middle\">\n                <code>\n                   <pre><span class=\"type\">{{ column.implName }}</span>:<br><span v-html=\"column.methodEscaped\">{{ column.methodEscaped }}</span></pre>\n                 </code>\n              </div>\n            </b-td>\n          </b-tr>\n        </template>\n      </b-tbody>\n    </b-table-simple>\n  </b-row>\n</template>\n<script>\nimport axios from 'axios';\n\nexport default {\n  data() {\n    return {\n      subscribers: {}\n    }\n  },\n  mounted() {\n    axios.get('/subscriber').then(response => {\n      this.subscribers = response.data;\n    });\n  }\n}\n</script>\n<style>\n.snippet-code pre {\n  margin: 0;\n}\n\n.snippet-code pre .comment {\n  color: rgb(0, 128, 0);\n}\n\n.snippet-code pre .keyword {\n  color: rgb(0, 0, 255);\n}\n\n.snippet-code pre .string {\n  color: rgb(163, 21, 21);\n}\n\n.snippet-code pre .type {\n  color: rgb(43, 145, 175);\n}\n</style>"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/src/router/index.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\nimport Home from '../pages/Home.vue'\n\nVue.use(VueRouter)\n\n\nconst routes = [\n    {\n        path: '/',\n        name: 'Home',\n        component: Home\n    },\n    {\n        path: '/published/:status',\n        name: 'Published',\n        props: true,\n        component: () => import('../pages/Published.vue')\n    },\n    {\n        path: '/published',\n        redirect: '/published/succeeded'\n    },\n    {\n        path: '/received/:status',\n        name: 'Received',\n        props: true,\n        component: () => import('../pages/Received.vue')\n    },\n    {\n        path: '/received',\n        redirect: '/received/succeeded'\n    },\n    {\n        path: '/subscriber',\n        name: 'Subscriber',\n        component: () => import('../pages/Subscriber.vue')\n    },\n    {\n        path: '/nodes',\n        name: 'Nodes',\n        component: () => import('../pages/Nodes.vue')\n    }\n]\n\nconst router = new VueRouter({\n    routes\n})\n\nexport default router;"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/src/store/store.js",
    "content": "import Vue from 'vue';\nimport Vuex from 'vuex';\n\nVue.use(Vuex);\n\nlet store = new Vuex.Store({\n    state: {\n        metric: {},\n        info: {}\n    },\n\n    getters: {\n        getMetric(state) {\n            return state.metric;\n        }\n    },\n    mutations: {\n        setMertic(state, val) {\n            state.metric = val;\n        },\n        setInfo(state, val) {\n            state.info = val;\n        }\n    },\n    actions: {\n        pollingMertic({ commit }, val) {\n            commit(\"setMertic\", val);\n        },\n        pollingInfo({ commit }, val) {\n            commit(\"setInfo\", val);\n        }\n    },\n});\n\nexport default store;"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard/wwwroot/vite.config.js",
    "content": "import { fileURLToPath, URL } from \"node:url\";\n\nimport { defineConfig } from \"vite\";\nimport vue2 from \"@vitejs/plugin-vue2\";\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  base: './',\n  plugins: [\n    vue2()\n  ],\n  resolve: {\n    alias: {\n      \"@\": fileURLToPath(new URL(\"./src\", import.meta.url)),\n    },\n  },\n  server: {\n    proxy: {\n      '^/cap/api': {\n        target: 'http://localhost:5000',\n        changeOrigin: true\n      }\n    }\n  }\n});\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard.K8s/DotNetCore.CAP.Dashboard.K8s.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\t<PropertyGroup>\n\t\t<TargetFramework>net8.0</TargetFramework>\n\t\t<ImplicitUsings>enable</ImplicitUsings>\n\t\t<Nullable>enable</Nullable>\n\t</PropertyGroup>\n\t<ItemGroup>\n\t\t<PackageReference Include=\"KubernetesClient\" Version=\"18.0.5\" />\n\t</ItemGroup>\n\t<ItemGroup>\n\t  <ProjectReference Include=\"..\\DotNetCore.CAP.Dashboard\\DotNetCore.CAP.Dashboard.csproj\" />\n\t</ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard.K8s/K8sDiscoveryOptions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing k8s;\n\nnamespace DotNetCore.CAP.Dashboard.K8s;\n\n// ReSharper disable once InconsistentNaming\n/// <summary>\n/// Represents all the option you can use to configure the k8s discovery.\n/// </summary>\npublic class K8sDiscoveryOptions\n{\n    public K8sDiscoveryOptions()\n    {\n        K8SClientConfig = KubernetesClientConfiguration.BuildDefaultConfig();\n        ShowOnlyExplicitVisibleNodes = true;\n    }\n\n    public KubernetesClientConfiguration K8SClientConfig { get; set; }\n\n    /// <summary>\n    /// If this is set to TRUE will make all nodes hidden by default. Only kubernetes services \n    /// with label \"dotnetcore.cap.visibility:show\" will be listed in the nodes section.\n    /// </summary>\n    public bool ShowOnlyExplicitVisibleNodes { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard.K8s/K8sDiscoveryOptionsExtensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing DotNetCore.CAP;\nusing DotNetCore.CAP.Dashboard.GatewayProxy;\nusing DotNetCore.CAP.Dashboard.GatewayProxy.Requester;\nusing DotNetCore.CAP.Dashboard.K8s;\nusing DotNetCore.CAP.Dashboard.NodeDiscovery;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace DotNetCore.CAP.Dashboard.K8s\n{\n    // ReSharper disable once InconsistentNaming\n    internal sealed class K8sDiscoveryOptionsExtension : ICapOptionsExtension\n    {\n        private readonly Action<K8sDiscoveryOptions>? _options;\n\n        public K8sDiscoveryOptionsExtension(Action<K8sDiscoveryOptions>? option)\n        {\n            _options = option;\n        }\n\n        public void AddServices(IServiceCollection services)\n        {\n            var k8sOptions = new K8sDiscoveryOptions();\n\n            _options?.Invoke(k8sOptions);\n            services.AddSingleton(k8sOptions);\n\n            services.AddSingleton<IHttpRequester, HttpClientHttpRequester>();\n            services.AddSingleton<IHttpClientCache, MemoryHttpClientCache>();\n            services.AddSingleton<IRequestMapper, RequestMapper>();\n            services.AddSingleton<GatewayProxyAgent>();\n            services.AddSingleton<INodeDiscoveryProvider, K8sNodeDiscoveryProvider>();\n        }\n    }\n}\n\nnamespace Microsoft.Extensions.DependencyInjection\n{\n    public static class CapDiscoveryOptionsExtensions\n    {\n        // ReSharper disable once InconsistentNaming\n        /// <summary>\n        /// Use K8s as a service discovery to view data from other nodes in the Dashboard.\n        /// </summary>\n        /// <param name=\"capOptions\"></param>\n        public static CapOptions UseK8sDiscovery(this CapOptions capOptions)\n        {\n            return capOptions.UseK8sDiscovery(opt => { });\n        }\n\n        // ReSharper disable once InconsistentNaming\n        /// <summary>\n        /// Use K8s as a service discovery to view data from other nodes in the Dashboard.\n        /// </summary>\n        /// <param name=\"capOptions\"></param>\n        /// <param name=\"options\">The option of <see cref=\"K8sDiscoveryOptions\" /></param>\n        /// <exception cref=\"ArgumentNullException\"></exception>\n        public static CapOptions UseK8sDiscovery(this CapOptions capOptions, Action<K8sDiscoveryOptions> options)\n        {\n            if (options == null) throw new ArgumentNullException(nameof(options));\n\n            capOptions.RegisterExtension(new K8sDiscoveryOptionsExtension(options));\n\n            return capOptions;\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard.K8s/K8sNodeDiscoveryProvider.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing DotNetCore.CAP.Dashboard.NodeDiscovery;\nusing k8s;\nusing k8s.Models;\nusing Microsoft.Extensions.Logging;\n\nnamespace DotNetCore.CAP.Dashboard.K8s;\n\n// ReSharper disable once InconsistentNaming\npublic class K8sNodeDiscoveryProvider : INodeDiscoveryProvider\n{\n    const string TagPrefix = \"dotnetcore.cap\";\n    private readonly ILogger<ConsulNodeDiscoveryProvider> _logger;\n    private readonly K8sDiscoveryOptions _options;\n\n    public K8sNodeDiscoveryProvider(ILoggerFactory logger, K8sDiscoveryOptions options)\n    {\n        _logger = logger.CreateLogger<ConsulNodeDiscoveryProvider>();\n        _options = options;\n    }\n\n    public async Task<Node?> GetNode(string svcName, string ns, CancellationToken cancellationToken = default)\n    {\n        try\n        {\n            var client = new Kubernetes(_options.K8SClientConfig);\n            var service =\n                await client.CoreV1.ReadNamespacedServiceAsync(svcName, ns, cancellationToken: cancellationToken);\n\n            return new Node\n            {\n                Id = service.Uid(),\n                Name = service.Name(),\n                Address = \"http://\" + service.Metadata.Name + \".\" + ns,\n                Port = service.Spec.Ports?[0].Port ?? 0,\n                Tags = string.Join(',',\n                    service.Labels()?.Select(x => x.Key + \":\" + x.Value) ?? Array.Empty<string>())\n            };\n        }\n        catch (Exception ex)\n        {\n            _logger.LogError(ex, $\"Get consul nodes raised an exception. Exception:{ex.Message}\");\n        }\n\n        return null;\n    }\n\n    public async Task<IList<Node>> GetNodes(string? ns, CancellationToken cancellationToken)\n    {\n        try\n        {\n            ns = _options.K8SClientConfig.Namespace;\n\n            if (ns == null) return new List<Node>();\n\n            var nodes = await ListServices(ns);\n\n            CapCache.Global.AddOrUpdate(\"cap.nodes.count\", nodes.Count, TimeSpan.FromSeconds(60), true);\n\n            return nodes;\n        }\n        catch (Exception ex)\n        {\n            CapCache.Global.AddOrUpdate(\"cap.nodes.count\", 0, TimeSpan.FromSeconds(20));\n\n            _logger.LogError(\n                $\"Get k8s services raised an exception. Exception:{ex.Message},{ex.InnerException?.Message}\");\n            return new List<Node>();\n        }\n    }\n\n    public async Task<List<string>> GetNamespaces(CancellationToken cancellationToken)\n    {\n        var client = new Kubernetes(_options.K8SClientConfig);\n        try\n        {\n            var namespaces = await client.ListNamespaceAsync(cancellationToken: cancellationToken);\n            return namespaces.Items.Select(x => x.Name()).ToList();\n        }\n        catch (Exception)\n        {\n            if (string.IsNullOrEmpty(_options.K8SClientConfig.Namespace))\n            {\n                return new List<string>();\n            }\n\n            return new List<string>() { _options.K8SClientConfig.Namespace };\n        }\n    }\n\n    public async Task<IList<Node>> ListServices(string? ns = null)\n    {\n        var client = new Kubernetes(_options.K8SClientConfig);\n        var services = await client.CoreV1.ListNamespacedServiceAsync(ns);\n\n        var result = new List<Node>();\n        foreach (var service in services.Items)\n        {\n            IDictionary<string, string> tags = service.Labels();\n\n            var filterResult = FilterNodesByTags(tags);\n\n            if (filterResult.hideNode)\n            {\n                continue;\n            }\n\n            int port = GetPortByNameOrIndex(service, filterResult.filteredPortName, filterResult.filteredPortIndex);\n\n            result.Add(new Node\n            {\n                Id = service.Uid(),\n                Name = service.Name(),\n                Address = \"http://\" + service.Metadata.Name + \".\" + ns,\n                Port = port,\n                Tags = string.Join(',', service.Labels()?.Select(x => x.Key + \":\" + x.Value) ?? Array.Empty<string>())\n            });\n        }\n\n        return result;\n    }\n\n\n    /// <summary>\n    /// Given the filters (filterPortName and filterPortIndex) this method will try to find the port \n    /// filterPortName is checked first and if no port is found by that name filterPortIndex is checked\n    /// Returns 0 if service is null or no port specified in the service \n    /// Returns the portNumber of the matched port if something is found \n    /// </summary>\n    /// <param name=\"service\"></param>\n    /// <param name=\"filterPortName\"></param>\n    /// <param name=\"filterPortIndex\"></param>\n    /// <returns></returns>\n    private static int GetPortByNameOrIndex(V1Service? service, string filterPortName, int filterPortIndex)\n    {\n        if (service is null)\n        {\n            return 0;\n        }\n\n        if (service.Spec.Ports is null)\n        {\n            return 0;\n        }\n\n        var result = GetPortByName(service.Spec.Ports, filterPortName);\n        if (result > 0)\n        {\n            return result;\n        }\n\n        result = GetPortByIndex(service.Spec.Ports, filterPortIndex);\n        if (result > 0)\n        {\n            return result;\n        }\n\n        return service.Spec.Ports[0]?.Port ?? 0;\n    }\n\n    /// <summary>\n    /// This method will try to find a port with the specified Index \n    /// Will Return 0 if index is not found  \n    /// Returns: port number or 0 if not found \n    /// </summary>\n    /// <param name=\"servicePorts\"></param>\n    /// <param name=\"filterIndex\"></param>\n    /// <returns></returns>\n    private static int GetPortByIndex(IList<V1ServicePort> servicePorts, int filterIndex)\n    {\n\n        var portByIndex = servicePorts.ElementAtOrDefault(filterIndex);\n        if (portByIndex is null)\n        {\n            return 0;\n        }\n\n        return portByIndex.Port;\n    }\n\n    /// <summary>\n    /// This method will try to find a port with the specified name \n    /// Will Return 0 if none found \n    /// Returns: port number or 0 if not found \n    /// </summary>\n    /// <param name=\"service\"></param>\n    /// <param name=\"portName\"></param>\n    /// <returns></returns>\n    private static int GetPortByName(IList<V1ServicePort> servicePorts, string portName)\n    {\n        if (!string.IsNullOrEmpty(portName))\n        {\n            return 0;\n        }\n\n        var portByName = servicePorts.FirstOrDefault(p => p.Name == portName);\n        if (portByName is null)\n        {\n            return 0;\n        }\n\n        return portByName.Port;\n    }\n\n    private record TagFilterResult(bool hideNode, int filteredPortIndex, string filteredPortName);\n\n    private TagFilterResult FilterNodesByTags(IDictionary<string, string> tags)\n    {\n        var isNodeHidden = _options.ShowOnlyExplicitVisibleNodes;\n        var filteredPortIndex = 0; //this the default port index \n        var filteredPortName = string.Empty; //this the default port index \n\n        if (tags == null)\n        {\n\n            return new TagFilterResult(isNodeHidden, filteredPortIndex, filteredPortName);\n        }\n\n\n        foreach (var tag in tags)\n        {\n            //look out for dotnetcore.cap tags \n            //based on value will do conditions \n            var isCapTag = tag.Key.StartsWith(TagPrefix, StringComparison.InvariantCultureIgnoreCase);\n\n            if (!isCapTag)\n            {\n                continue;\n            }\n\n            string capTagScope = GetTagScope(tag);\n\n            //check for hide Tag\n            if (IsNodeHidden(tag, capTagScope))\n            {\n                return new TagFilterResult(true, filteredPortIndex, filteredPortName);\n            }\n            else\n            {\n                isNodeHidden = false;\n            }\n\n            //check for portIndex-X tag.\n            //If multiple tags with portIndex are found only the last has power\n            var hasNewPort = CheckFilterPortIndex(tag, capTagScope);\n            if (hasNewPort.HasValue)\n            {\n                filteredPortIndex = hasNewPort.Value;\n            }\n\n            //check for portName-X tag.\n            //If multiple tags with portName are found only the last has power\n            if (capTagScope.Equals(\"portName\", StringComparison.InvariantCultureIgnoreCase))\n            {\n                filteredPortName = tag.Value;\n            }\n\n        }\n\n        return new TagFilterResult(isNodeHidden, filteredPortIndex, filteredPortName);\n    }\n\n    private int? CheckFilterPortIndex(KeyValuePair<string, string> tag, string capTagScope)\n    {\n        if (!capTagScope.Equals(\"portIndex\", StringComparison.InvariantCultureIgnoreCase))\n        {\n            return null;\n        }\n\n        var hasPort = int.TryParse(tag.Value, out int filterPort);\n        if (!hasPort)\n        {\n            return null;\n        }\n\n        return filterPort;\n    }\n\n    private bool IsNodeHidden(KeyValuePair<string, string> tag, string capTagScope)\n    {\n        if (!capTagScope.Equals(\"visibility\", StringComparison.InvariantCultureIgnoreCase))\n        {\n            return false;\n        }\n\n        //We will not show the node if the tag value is \"dotnetcore.cap.visibility:hide\"\n        if (tag.Value.Equals(\"hide\", StringComparison.InvariantCultureIgnoreCase))\n        {\n            return true;\n        }\n\n        //We will not show the node if the K8s Dashboard option is \n        //ShowOnlyExplicitVisibleNodes=True\n        //and the tag value is NOT \"dotnetcore.cap.visibility:show\"\n        if (!_options.ShowOnlyExplicitVisibleNodes)\n        {\n            return false;\n        }\n\n        return !tag.Value.Equals(\"show\", StringComparison.InvariantCultureIgnoreCase);\n    }\n\n    private string GetTagScope(KeyValuePair<string, string> tag)\n    {\n        var capTagScope = tag.Key.Replace(TagPrefix, \"\", StringComparison.InvariantCultureIgnoreCase);\n        if (capTagScope.StartsWith(\".\"))\n        {\n            capTagScope = capTagScope.Substring(1);\n        }\n\n        return capTagScope;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Dashboard.K8s/ServiceCollectionExtensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing DotNetCore.CAP;\nusing DotNetCore.CAP.Dashboard.K8s;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.Extensions.DependencyInjection;\n\n/// <summary>\n/// Contains extension methods to <see cref=\"IServiceCollection\" /> for configuring consistence services.\n/// </summary>\npublic static class ServiceCollectionExtensions\n{\n    /// <summary>\n    /// Run only CAP dashboard to view data based on the nodes discovered in Kubernetes.\n    /// </summary>\n    /// <param name=\"services\">The services available in the application.</param>\n    /// <param name=\"option\">An action to configure the <see cref=\"DashboardOptions\" />.</param>\n    /// <param name=\"k8SOption\">An action to configure the <see cref=\"K8sDiscoveryOptions\" />.</param>\n    /// <returns>An <see cref=\"CapBuilder\" /> for application services.</returns>\n    public static IServiceCollection AddCapDashboardStandalone(this IServiceCollection services,\n        Action<DashboardOptions>? option = null,\n        Action<K8sDiscoveryOptions>? k8SOption = null)\n    {\n        new DashboardOptionsExtension(option ?? (_ => { })).AddServices(services);\n        new K8sDiscoveryOptionsExtension(k8SOption).AddServices(services);\n        return services;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.InMemoryStorage/CAP.InMemoryCapOptionsExtension.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing DotNetCore.CAP.InMemoryStorage;\nusing DotNetCore.CAP.Persistence;\nusing Microsoft.Extensions.DependencyInjection;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\ninternal class InMemoryCapOptionsExtension : ICapOptionsExtension\n{\n    public void AddServices(IServiceCollection services)\n    {\n        services.AddSingleton(new CapStorageMarkerService(\"InMemory\"));\n\n        services.AddTransient<ICapTransaction, InMemoryCapTransaction>();\n        services.AddSingleton<IDataStorage, InMemoryStorage.InMemoryStorage>();\n        services.AddSingleton<IStorageInitializer, InMemoryStorageInitializer>();\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.InMemoryStorage/CAP.Options.Extensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing DotNetCore.CAP;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.Extensions.DependencyInjection;\n\npublic static class CapOptionsExtensions\n{\n    public static CapOptions UseInMemoryStorage(this CapOptions options)\n    {\n        options.RegisterExtension(new InMemoryCapOptionsExtension());\n        return options;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.InMemoryStorage/DotNetCore.CAP.InMemoryStorage.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\t<Nullable>enable</Nullable>\n    <PackageTags>$(PackageTags);InMemory</PackageTags>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n  </ItemGroup>\n \n</Project>\n"
  },
  {
    "path": "src/DotNetCore.CAP.InMemoryStorage/ICapTransaction.InMemory.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\n// ReSharper disable once CheckNamespace\n\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Transport;\n\nnamespace DotNetCore.CAP.InMemoryStorage;\n\ninternal class InMemoryCapTransaction : CapTransactionBase\n{\n    public InMemoryCapTransaction(IDispatcher dispatcher) : base(dispatcher)\n    {\n    }\n\n    public override void Commit()\n    {\n        Flush();\n    }\n\n    public override Task CommitAsync(CancellationToken cancellationToken = default)\n    {\n        return Task.CompletedTask;\n    }\n\n    public override void Rollback()\n    {\n        //Ignore\n    }\n\n    public override Task RollbackAsync(CancellationToken cancellationToken = default)\n    {\n        return Task.CompletedTask;\n    } \n}"
  },
  {
    "path": "src/DotNetCore.CAP.InMemoryStorage/IDataStorage.InMemory.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Monitoring;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Serialization;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.InMemoryStorage;\n\ninternal class InMemoryStorage : IDataStorage\n{\n    private readonly IOptions<CapOptions> _capOptions;\n    private readonly ISerializer _serializer;\n    private readonly ISnowflakeId _snowflakeId;\n\n    public InMemoryStorage(IOptions<CapOptions> capOptions, ISerializer serializer, ISnowflakeId snowflakeId)\n    {\n        _capOptions = capOptions;\n        _serializer = serializer;\n        _snowflakeId = snowflakeId;\n    }\n\n    public static ConcurrentDictionary<string, MemoryMessage> PublishedMessages { get; } = new();\n\n    public static ConcurrentDictionary<string, MemoryMessage> ReceivedMessages { get; } = new();\n\n    public Task<bool> AcquireLockAsync(string key, TimeSpan ttl, string instance, CancellationToken token = default)\n    {\n        return Task.FromResult(true);\n    }\n\n    public Task ReleaseLockAsync(string key, string instance, CancellationToken token = default)\n    {\n        return Task.CompletedTask;\n    }\n\n    public Task RenewLockAsync(string key, TimeSpan ttl, string instance, CancellationToken token = default)\n    {\n        return Task.CompletedTask;\n    }\n\n    public Task ChangePublishStateToDelayedAsync(string[] ids)\n    {\n        foreach (var id in ids)\n        {\n            PublishedMessages[id].StatusName = StatusName.Delayed;\n        }\n\n        return Task.CompletedTask;\n    }\n\n    public Task ChangePublishStateAsync(MediumMessage message, StatusName state, object? dbTransaction = null)\n    {\n        PublishedMessages[message.DbId].StatusName = state;\n        PublishedMessages[message.DbId].ExpiresAt = message.ExpiresAt;\n        PublishedMessages[message.DbId].Content = _serializer.Serialize(message.Origin);\n        return Task.CompletedTask;\n    }\n\n    public Task ChangeReceiveStateAsync(MediumMessage message, StatusName state)\n    {\n        ReceivedMessages[message.DbId].StatusName = state;\n        ReceivedMessages[message.DbId].ExpiresAt = message.ExpiresAt;\n        ReceivedMessages[message.DbId].Content = _serializer.Serialize(message.Origin);\n        return Task.CompletedTask;\n    }\n\n    public Task<MediumMessage> StoreMessageAsync(string name, Message content, object? dbTransaction = null)\n    {\n        var message = new MediumMessage\n        {\n            DbId = content.GetId(),\n            Origin = content,\n            Content = _serializer.Serialize(content),\n            Added = DateTime.Now,\n            ExpiresAt = null,\n            Retries = 0\n        };\n\n        PublishedMessages[message.DbId] = new MemoryMessage\n        {\n            DbId = message.DbId,\n            Name = name,\n            Origin = message.Origin,\n            Content = message.Content,\n            Retries = message.Retries,\n            Added = message.Added,\n            ExpiresAt = message.ExpiresAt,\n            StatusName = StatusName.Scheduled\n        };\n\n        return Task.FromResult(message);\n    }\n\n    public Task StoreReceivedExceptionMessageAsync(string name, string group, string content)\n    {\n        var id = _snowflakeId.NextId().ToString();\n\n        ReceivedMessages[id] = new MemoryMessage\n        {\n            DbId = id,\n            Group = group,\n            Origin = null!,\n            Name = name,\n            Content = content,\n            Retries = _capOptions.Value.FailedRetryCount,\n            Added = DateTime.Now,\n            ExpiresAt = DateTime.Now.AddSeconds(_capOptions.Value.FailedMessageExpiredAfter),\n            StatusName = StatusName.Failed\n        };\n\n        return Task.CompletedTask;\n    }\n\n    public Task<MediumMessage> StoreReceivedMessageAsync(string name, string group, Message message)\n    {\n        var mdMessage = new MediumMessage\n        {\n            DbId = _snowflakeId.NextId().ToString(),\n            Origin = message,\n            Added = DateTime.Now,\n            ExpiresAt = null,\n            Retries = 0\n        };\n\n        ReceivedMessages[mdMessage.DbId] = new MemoryMessage\n        {\n            DbId = mdMessage.DbId,\n            Origin = mdMessage.Origin,\n            Group = group,\n            Name = name,\n            Content = _serializer.Serialize(mdMessage.Origin),\n            Retries = mdMessage.Retries,\n            Added = mdMessage.Added,\n            ExpiresAt = mdMessage.ExpiresAt,\n            StatusName = StatusName.Scheduled\n        };\n\n        return Task.FromResult(mdMessage);\n    }\n\n    public Task<int> DeleteExpiresAsync(string table, DateTime timeout, int batchCount = 1000,\n        CancellationToken token = default)\n    {\n        var removed = 0;\n        if (table == nameof(PublishedMessages))\n        {\n            var ids = PublishedMessages.Values\n                .Where(x => x.ExpiresAt < timeout)\n                .Select(x => x.DbId)\n                .Take(batchCount);\n\n            foreach (var id in ids)\n            {\n                if (PublishedMessages.TryRemove(id, out _)) removed++;\n            }\n        }\n        else\n        {\n            var ids = ReceivedMessages.Values\n                .Where(x => x.ExpiresAt < timeout)\n                .Select(x => x.DbId)\n                .Take(batchCount);\n\n            foreach (var id in ids)\n            {\n                if (ReceivedMessages.TryRemove(id, out _)) removed++;\n            }\n        }\n\n        return Task.FromResult(removed);\n    }\n\n    public Task<IEnumerable<MediumMessage>> GetPublishedMessagesOfNeedRetry(TimeSpan lookbackSeconds)\n    {\n        IEnumerable<MediumMessage> result = PublishedMessages.Values\n            .Where(x => x.Retries < _capOptions.Value.FailedRetryCount\n                        && x.Added < DateTime.Now.Subtract(lookbackSeconds)\n                        && (x.StatusName == StatusName.Scheduled || x.StatusName == StatusName.Failed))\n            .Take(200)\n            .Select(x => (MediumMessage)x).ToList();\n\n        //foreach (var message in result)\n        //{\n        //    message.Origin = _serializer.DeserializeAsync(message.Content)!;\n        //}\n\n        return Task.FromResult(result);\n    }\n\n    public Task<IEnumerable<MediumMessage>> GetReceivedMessagesOfNeedRetry(TimeSpan lookbackSeconds)\n    {\n        IEnumerable<MediumMessage> result = ReceivedMessages.Values\n            .Where(x => x.Retries < _capOptions.Value.FailedRetryCount\n                        && x.Added < DateTime.Now.Subtract(lookbackSeconds)\n                        && (x.StatusName == StatusName.Scheduled || x.StatusName == StatusName.Failed))\n            .Take(200)\n            .Select(x => (MediumMessage)x).ToList();\n\n        return Task.FromResult(result);\n    }\n\n    public Task<int> DeleteReceivedMessageAsync(long id)\n    {\n        var deleteResult = ReceivedMessages.TryRemove(id.ToString(CultureInfo.InvariantCulture), out _);\n        return Task.FromResult(deleteResult ? 1 : 0);\n    }\n\n    public Task<int> DeletePublishedMessageAsync(long id)\n    {\n        var deleteResult = PublishedMessages.TryRemove(id.ToString(CultureInfo.InvariantCulture), out _);\n        return Task.FromResult(deleteResult ? 1 : 0);\n    }\n\n    public Task ScheduleMessagesOfDelayedAsync(Func<object, IEnumerable<MediumMessage>, Task> scheduleTask,\n        CancellationToken token = default)\n    {\n        var result = PublishedMessages.Values.Where(x =>\n                (x.StatusName == StatusName.Delayed && x.ExpiresAt < DateTime.Now.AddMinutes(2))\n                || (x.StatusName == StatusName.Queued && x.ExpiresAt < DateTime.Now.AddMinutes(-1)))\n            .Take(_capOptions.Value.SchedulerBatchSize)\n            .Select(x => (MediumMessage)x);\n\n        return scheduleTask(null!, result);\n    }\n\n    public IMonitoringApi GetMonitoringApi()\n    {\n        return new InMemoryMonitoringApi();\n    }\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP.InMemoryStorage/IMonitoringApi.InMemory.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Monitoring;\nusing DotNetCore.CAP.Persistence;\n\nnamespace DotNetCore.CAP.InMemoryStorage;\n\ninternal class InMemoryMonitoringApi : IMonitoringApi\n{\n    public Task<MediumMessage?> GetPublishedMessageAsync(long id)\n    {\n        return Task.FromResult<MediumMessage?>(\n            InMemoryStorage.PublishedMessages.Values.FirstOrDefault(x =>\n                x.DbId == id.ToString(CultureInfo.InvariantCulture)));\n    }\n\n    public Task<MediumMessage?> GetReceivedMessageAsync(long id)\n    {\n        return Task.FromResult<MediumMessage?>(\n            InMemoryStorage.ReceivedMessages.Values.FirstOrDefault(x =>\n                x.DbId == id.ToString(CultureInfo.InvariantCulture)));\n    }\n\n    public Task<StatisticsDto> GetStatisticsAsync()\n    {\n        var stats = new StatisticsDto\n        {\n            PublishedSucceeded =\n                InMemoryStorage.PublishedMessages.Values.Count(x => x.StatusName == StatusName.Succeeded),\n            ReceivedSucceeded =\n                InMemoryStorage.ReceivedMessages.Values.Count(x => x.StatusName == StatusName.Succeeded),\n            PublishedFailed = InMemoryStorage.PublishedMessages.Values.Count(x => x.StatusName == StatusName.Failed),\n            ReceivedFailed = InMemoryStorage.ReceivedMessages.Values.Count(x => x.StatusName == StatusName.Failed),\n            PublishedDelayed = InMemoryStorage.PublishedMessages.Values.Count(x => x.StatusName == StatusName.Delayed)\n        };\n        return Task.FromResult(stats);\n    }\n\n    public Task<IDictionary<DateTime, int>> HourlyFailedJobs(MessageType type)\n    {\n        return GetHourlyTimelineStats(type, nameof(StatusName.Failed));\n    }\n\n    public Task<IDictionary<DateTime, int>> HourlySucceededJobs(MessageType type)\n    {\n        return GetHourlyTimelineStats(type, nameof(StatusName.Succeeded));\n    }\n\n    public Task<PagedQueryResult<MessageDto>> GetMessagesAsync(MessageQueryDto queryDto)\n    {\n        if (queryDto.MessageType == MessageType.Publish)\n        {\n            var expression = InMemoryStorage.PublishedMessages.Values.Where(x => true);\n\n            if (!string.IsNullOrEmpty(queryDto.StatusName))\n                expression = expression.Where(x =>\n                    x.StatusName.ToString().Equals(queryDto.StatusName, StringComparison.InvariantCultureIgnoreCase));\n\n            if (!string.IsNullOrEmpty(queryDto.Name))\n                expression = expression.Where(x =>\n                    x.Name.Equals(queryDto.Name, StringComparison.InvariantCultureIgnoreCase));\n\n            if (!string.IsNullOrEmpty(queryDto.Content))\n                expression = expression.Where(x => x.Content.Contains(queryDto.Content));\n\n            var offset = queryDto.CurrentPage * queryDto.PageSize;\n            var size = queryDto.PageSize;\n\n            var allItems = expression.Select(x => new MessageDto\n            {\n                Added = x.Added,\n                Version = \"N/A\",\n                Content = x.Content,\n                ExpiresAt = x.ExpiresAt,\n                Id = x.DbId,\n                Name = x.Name,\n                Retries = x.Retries,\n                StatusName = x.StatusName.ToString()\n            });\n\n            return Task.FromResult(new PagedQueryResult<MessageDto>\n            {\n                Items = allItems.Skip(offset).Take(size).ToList(),\n                PageIndex = queryDto.CurrentPage,\n                PageSize = queryDto.PageSize,\n                Totals = allItems.Count()\n            });\n        }\n        else\n        {\n            var expression = InMemoryStorage.ReceivedMessages.Values.Where(x => true);\n\n            if (!string.IsNullOrEmpty(queryDto.StatusName))\n                expression = expression.Where(x =>\n                    x.StatusName.ToString().Equals(queryDto.StatusName, StringComparison.InvariantCultureIgnoreCase));\n\n            if (!string.IsNullOrEmpty(queryDto.Name))\n                expression = expression.Where(x =>\n                    x.Name.Equals(queryDto.Name, StringComparison.InvariantCultureIgnoreCase));\n\n            if (!string.IsNullOrEmpty(queryDto.Group))\n                expression = expression.Where(x =>\n                    x.Group.Equals(queryDto.Group, StringComparison.InvariantCultureIgnoreCase));\n\n            if (!string.IsNullOrEmpty(queryDto.Content))\n                expression = expression.Where(x => x.Content.Contains(queryDto.Content));\n\n            var offset = queryDto.CurrentPage * queryDto.PageSize;\n            var size = queryDto.PageSize;\n\n            var allItems = expression.Select(x => new MessageDto\n            {\n                Added = x.Added,\n                Group = x.Group,\n                Version = \"N/A\",\n                Content = x.Content,\n                ExpiresAt = x.ExpiresAt,\n                Id = x.DbId,\n                Name = x.Name,\n                Retries = x.Retries,\n                StatusName = x.StatusName.ToString()\n            });\n\n            return Task.FromResult(new PagedQueryResult<MessageDto>\n            {\n                Items = allItems.Skip(offset).Take(size).ToList(),\n                PageIndex = queryDto.CurrentPage,\n                PageSize = queryDto.PageSize,\n                Totals = allItems.Count()\n            });\n        }\n    }\n\n    public ValueTask<int> PublishedFailedCount()\n    {\n        return new ValueTask<int>(\n            InMemoryStorage.PublishedMessages.Values.Count(x => x.StatusName == StatusName.Failed));\n    }\n\n    public ValueTask<int> PublishedSucceededCount()\n    {\n        return new ValueTask<int>(\n            InMemoryStorage.PublishedMessages.Values.Count(x => x.StatusName == StatusName.Succeeded));\n    }\n\n    public ValueTask<int> ReceivedFailedCount()\n    {\n        return new ValueTask<int>(\n            InMemoryStorage.ReceivedMessages.Values.Count(x => x.StatusName == StatusName.Failed));\n    }\n\n    public ValueTask<int> ReceivedSucceededCount()\n    {\n        return new ValueTask<int>(\n            InMemoryStorage.ReceivedMessages.Values.Count(x => x.StatusName == StatusName.Succeeded));\n    }\n\n    private Task<IDictionary<DateTime, int>> GetHourlyTimelineStats(MessageType type, string statusName)\n    {\n        var endDate = DateTime.Now;\n        var dates = new List<DateTime>();\n        for (var i = 0; i < 24; i++)\n        {\n            dates.Add(endDate);\n            endDate = endDate.AddHours(-1);\n        }\n\n        var keyMaps = dates.ToDictionary(x => x.ToString(\"yyyy-MM-dd-HH\"), x => x);\n\n\n        Dictionary<string, int> valuesMap;\n        if (type == MessageType.Publish)\n            valuesMap = InMemoryStorage.PublishedMessages.Values\n                .Where(x => x.StatusName.ToString() == statusName)\n                .GroupBy(x => x.Added.ToString(\"yyyy-MM-dd-HH\"))\n                .ToDictionary(x => x.Key, x => x.Count());\n        else\n            valuesMap = InMemoryStorage.ReceivedMessages.Values\n                .Where(x => x.StatusName.ToString() == statusName)\n                .GroupBy(x => x.Added.ToString(\"yyyy-MM-dd-HH\"))\n                .ToDictionary(x => x.Key, x => x.Count());\n\n        foreach (var key in keyMaps.Keys)\n        {\n            if (!valuesMap.ContainsKey(key)) valuesMap.Add(key, 0);\n        }\n\n        IDictionary<DateTime, int> result = new Dictionary<DateTime, int>();\n        for (var i = 0; i < keyMaps.Count; i++)\n        {\n            var value = valuesMap[keyMaps.ElementAt(i).Key];\n            result.Add(keyMaps.ElementAt(i).Value, value);\n        }\n\n        return Task.FromResult(result);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.InMemoryStorage/IStorageInitializer.InMemory.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Persistence;\n\nnamespace DotNetCore.CAP.InMemoryStorage;\n\ninternal class InMemoryStorageInitializer : IStorageInitializer\n{\n    public string GetPublishedTableName()\n    {\n        return nameof(InMemoryStorage.PublishedMessages);\n    }\n\n    public string GetReceivedTableName()\n    {\n        return nameof(InMemoryStorage.ReceivedMessages);\n    }\n\n    public string GetLockTableName()\n    {\n        return string.Empty;\n    }\n\n    public Task InitializeAsync(CancellationToken cancellationToken)\n    {\n        return Task.CompletedTask;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.InMemoryStorage/MemoryMessage.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Persistence;\n\nnamespace DotNetCore.CAP.InMemoryStorage;\n\ninternal class MemoryMessage : MediumMessage\n{\n    public string Name { get; set; } = default!;\n\n    public StatusName StatusName { get; set; }\n\n    public string Group { get; set; } = default!;\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP.Kafka;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.DependencyInjection;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\ninternal sealed class KafkaCapOptionsExtension : ICapOptionsExtension\n{\n    private readonly Action<KafkaOptions> _configure;\n\n    public KafkaCapOptionsExtension(Action<KafkaOptions> configure)\n    {\n        _configure = configure;\n    }\n\n    public void AddServices(IServiceCollection services)\n    {\n        services.AddSingleton(new CapMessageQueueMakerService(\"Kafka\"));\n\n        services.Configure(_configure);\n\n        services.AddSingleton<ITransport, KafkaTransport>();\n        services.AddSingleton<IConsumerClientFactory, KafkaConsumerClientFactory>();\n        services.AddSingleton<IConnectionPool, ConnectionPool>();\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing Confluent.Kafka;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\n/// <summary>\n/// Provides programmatic configuration for the CAP kafka project.\n/// </summary>\npublic class KafkaOptions\n{\n    /// <summary>\n    /// librdkafka configuration parameters (refer to https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md).\n    /// <para>\n    /// Topic configuration parameters are specified via the \"default.topic.config\" sub-dictionary config parameter.\n    /// </para>\n    /// </summary>\n    public readonly Dictionary<string, string> MainConfig;\n\n    public KafkaOptions()\n    {\n        MainConfig = new Dictionary<string, string>();\n        RetriableErrorCodes = new List<ErrorCode>\n        {\n            ErrorCode.GroupLoadInProgress,\n            ErrorCode.Local_Retry,\n            ErrorCode.Local_TimedOut,\n            ErrorCode.RequestTimedOut,\n            ErrorCode.LeaderNotAvailable,\n            ErrorCode.NotLeaderForPartition,\n            ErrorCode.RebalanceInProgress,\n            ErrorCode.NotCoordinatorForGroup,\n            ErrorCode.NetworkException,\n            ErrorCode.GroupCoordinatorNotAvailable\n        };\n    }\n\n    /// <summary>\n    /// Producer connection pool size, default is 10\n    /// </summary>\n    public int ConnectionPoolSize { get; set; } = 10;\n\n    /// <summary>\n    /// The `bootstrap.servers` item config of <see cref=\"MainConfig\" />.\n    /// <para>\n    /// Initial list of brokers as a CSV list of broker host or host:port.\n    /// </para>\n    /// </summary>\n    public string Servers { get; set; } = default!;\n\n    /// <summary>\n    /// If you need to get offset and partition and so on.., you can use this function to write additional header into\n    /// <see cref=\"CapHeader\" />\n    /// </summary>\n    public Func<ConsumeResult<string, byte[]>, IServiceProvider, List<KeyValuePair<string, string>>>? CustomHeadersBuilder { get; set; }\n\n    /// <summary>\n    /// New retriable error code (refer to\n    /// https://docs.confluent.io/platform/current/clients/librdkafka/html/rdkafkacpp_8h.html#a4c6b7af48c215724c323c60ea4080dbf)\n    /// </summary>\n    public IList<ErrorCode> RetriableErrorCodes { get; set; }\n\n    public KafkaTopicOptions TopicOptions { get; set; } = new();\n}\n\npublic class KafkaTopicOptions\n{\n    /// <summary>\n    /// The number of partitions for the new topic\n    /// </summary>\n    public short NumPartitions { get; set; } = -1;\n\n    /// <summary>\n    /// The replication factor for the new topic\n    /// </summary>\n    public short ReplicationFactor { get; set; } = -1;\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Kafka/CAP.Options.Extensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.Extensions.DependencyInjection;\n\npublic static class CapOptionsExtensions\n{\n    /// <summary>\n    /// Configuration to use kafka in CAP.\n    /// </summary>\n    /// <param name=\"options\">CAP configuration options</param>\n    /// <param name=\"bootstrapServers\">Kafka bootstrap server urls.</param>\n    public static CapOptions UseKafka(this CapOptions options, string bootstrapServers)\n    {\n        return options.UseKafka(opt => { opt.Servers = bootstrapServers; });\n    }\n\n    /// <summary>\n    /// Configuration to use kafka in CAP.\n    /// </summary>\n    /// <param name=\"options\">CAP configuration options</param>\n    /// <param name=\"configure\">Provides programmatic configuration for the kafka .</param>\n    /// <returns></returns>\n    public static CapOptions UseKafka(this CapOptions options, Action<KafkaOptions> configure)\n    {\n        if (configure == null) throw new ArgumentNullException(nameof(configure));\n\n        options.RegisterExtension(new KafkaCapOptionsExtension(configure));\n\n        return options;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Kafka/DotNetCore.CAP.Kafka.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\t<Nullable>enable</Nullable>\n    <PackageTags>$(PackageTags);Kafka</PackageTags>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <WarningsAsErrors>NU1605;NU1701</WarningsAsErrors>\n    <NoWarn>NU1701;CS1591</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Confluent.Kafka\" Version=\"2.12.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n  </ItemGroup> \n\n</Project>\n"
  },
  {
    "path": "src/DotNetCore.CAP.Kafka/IConnectionPool.Default.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Threading;\nusing Confluent.Kafka;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.Kafka;\n\npublic class ConnectionPool : IConnectionPool, IDisposable\n{\n    private readonly KafkaOptions _options;\n    private readonly ConcurrentQueue<IProducer<string, byte[]>> _producerPool;\n    private int _maxSize;\n    private int _pCount;\n\n    public ConnectionPool(ILogger<ConnectionPool> logger, IOptions<KafkaOptions> options)\n    {\n        _options = options.Value;\n        _producerPool = new ConcurrentQueue<IProducer<string, byte[]>>();\n        _maxSize = _options.ConnectionPoolSize;\n\n        logger.LogDebug(\"CAP Kafka servers: {0}\", _options.Servers);\n    }\n\n    public string ServersAddress => _options.Servers;\n\n    public IProducer<string, byte[]> RentProducer()\n    {\n        if (_producerPool.TryDequeue(out var producer))\n        {\n            Interlocked.Decrement(ref _pCount);\n\n            return producer;\n        }\n\n        var config = new ProducerConfig(new Dictionary<string, string>(_options.MainConfig))\n        {\n            BootstrapServers = _options.Servers,\n        };\n\n        config.QueueBufferingMaxMessages ??= 10;\n        config.MessageTimeoutMs ??= 5000;\n        config.RequestTimeoutMs ??= 3000;\n\n        producer = BuildProducer(config);\n\n        return producer;\n    }\n\n    public bool Return(IProducer<string, byte[]> producer)\n    {\n        if (Interlocked.Increment(ref _pCount) <= _maxSize)\n        {\n            _producerPool.Enqueue(producer);\n\n            return true;\n        }\n\n        producer.Dispose();\n\n        Interlocked.Decrement(ref _pCount);\n\n        return false;\n    }\n\n    public void Dispose()\n    {\n        _maxSize = 0;\n\n        while (_producerPool.TryDequeue(out var context))\n        {\n            context.Dispose();\n        }\n    }\n\n    protected virtual IProducer<string, byte[]> BuildProducer(ProducerConfig config)\n    {\n        return new ProducerBuilder<string, byte[]>(config).Build();\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Kafka/IConnectionPool.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing Confluent.Kafka;\n\nnamespace DotNetCore.CAP.Kafka;\n\npublic interface IConnectionPool\n{\n    string ServersAddress { get; }\n\n    IProducer<string, byte[]> RentProducer();\n\n    bool Return(IProducer<string, byte[]> producer);\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Kafka/ITransport.Kafka.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Confluent.Kafka;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Logging;\nusing Headers = Confluent.Kafka.Headers;\n\nnamespace DotNetCore.CAP.Kafka;\n\ninternal class KafkaTransport : ITransport\n{\n    private readonly IConnectionPool _connectionPool;\n    private readonly ILogger _logger;\n\n    public KafkaTransport(ILogger<KafkaTransport> logger, IConnectionPool connectionPool)\n    {\n        _logger = logger;\n        _connectionPool = connectionPool;\n    }\n\n    public BrokerAddress BrokerAddress => new(\"Kafka\", _connectionPool.ServersAddress);\n\n    public async Task<OperateResult> SendAsync(TransportMessage message)\n    {\n        var producer = _connectionPool.RentProducer();\n\n        try\n        {\n            var headers = new Headers();\n\n            foreach (var header in message.Headers)\n            {\n                headers.Add(header.Value != null\n                    ? new Header(header.Key, Encoding.UTF8.GetBytes(header.Value))\n                    : new Header(header.Key, null));\n            }\n\n            var result = await producer.ProduceAsync(message.GetName(), new Message<string, byte[]>\n            {\n                Headers = headers,\n                Key = message.Headers.TryGetValue(KafkaHeaders.KafkaKey, out var kafkaMessageKey) &&\n                      !string.IsNullOrEmpty(kafkaMessageKey)\n                    ? kafkaMessageKey\n                    : message.GetId(),\n                Value = message.Body.ToArray()!\n            });\n\n            if (result.Status is PersistenceStatus.Persisted or PersistenceStatus.PossiblyPersisted)\n            {\n                _logger.LogDebug($\"kafka topic message [{message.GetName()}] has been published.\");\n\n                return OperateResult.Success;\n            }\n\n            throw new PublisherSentFailedException(\"kafka message persisted failed!\");\n        }\n        catch (Exception ex)\n        {\n            var warpEx = new PublisherSentFailedException(ex.Message, ex);\n\n            return OperateResult.Failed(warpEx);\n        }\n        finally\n        {\n            _connectionPool.Return(producer);\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Confluent.Kafka;\nusing Confluent.Kafka.Admin;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Options;\nusing Headers = DotNetCore.CAP.Messages.Headers;\n\nnamespace DotNetCore.CAP.Kafka;\n\npublic class KafkaConsumerClient : IConsumerClient\n{\n    private static readonly object Lock = new();\n    private readonly string _groupId;\n    private readonly byte _groupConcurrent;\n    private readonly SemaphoreSlim _semaphore;\n    private readonly KafkaOptions _kafkaOptions;\n    private readonly IServiceProvider _serviceProvider;\n    private IConsumer<string, byte[]>? _consumerClient;\n\n    public KafkaConsumerClient(string groupId, byte groupConcurrent,\n        IOptions<KafkaOptions> options, IServiceProvider serviceProvider)\n    {\n        _groupId = groupId;\n        _groupConcurrent = groupConcurrent;\n        _semaphore = new SemaphoreSlim(groupConcurrent);\n        _serviceProvider = serviceProvider;\n        _kafkaOptions = options.Value ?? throw new ArgumentNullException(nameof(options));\n    }\n\n    public Func<TransportMessage, object?, Task>? OnMessageCallback { get; set; }\n\n    public Action<LogMessageEventArgs>? OnLogCallback { get; set; }\n\n    public BrokerAddress BrokerAddress => new(\"kafka\", _kafkaOptions.Servers);\n\n    public async Task<ICollection<string>> FetchTopicsAsync(IEnumerable<string> topicNames)\n    {\n        if (topicNames == null) throw new ArgumentNullException(nameof(topicNames));\n\n        var regexTopicNames = topicNames.Select(Helper.WildcardToRegex).ToList();\n\n        var allowAutoCreate = true;\n        if (_kafkaOptions.MainConfig.TryGetValue(\"allow.auto.create.topics\", out var autoCreateValue)\n            && bool.TryParse(autoCreateValue, out var parsedValue))\n        {\n            allowAutoCreate = parsedValue;\n        }\n\n        if (allowAutoCreate)\n        {\n            try\n            {\n                var config = new AdminClientConfig(_kafkaOptions.MainConfig)\n                { BootstrapServers = _kafkaOptions.Servers };\n\n                using var adminClient = new AdminClientBuilder(config).Build();\n\n                await adminClient.CreateTopicsAsync(regexTopicNames.Select(x => new TopicSpecification\n                {\n                    Name = x,\n                    NumPartitions = _kafkaOptions.TopicOptions.NumPartitions,\n                    ReplicationFactor = _kafkaOptions.TopicOptions.ReplicationFactor\n                }));\n            }\n            catch (CreateTopicsException ex) when (ex.Message.Contains(\"already exists\"))\n            {\n            }\n            catch (Exception ex)\n            {\n                var logArgs = new LogMessageEventArgs\n                {\n                    LogType = MqLogType.ConsumeError,\n                    Reason = \"An error was encountered when automatically creating topic! -->\" + ex.Message\n                };\n                OnLogCallback!(logArgs);\n            }\n        }\n\n        return regexTopicNames;\n    }\n\n    public Task SubscribeAsync(IEnumerable<string> topics)\n    {\n        if (topics == null) throw new ArgumentNullException(nameof(topics));\n\n        Connect();\n\n        _consumerClient!.Subscribe(topics);\n\n        return Task.CompletedTask;\n    }\n\n    public async Task ListeningAsync(TimeSpan timeout, CancellationToken cancellationToken)\n    {\n        Connect();\n\n        while (!cancellationToken.IsCancellationRequested)\n        {\n            ConsumeResult<string, byte[]> consumerResult;\n\n            try\n            {\n                consumerResult = _consumerClient!.Consume(timeout);\n\n                if (consumerResult == null) continue;\n                if (consumerResult.IsPartitionEOF || consumerResult.Message.Value == null) continue;\n            }\n            catch (ConsumeException e) when (_kafkaOptions.RetriableErrorCodes.Contains(e.Error.Code))\n            {\n                var logArgs = new LogMessageEventArgs\n                {\n                    LogType = MqLogType.ConsumeRetries,\n                    Reason = e.Error.ToString()\n                };\n                OnLogCallback!(logArgs);\n\n                continue;\n            }\n\n            if (_groupConcurrent > 0)\n            {\n                _semaphore.Wait(cancellationToken);\n                _ = Task.Run(() => ConsumeAsync(consumerResult), cancellationToken).ConfigureAwait(false);\n            }\n            else\n            {\n                await ConsumeAsync(consumerResult);\n            }\n        }\n        // ReSharper disable once FunctionNeverReturns\n    }\n\n    public Task CommitAsync(object? sender)\n    {\n        _consumerClient!.Commit((ConsumeResult<string, byte[]>)sender!);\n        _semaphore.Release();\n        return Task.CompletedTask;\n    }\n\n    public Task RejectAsync(object? sender)\n    {\n        _consumerClient!.Assign(_consumerClient.Assignment);\n        _semaphore.Release();\n        return Task.CompletedTask;\n    }\n\n    public ValueTask DisposeAsync()\n    {\n        _consumerClient?.Dispose();\n        return ValueTask.CompletedTask;\n    }\n\n    public void Connect()\n    {\n        if (_consumerClient != null) return;\n\n        lock (Lock)\n        {\n            if (_consumerClient == null)\n            {\n                var config = new ConsumerConfig(new Dictionary<string, string>(_kafkaOptions.MainConfig));\n                config.BootstrapServers ??= _kafkaOptions.Servers;\n                config.GroupId ??= _groupId;\n                config.AutoOffsetReset ??= AutoOffsetReset.Earliest;\n                config.AllowAutoCreateTopics ??= true;\n                config.EnableAutoCommit ??= false;\n                config.LogConnectionClose ??= false;\n\n                _consumerClient = BuildConsumer(config);\n            }\n        }\n    }\n\n    private async Task ConsumeAsync(ConsumeResult<string, byte[]> consumerResult)\n    {\n        var headers = new Dictionary<string, string?>(consumerResult.Message.Headers.Count);\n        foreach (var header in consumerResult.Message.Headers)\n        {\n            var val = header.GetValueBytes();\n            headers[header.Key] = val != null ? Encoding.UTF8.GetString(val) : null;\n        }\n\n        headers[Headers.Group] = _groupId;\n\n        if (_kafkaOptions.CustomHeadersBuilder != null)\n        {\n            var customHeaders = _kafkaOptions.CustomHeadersBuilder(consumerResult, _serviceProvider);\n            foreach (var customHeader in customHeaders)\n            {\n                headers[customHeader.Key] = customHeader.Value;\n            }\n        }\n\n        var message = new TransportMessage(headers, consumerResult.Message.Value);\n\n        await OnMessageCallback!(message, consumerResult);\n    }\n\n    protected virtual IConsumer<string, byte[]> BuildConsumer(ConsumerConfig config)\n    {\n        return new ConsumerBuilder<string, byte[]>(config)\n            .SetErrorHandler(ConsumerClient_OnConsumeError)\n            .Build();\n    }\n\n    private void ConsumerClient_OnConsumeError(IConsumer<string, byte[]> consumer, Error e)\n    {\n        var logArgs = new LogMessageEventArgs\n        {\n            LogType = MqLogType.ServerConnError,\n            Reason = $\"An error occurred during connect kafka --> {e.Reason}\"\n        };\n        OnLogCallback!(logArgs);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Kafka/KafkaConsumerClientFactory.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.Kafka;\n\npublic class KafkaConsumerClientFactory : IConsumerClientFactory\n{\n    private readonly IOptions<KafkaOptions> _kafkaOptions;\n    private readonly IServiceProvider _serviceProvider;\n\n    public KafkaConsumerClientFactory(IOptions<KafkaOptions> kafkaOptions, IServiceProvider serviceProvider)\n    {\n        _kafkaOptions = kafkaOptions;\n        _serviceProvider = serviceProvider;\n    }\n\n    public virtual Task<IConsumerClient> CreateAsync(string groupName, byte groupConcurrent)\n    {\n        try\n        {\n            return Task.FromResult<IConsumerClient>(new KafkaConsumerClient(groupName, groupConcurrent, _kafkaOptions, _serviceProvider));\n        }\n        catch (Exception e)\n        {\n            throw new BrokerConnectionException(e);\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Kafka/KafkaHeaders.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nnamespace DotNetCore.CAP.Kafka;\n\npublic static class KafkaHeaders\n{\n    public const string KafkaKey = \"cap-kafka-key\";\n}"
  },
  {
    "path": "src/DotNetCore.CAP.MongoDB/CAP.MongoDBCapOptionsExtension.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP.Persistence;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Options;\nusing MongoDB.Driver;\n\nnamespace DotNetCore.CAP.MongoDB;\n\n// ReSharper disable once InconsistentNaming\npublic class MongoDBCapOptionsExtension : ICapOptionsExtension\n{\n    private readonly Action<MongoDBOptions> _configure;\n\n    public MongoDBCapOptionsExtension(Action<MongoDBOptions> configure)\n    {\n        _configure = configure;\n    }\n\n    public void AddServices(IServiceCollection services)\n    {\n        services.AddSingleton(new CapStorageMarkerService(\"MongoDB\"));\n\n        services.AddSingleton<IDataStorage, MongoDBDataStorage>();\n        services.AddSingleton<IStorageInitializer, MongoDBStorageInitializer>();\n\n        services.Configure(_configure);\n\n        //Try to add IMongoClient if does not exists\n        services.TryAddSingleton<IMongoClient>(x =>\n        {\n            var options = x.GetRequiredService<IOptions<MongoDBOptions>>().Value;\n            return new MongoClient(options.DatabaseConnection);\n        });\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.MongoDB/CAP.MongoDBOptions.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nnamespace DotNetCore.CAP.MongoDB;\n\n// ReSharper disable once InconsistentNaming\npublic class MongoDBOptions\n{\n    /// <summary>\n    /// Gets or sets the database name to use when creating database objects.\n    /// Default value: \"cap\"\n    /// </summary>\n    public string DatabaseName { get; set; } = \"cap\";\n\n    /// <summary>\n    /// MongoDB database connection string.\n    /// Default value: \"mongodb://localhost:27017\"\n    /// </summary>\n    public string DatabaseConnection { get; set; } = \"mongodb://localhost:27017\";\n\n    /// <summary>\n    /// MongoDB received message collection name.\n    /// Default value: \"received\"\n    /// </summary>\n    public string ReceivedCollection { get; set; } = \"cap.received\";\n\n    /// <summary>\n    /// MongoDB published message collection name.\n    /// Default value: \"published\"\n    /// </summary>\n    public string PublishedCollection { get; set; } = \"cap.published\";\n\n    /// <summary>\n    /// MongoDB lock collection name.\n    /// Default value: lock\n    /// </summary>\n    public string LockCollection { get; set; } = \"cap.lock\";\n\n\n    internal string Version { get; set; } = default!;\n}"
  },
  {
    "path": "src/DotNetCore.CAP.MongoDB/CAP.Options.Extensions.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP;\nusing DotNetCore.CAP.MongoDB;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.Extensions.DependencyInjection;\n\npublic static class CapOptionsExtensions\n{\n    public static CapOptions UseMongoDB(this CapOptions options)\n    {\n        return options.UseMongoDB(x => { });\n    }\n\n    public static CapOptions UseMongoDB(this CapOptions options, string connectionString)\n    {\n        return options.UseMongoDB(x => { x.DatabaseConnection = connectionString; });\n    }\n\n    public static CapOptions UseMongoDB(this CapOptions options, Action<MongoDBOptions> configure)\n    {\n        if (configure == null) throw new ArgumentNullException(nameof(configure));\n\n        configure += x => x.Version = options.Version;\n\n        options.RegisterExtension(new MongoDBCapOptionsExtension(configure));\n\n        return options;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.MongoDB/DotNetCore.CAP.MongoDB.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\t<Nullable>enable</Nullable>\n    <PackageTags>$(PackageTags);MongoDB</PackageTags>\n  </PropertyGroup>\n   \n  <ItemGroup>\n    <ProjectReference Include=\"..\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"MongoDB.Driver\" Version=\"3.5.0\" />\n  </ItemGroup> \n\n</Project>\n"
  },
  {
    "path": "src/DotNetCore.CAP.MongoDB/ICapTransaction.MongoDB.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Diagnostics;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.DependencyInjection;\nusing MongoDB.Driver;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\npublic class MongoDBCapTransaction : CapTransactionBase\n{\n    public MongoDBCapTransaction(IDispatcher dispatcher)\n        : base(dispatcher)\n    {\n    }\n\n    public override void Commit()\n    {\n        Debug.Assert(DbTransaction != null);\n\n        if (DbTransaction is IClientSessionHandle session) session.CommitTransaction();\n\n        Flush();\n    }\n\n    public override async Task CommitAsync(CancellationToken cancellationToken = default)\n    {\n        Debug.Assert(DbTransaction != null);\n\n        if (DbTransaction is IClientSessionHandle session)\n            await session.CommitTransactionAsync(cancellationToken).ConfigureAwait(false);\n\n        await FlushAsync();\n    }\n\n    public override void Rollback()\n    {\n        Debug.Assert(DbTransaction != null);\n\n        if (DbTransaction is IClientSessionHandle session) session.AbortTransaction();\n    }\n\n    public override async Task RollbackAsync(CancellationToken cancellationToken = default)\n    {\n        Debug.Assert(DbTransaction != null);\n\n        if (DbTransaction is IClientSessionHandle session)\n            await session.AbortTransactionAsync(cancellationToken).ConfigureAwait(false);\n    }\n}\n\npublic static class CapTransactionExtensions\n{\n    public static ICapTransaction Begin(this ICapTransaction transaction,\n        IClientSessionHandle dbTransaction, bool autoCommit = false)\n    {\n        if (!dbTransaction.IsInTransaction) dbTransaction.StartTransaction();\n\n        transaction.DbTransaction = dbTransaction;\n        transaction.AutoCommit = autoCommit;\n\n        return transaction;\n    }\n\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"client\">The <see cref=\"IMongoClient\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <returns>The <see cref=\"IClientSessionHandle\" /> of MongoDB transaction session object.</returns>\n    public static IClientSessionHandle StartTransaction(this IMongoClient client,\n        ICapPublisher publisher, bool autoCommit = false)\n    {\n        var clientSessionHandle = client.StartSession();\n        publisher.Transaction = ActivatorUtilities.CreateInstance<MongoDBCapTransaction>(publisher.ServiceProvider);\n        var capTrans = publisher.Transaction.Begin(clientSessionHandle, autoCommit);\n        return new CapMongoDbClientSessionHandle(capTrans);\n    }\n\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"client\">The <see cref=\"IMongoClient\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <param name=\"options\">The <see cref=\"ClientSessionOptions\"/>.</param>\n    /// <param name=\"cancellationToken\">The <see cref=\"CancellationToken\"/>.</param>\n    /// <returns>The <see cref=\"IClientSessionHandle\" /> of MongoDB transaction session object.</returns>\n    public static Task<IClientSessionHandle> StartTransactionAsync(this IMongoClient client,\n        ICapPublisher publisher, bool autoCommit = false, ClientSessionOptions? options = null, CancellationToken cancellationToken = default)\n    {\n        var clientSessionHandle = client.StartSessionAsync(options, cancellationToken).GetAwaiter().GetResult();\n        publisher.Transaction = ActivatorUtilities.CreateInstance<MongoDBCapTransaction>(publisher.ServiceProvider);\n\n        var capTrans = publisher.Transaction.Begin(clientSessionHandle, autoCommit);\n        return Task.FromResult<IClientSessionHandle>(new CapMongoDbClientSessionHandle(capTrans));\n    }\n\n    /// <summary>\n    /// Start the CAP transaction with a custom session handle\n    /// </summary>\n    /// <param name=\"client\">The <see cref=\"IMongoClient\" />.</param>\n    /// <param name=\"clientSessionHandle\">The <see cref=\"IClientSessionHandle\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <returns>The <see cref=\"IClientSessionHandle\" /> of MongoDB transaction session object.</returns>\n    public static IClientSessionHandle StartTransaction(this IMongoClient _, IClientSessionHandle clientSessionHandle,\n        ICapPublisher publisher, bool autoCommit = false)\n    {\n        publisher.Transaction = ActivatorUtilities.CreateInstance<MongoDBCapTransaction>(publisher.ServiceProvider);\n        var capTrans = publisher.Transaction.Begin(clientSessionHandle, autoCommit);\n        return new CapMongoDbClientSessionHandle(capTrans);\n    }\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP.MongoDB/IClientSessionHandle.CAP.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP;\nusing MongoDB.Bson;\nusing MongoDB.Driver.Core.Bindings;\n\n// ReSharper disable once CheckNamespace\nnamespace MongoDB.Driver;\n\ninternal class CapMongoDbClientSessionHandle : IClientSessionHandle\n{\n    private readonly IClientSessionHandle _sessionHandle;\n    private readonly ICapTransaction _transaction;\n\n    public CapMongoDbClientSessionHandle(ICapTransaction transaction)\n    {\n        _transaction = transaction;\n        _sessionHandle = (IClientSessionHandle)_transaction.DbTransaction!;\n    }\n\n    public void Dispose()\n    {\n        _transaction.Dispose();\n    }\n\n    public void AbortTransaction(CancellationToken cancellationToken = default)\n    {\n        _transaction.Rollback();\n    }\n\n    public Task AbortTransactionAsync(CancellationToken cancellationToken = default)\n    {\n        _transaction.Rollback();\n        return Task.CompletedTask;\n    }\n\n    public void AdvanceClusterTime(BsonDocument newClusterTime)\n    {\n        _sessionHandle.AdvanceClusterTime(newClusterTime);\n    }\n\n    public void AdvanceOperationTime(BsonTimestamp newOperationTime)\n    {\n        _sessionHandle.AdvanceOperationTime(newOperationTime);\n    }\n\n    public void CommitTransaction(CancellationToken cancellationToken = default)\n    {\n        _transaction.Commit();\n    }\n\n    public Task CommitTransactionAsync(CancellationToken cancellationToken = default)\n    {\n        _transaction.Commit();\n        return Task.CompletedTask;\n    }\n\n    public void StartTransaction(TransactionOptions? transactionOptions = null)\n    {\n        _sessionHandle.StartTransaction(transactionOptions);\n    }\n\n    public IMongoClient Client => _sessionHandle.Client;\n    public BsonDocument ClusterTime => _sessionHandle.ClusterTime;\n    public bool IsImplicit => _sessionHandle.IsImplicit;\n    public bool IsInTransaction => _sessionHandle.IsInTransaction;\n    public BsonTimestamp OperationTime => _sessionHandle.OperationTime;\n    public ClientSessionOptions Options => _sessionHandle.Options;\n    public IServerSession ServerSession => _sessionHandle.ServerSession;\n    public ICoreSessionHandle WrappedCoreSession => _sessionHandle.WrappedCoreSession;\n\n    public IClientSessionHandle Fork()\n    {\n        return _sessionHandle.Fork();\n    }\n\n    public TResult WithTransaction<TResult>(Func<IClientSessionHandle, CancellationToken, TResult> callback,\n        TransactionOptions? transactionOptions = null, CancellationToken cancellationToken = default)\n    {\n        return _sessionHandle.WithTransaction(callback, transactionOptions, cancellationToken);\n    }\n\n    public Task<TResult> WithTransactionAsync<TResult>(\n        Func<IClientSessionHandle, CancellationToken, Task<TResult>> callbackAsync,\n        TransactionOptions? transactionOptions = null, CancellationToken cancellationToken = default)\n    {\n        return _sessionHandle.WithTransactionAsync(callbackAsync, transactionOptions, cancellationToken);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.MongoDB/IDataStorage.MongoDB.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Monitoring;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Serialization;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing MongoDB.Bson;\nusing MongoDB.Driver;\n\nnamespace DotNetCore.CAP.MongoDB;\n\npublic class MongoDBDataStorage : IDataStorage\n{\n    private readonly IOptions<CapOptions> _capOptions;\n    private readonly IMongoClient _client;\n    private readonly IMongoDatabase _database;\n    private readonly IOptions<MongoDBOptions> _options;\n    private readonly ISerializer _serializer;\n    private readonly ISnowflakeId _snowflakeId;\n    private readonly ILogger _logger;\n\n    public MongoDBDataStorage(\n        IOptions<CapOptions> capOptions,\n        IOptions<MongoDBOptions> options,\n        IMongoClient client,\n        ISerializer serializer,\n        ISnowflakeId snowflakeId,\n        ILogger<MongoDBDataStorage> logger)\n    {\n        _capOptions = capOptions;\n        _options = options;\n        _client = client;\n        _database = _client.GetDatabase(_options.Value.DatabaseName);\n        _serializer = serializer;\n        _snowflakeId = snowflakeId;\n        _logger = logger;\n    }\n\n    public async Task<bool> AcquireLockAsync(string key, TimeSpan ttl, string instance,\n        CancellationToken token = default)\n    {\n\n        var collection = _database.GetCollection<Lock>(_options.Value.LockCollection);\n        using var session = await _client.StartSessionAsync(cancellationToken: token).ConfigureAwait(false);\n        var transactionOptions =\n            new TransactionOptions(ReadConcern.Majority, ReadPreference.Primary, WriteConcern.WMajority);\n\n        try\n        {\n            var result = await session.WithTransactionAsync(async (handle, cancellationToken) =>\n            {\n                var opResult = await collection.UpdateOneAsync(handle,\n                    model => model.Key == key && model.LastLockTime < DateTime.Now.Subtract(ttl),\n                    Builders<Lock>.Update.Set(model => model.Instance, instance)\n                        .Set(model => model.LastLockTime, DateTime.Now), null, cancellationToken);\n                var isAcquired = opResult.IsModifiedCountAvailable && opResult.ModifiedCount > 0;\n                return isAcquired;\n            }, transactionOptions, token);\n\n            return result;\n        }\n        catch (Exception ex)\n        {\n            _logger.LogWarning(\n                ex, \"Failed to acquire lock for key '{Key}' with instance '{Instance}'.\", key, instance);\n            return false;\n        }\n    }\n\n    public async Task ReleaseLockAsync(string key, string instance, CancellationToken token = default)\n    {\n        var collection = _database.GetCollection<Lock>(_options.Value.LockCollection);\n        await collection.UpdateOneAsync(\n            model => model.Key == key && model.Instance == instance,\n            Builders<Lock>.Update.Set(model => model.Instance, \"\")\n                .Set(model => model.LastLockTime, DateTime.MinValue), null, token).ConfigureAwait(false);\n    }\n\n    public async Task RenewLockAsync(string key, TimeSpan ttl, string instance, CancellationToken token = default)\n    {\n        var collection = _database.GetCollection<Lock>(_options.Value.LockCollection);\n        var filter = Builders<Lock>.Filter.Where(it => it.Key == key && it.Instance == instance);\n        var pipeline = new EmptyPipelineDefinition<Lock>()\n            .AppendStage<Lock, Lock, Lock>(\n                $\"{{$set:{{LastLockTime:{{$add:[ \\\"$LastLockTime\\\",  {ttl.TotalMilliseconds} ]}}}}}}\");\n        var update = Builders<Lock>.Update.Pipeline(pipeline);\n        await collection.UpdateOneAsync(filter, update, cancellationToken: token).ConfigureAwait(false);\n    }\n\n    public async Task ChangePublishStateToDelayedAsync(string[] ids)\n    {\n        var collection = _database.GetCollection<PublishedMessage>(_options.Value.PublishedCollection);\n        var updateDef = Builders<PublishedMessage>.Update.Set(x => x.StatusName, nameof(StatusName.Delayed));\n        var filter = Builders<PublishedMessage>.Filter.In(x => x.Id, ids.Select(long.Parse));\n\n        await collection.UpdateManyAsync(filter, updateDef).ConfigureAwait(false);\n    }\n\n    public async Task ChangePublishStateAsync(MediumMessage message, StatusName state, object? transaction = null)\n    {\n        var collection = _database.GetCollection<PublishedMessage>(_options.Value.PublishedCollection);\n\n        var updateDef = Builders<PublishedMessage>.Update\n            .Set(x => x.Content, _serializer.Serialize(message.Origin))\n            .Set(x => x.Retries, message.Retries)\n            .Set(x => x.ExpiresAt, message.ExpiresAt)\n            .Set(x => x.StatusName, state.ToString(\"G\"));\n\n        if (transaction != null)\n        {\n            var session = transaction as IClientSessionHandle;\n            await collection.UpdateOneAsync(session, x => x.Id == long.Parse(message.DbId), updateDef)\n                .ConfigureAwait(false);\n        }\n        else\n        {\n            await collection.UpdateOneAsync(x => x.Id == long.Parse(message.DbId), updateDef).ConfigureAwait(false);\n        }\n    }\n\n    public async Task ChangeReceiveStateAsync(MediumMessage message, StatusName state)\n    {\n        var collection = _database.GetCollection<ReceivedMessage>(_options.Value.ReceivedCollection);\n\n        var updateDef = Builders<ReceivedMessage>.Update\n            .Set(x => x.Content, _serializer.Serialize(message.Origin))\n            .Set(x => x.Retries, message.Retries)\n            .Set(x => x.ExpiresAt, message.ExpiresAt)\n            .Set(x => x.StatusName, state.ToString(\"G\"));\n\n        await collection.UpdateOneAsync(x => x.Id == long.Parse(message.DbId), updateDef).ConfigureAwait(false);\n    }\n\n    public async Task<MediumMessage> StoreMessageAsync(string name, Message content, object? dbTransaction = null)\n    {\n        var insertOptions = new InsertOneOptions { BypassDocumentValidation = false };\n\n        var message = new MediumMessage\n        {\n            DbId = content.GetId(),\n            Origin = content,\n            Content = _serializer.Serialize(content),\n            Added = DateTime.Now,\n            ExpiresAt = null,\n            Retries = 0\n        };\n\n        var collection = _database.GetCollection<PublishedMessage>(_options.Value.PublishedCollection);\n\n        var store = new PublishedMessage\n        {\n            Id = long.Parse(message.DbId),\n            Name = name,\n            Content = message.Content,\n            Added = message.Added,\n            StatusName = nameof(StatusName.Scheduled),\n            ExpiresAt = message.ExpiresAt,\n            Retries = message.Retries,\n            Version = _options.Value.Version\n        };\n\n        if (dbTransaction == null)\n        {\n            await collection.InsertOneAsync(store, insertOptions).ConfigureAwait(false);\n        }\n        else\n        {\n            var dbTrans = dbTransaction as IClientSessionHandle;\n            await collection.InsertOneAsync(dbTrans, store, insertOptions).ConfigureAwait(false);\n        }\n\n        return message;\n    }\n\n    public async Task StoreReceivedExceptionMessageAsync(string name, string group, string content)\n    {\n        var collection = _database.GetCollection<ReceivedMessage>(_options.Value.ReceivedCollection);\n\n        var store = new ReceivedMessage\n        {\n            Id = _snowflakeId.NextId(),\n            Group = group,\n            Name = name,\n            Content = content,\n            Added = DateTime.Now,\n            ExpiresAt = DateTime.Now.AddSeconds(_capOptions.Value.FailedMessageExpiredAfter),\n            Retries = _capOptions.Value.FailedRetryCount,\n            Version = _capOptions.Value.Version,\n            StatusName = nameof(StatusName.Failed)\n        };\n\n        await collection.InsertOneAsync(store).ConfigureAwait(false);\n    }\n\n    public async Task<MediumMessage> StoreReceivedMessageAsync(string name, string group, Message message)\n    {\n        var mdMessage = new MediumMessage\n        {\n            DbId = _snowflakeId.NextId().ToString(),\n            Origin = message,\n            Added = DateTime.Now,\n            ExpiresAt = null,\n            Retries = 0\n        };\n        var content = _serializer.Serialize(mdMessage.Origin);\n\n        var collection = _database.GetCollection<ReceivedMessage>(_options.Value.ReceivedCollection);\n\n        var store = new ReceivedMessage\n        {\n            Id = long.Parse(mdMessage.DbId),\n            Group = group,\n            Name = name,\n            Content = content,\n            Added = mdMessage.Added,\n            ExpiresAt = mdMessage.ExpiresAt,\n            Retries = mdMessage.Retries,\n            Version = _capOptions.Value.Version,\n            StatusName = nameof(StatusName.Scheduled)\n        };\n\n        await collection.InsertOneAsync(store).ConfigureAwait(false);\n\n        return mdMessage;\n    }\n\n    public async Task<int> DeleteExpiresAsync(string collection, DateTime timeout, int batchCount = 1000,\n        CancellationToken cancellationToken = default)\n    {\n        if (collection == _options.Value.PublishedCollection)\n        {\n            var publishedCollection = _database.GetCollection<PublishedMessage>(_options.Value.PublishedCollection);\n            var ret = await publishedCollection\n                .DeleteManyAsync(\n                    x => x.ExpiresAt < timeout && (x.StatusName == nameof(StatusName.Succeeded) ||\n                                                   x.StatusName == nameof(StatusName.Failed)), cancellationToken)\n                .ConfigureAwait(false);\n            return (int)ret.DeletedCount;\n        }\n        else\n        {\n            var receivedCollection = _database.GetCollection<ReceivedMessage>(_options.Value.ReceivedCollection);\n            var ret = await receivedCollection\n                .DeleteManyAsync(\n                    x => x.ExpiresAt < timeout && (x.StatusName == nameof(StatusName.Succeeded) ||\n                                                   x.StatusName == nameof(StatusName.Failed)), cancellationToken)\n                .ConfigureAwait(false);\n            return (int)ret.DeletedCount;\n        }\n    }\n\n    public async Task<IEnumerable<MediumMessage>> GetPublishedMessagesOfNeedRetry(TimeSpan lookbackSeconds)\n    {\n        var fourMinAgo = DateTime.Now.Subtract(lookbackSeconds);\n        var collection = _database.GetCollection<PublishedMessage>(_options.Value.PublishedCollection);\n        var queryResult = await collection\n            .Find(x => x.Retries < _capOptions.Value.FailedRetryCount\n                       && x.Added < fourMinAgo\n                       && x.Version == _capOptions.Value.Version\n                       && (x.StatusName == nameof(StatusName.Failed) ||\n                           x.StatusName == nameof(StatusName.Scheduled)))\n            .Limit(200)\n            .ToListAsync().ConfigureAwait(false);\n        return queryResult.Select(x => new MediumMessage\n        {\n            DbId = x.Id.ToString(),\n            Origin = _serializer.Deserialize(x.Content)!,\n            Retries = x.Retries,\n            Added = x.Added\n        }).ToList();\n    }\n\n    public async Task<IEnumerable<MediumMessage>> GetReceivedMessagesOfNeedRetry(TimeSpan lookbackSeconds)\n    {\n        var fourMinAgo = DateTime.Now.Subtract(lookbackSeconds);\n        var collection = _database.GetCollection<ReceivedMessage>(_options.Value.ReceivedCollection);\n        var queryResult = await collection\n            .Find(x => x.Retries < _capOptions.Value.FailedRetryCount\n                       && x.Added < fourMinAgo\n                       && x.Version == _capOptions.Value.Version\n                       && (x.StatusName == nameof(StatusName.Failed) ||\n                           x.StatusName == nameof(StatusName.Scheduled)))\n            .Limit(200)\n            .ToListAsync().ConfigureAwait(false);\n        return queryResult.Select(x => new MediumMessage\n        {\n            DbId = x.Id.ToString(),\n            Origin = _serializer.Deserialize(x.Content)!,\n            Retries = x.Retries,\n            Added = x.Added\n        }).ToList();\n    }\n\n    public async Task<int> DeleteReceivedMessageAsync(long id)\n    {\n        var collection = _database.GetCollection<ReceivedMessage>(_options.Value.ReceivedCollection);\n        var deleteResult = await collection.DeleteOneAsync(x => x.Id == id).ConfigureAwait(false);\n        return (int)deleteResult.DeletedCount;\n    }\n\n    public async Task<int> DeletePublishedMessageAsync(long id)\n    {\n        var collection = _database.GetCollection<PublishedMessage>(_options.Value.PublishedCollection);\n        var deleteResult = await collection.DeleteOneAsync(x => x.Id == id).ConfigureAwait(false);\n        return (int)deleteResult.DeletedCount;\n    }\n\n    public async Task ScheduleMessagesOfDelayedAsync(Func<object, IEnumerable<MediumMessage>, Task> scheduleTask,\n        CancellationToken token = default)\n    {\n        var collection = _database.GetCollection<PublishedMessage>(_options.Value.PublishedCollection);\n\n        var update = Builders<PublishedMessage>.Update.Set(x => x._lockToken, ObjectId.GenerateNewId());\n\n        var filter = Builders<PublishedMessage>.Filter.Where(x => x.Version == _capOptions.Value.Version\n                                                                  && ((x.StatusName == nameof(StatusName.Delayed) &&\n                                                                       x.ExpiresAt < DateTime.Now.AddMinutes(2))\n                                                                      ||\n                                                                      (x.StatusName == nameof(StatusName.Queued) &&\n                                                                       x.ExpiresAt < DateTime.Now.AddMinutes(-1)))\n        );\n\n        using var timeoutTs = new CancellationTokenSource(TimeSpan.FromSeconds(10));\n        using var linkedTs = CancellationTokenSource.CreateLinkedTokenSource(timeoutTs.Token, token);\n\n        using var session = await _client.StartSessionAsync(cancellationToken: token).ConfigureAwait(false);\n        var transactionOptions =\n            new TransactionOptions(ReadConcern.Majority, ReadPreference.Primary, WriteConcern.WMajority);\n        session.StartTransaction(transactionOptions);\n\n        while (!timeoutTs.IsCancellationRequested)\n        {\n            try\n            {\n                try\n                {\n                    await collection.UpdateManyAsync(session, filter, update, cancellationToken: linkedTs.Token)\n                        .ConfigureAwait(false);\n\n                    var queryResult = await collection.Find(session, filter)\n                        .Limit(_capOptions.Value.SchedulerBatchSize)\n                        .ToListAsync(linkedTs.Token)\n                        .ConfigureAwait(false);\n\n                    var result = queryResult.Select(x => new MediumMessage\n                    {\n                        DbId = x.Id.ToString(),\n                        Origin = _serializer.Deserialize(x.Content)!,\n                        Retries = x.Retries,\n                        Added = x.Added,\n                        ExpiresAt = x.ExpiresAt\n                    }).ToList();\n\n                    await scheduleTask(session, result).ConfigureAwait(false);\n\n                    await session.CommitTransactionAsync(token).ConfigureAwait(false);\n\n                    break;\n                }\n                catch (MongoCommandException e) when (e.HasErrorLabel(\"TransientTransactionError\") &&\n                                                      e.CodeName == \"WriteConflict\")\n                {\n                    await session.AbortTransactionAsync(linkedTs.Token).ConfigureAwait(false);\n                    await Task.Delay(TimeSpan.FromMilliseconds(Random.Shared.Next(5, 20)), linkedTs.Token)\n                        .ConfigureAwait(false);\n                    session.StartTransaction(transactionOptions);\n                }\n            }\n            catch (Exception ex) when (ex is OperationCanceledException && timeoutTs.IsCancellationRequested)\n            {\n                break;\n            }\n        }\n    }\n\n    public IMonitoringApi GetMonitoringApi()\n    {\n        return new MongoDBMonitoringApi(_client, _options, _serializer);\n    }\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP.MongoDB/IMonitoringApi.MongoDB.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Monitoring;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Serialization;\nusing Microsoft.Extensions.Options;\nusing MongoDB.Driver;\n\nnamespace DotNetCore.CAP.MongoDB;\n\npublic class MongoDBMonitoringApi : IMonitoringApi\n{\n    private readonly IMongoDatabase _database;\n    private readonly MongoDBOptions _options;\n    private readonly ISerializer _serializer;\n\n    public MongoDBMonitoringApi(IMongoClient client, IOptions<MongoDBOptions> options, ISerializer serializer)\n    {\n        var mongoClient = client ?? throw new ArgumentNullException(nameof(client));\n        _options = options.Value ?? throw new ArgumentNullException(nameof(options));\n        _serializer = serializer ?? throw new ArgumentNullException(nameof(serializer));\n        _database = mongoClient.GetDatabase(_options.DatabaseName);\n    }\n\n    public async Task<MediumMessage?> GetPublishedMessageAsync(long id)\n    {\n        var collection = _database.GetCollection<PublishedMessage>(_options.PublishedCollection);\n        var message = await collection.Find(x => x.Id == id).FirstOrDefaultAsync().ConfigureAwait(false);\n        return new MediumMessage\n        {\n            Added = message.Added,\n            Origin = _serializer.Deserialize(message.Content)!,\n            Content = message.Content,\n            DbId = message.Id.ToString(),\n            ExpiresAt = message.ExpiresAt,\n            Retries = message.Retries\n        };\n    }\n\n    public async Task<MediumMessage?> GetReceivedMessageAsync(long id)\n    {\n        var collection = _database.GetCollection<ReceivedMessage>(_options.ReceivedCollection);\n        var message = await collection.Find(x => x.Id == id).FirstOrDefaultAsync().ConfigureAwait(false);\n        return new MediumMessage\n        {\n            Added = message.Added,\n            Origin = _serializer.Deserialize(message.Content)!,\n            Content = message.Content,\n            DbId = message.Id.ToString(),\n            ExpiresAt = message.ExpiresAt,\n            Retries = message.Retries\n        };\n    }\n\n    public async Task<StatisticsDto> GetStatisticsAsync()\n    {\n        var publishedCollection = _database.GetCollection<PublishedMessage>(_options.PublishedCollection);\n        var receivedCollection = _database.GetCollection<ReceivedMessage>(_options.ReceivedCollection);\n\n        var statistics = new StatisticsDto\n        {\n            PublishedSucceeded =\n                (int)await publishedCollection.CountDocumentsAsync(x => x.StatusName == nameof(StatusName.Succeeded))\n                    .ConfigureAwait(false),\n            PublishedFailed =\n                (int)await publishedCollection.CountDocumentsAsync(x => x.StatusName == nameof(StatusName.Failed))\n                    .ConfigureAwait(false),\n            ReceivedSucceeded =\n                (int)await receivedCollection.CountDocumentsAsync(x => x.StatusName == nameof(StatusName.Succeeded))\n                    .ConfigureAwait(false),\n            ReceivedFailed =\n                (int)await receivedCollection.CountDocumentsAsync(x => x.StatusName == nameof(StatusName.Failed))\n                    .ConfigureAwait(false),\n            PublishedDelayed =\n                (int)await publishedCollection.CountDocumentsAsync(x => x.StatusName == nameof(StatusName.Delayed))\n                    .ConfigureAwait(false)\n        };\n        return statistics;\n    }\n\n    public Task<IDictionary<DateTime, int>> HourlyFailedJobs(MessageType type)\n    {\n        return GetHourlyTimelineStats(type, nameof(StatusName.Failed));\n    }\n\n    public Task<IDictionary<DateTime, int>> HourlySucceededJobs(MessageType type)\n    {\n        return GetHourlyTimelineStats(type, nameof(StatusName.Succeeded));\n    }\n\n    public Task<PagedQueryResult<MessageDto>> GetMessagesAsync(MessageQueryDto queryDto)\n    {\n        return queryDto.MessageType == MessageType.Publish\n            ? FindPublishedMessages(queryDto)\n            : FindReceivedMessages(queryDto);\n    }\n\n    public ValueTask<int> PublishedFailedCount()\n    {\n        return GetNumberOfMessage(_options.PublishedCollection, nameof(StatusName.Failed));\n    }\n\n    public ValueTask<int> PublishedSucceededCount()\n    {\n        return GetNumberOfMessage(_options.PublishedCollection, nameof(StatusName.Succeeded));\n    }\n\n    public ValueTask<int> ReceivedFailedCount()\n    {\n        return GetNumberOfMessage(_options.ReceivedCollection, nameof(StatusName.Failed));\n    }\n\n    public ValueTask<int> ReceivedSucceededCount()\n    {\n        return GetNumberOfMessage(_options.ReceivedCollection, nameof(StatusName.Succeeded));\n    }\n\n    private async Task<PagedQueryResult<MessageDto>> FindReceivedMessages(MessageQueryDto queryDto)\n    {\n        var collection = _database.GetCollection<ReceivedMessage>(_options.ReceivedCollection);\n        var builder = Builders<ReceivedMessage>.Filter;\n        var filter = builder.Empty;\n        if (!string.IsNullOrEmpty(queryDto.StatusName))\n            filter &= builder.Regex(x => x.StatusName, $\"/{queryDto.StatusName}/i\");\n\n        if (!string.IsNullOrEmpty(queryDto.Name)) filter &= builder.Eq(x => x.Name, queryDto.Name);\n\n        if (!string.IsNullOrEmpty(queryDto.Group)) filter &= builder.Eq(x => x.Group, queryDto.Group);\n\n        if (!string.IsNullOrEmpty(queryDto.Content))\n            filter &= builder.Regex(x => x.Content, $\".*{queryDto.Content}.*\");\n\n        var queryItems = await collection.Find(filter)\n            .SortByDescending(x => x.Added)\n            .Skip(queryDto.PageSize * queryDto.CurrentPage)\n            .Limit(queryDto.PageSize)\n            .ToListAsync().ConfigureAwait(false);\n        var items = queryItems.Select(x => new MessageDto\n            {\n                Id = x.Id.ToString(),\n                Version = x.Version.ToString(),\n                Group = x.Group,\n                Name = x.Name,\n                Content = x.Content,\n                Added = x.Added.ToLocalTime(),\n                ExpiresAt = x.ExpiresAt?.ToLocalTime(),\n                Retries = x.Retries,\n                StatusName = x.StatusName\n            })\n            .ToList();\n\n        var count = await collection.CountDocumentsAsync(filter).ConfigureAwait(false);\n\n        return new PagedQueryResult<MessageDto>\n            { Items = items, PageIndex = queryDto.CurrentPage, PageSize = queryDto.PageSize, Totals = count };\n    }\n\n    private async Task<PagedQueryResult<MessageDto>> FindPublishedMessages(MessageQueryDto queryDto)\n    {\n        var collection = _database.GetCollection<PublishedMessage>(_options.PublishedCollection);\n\n        var builder = Builders<PublishedMessage>.Filter;\n        var filter = builder.Empty;\n        if (!string.IsNullOrEmpty(queryDto.StatusName))\n            filter &= builder.Regex(x => x.StatusName, $\"/{queryDto.StatusName}/i\");\n\n        if (!string.IsNullOrEmpty(queryDto.Name)) filter &= builder.Eq(x => x.Name, queryDto.Name);\n\n        if (!string.IsNullOrEmpty(queryDto.Content))\n            filter &= builder.Regex(x => x.Content, $\".*{queryDto.Content}.*\");\n\n        var queryItems = await collection.Find(filter)\n            .SortByDescending(x => x.Added)\n            .Skip(queryDto.PageSize * queryDto.CurrentPage)\n            .Limit(queryDto.PageSize)\n            .ToListAsync().ConfigureAwait(false);\n        var items = queryItems\n            .Select(x => new MessageDto\n            {\n                Id = x.Id.ToString(),\n                Version = x.Version.ToString(),\n                Group = null,\n                Name = x.Name,\n                Content = x.Content,\n                Added = x.Added.ToLocalTime(),\n                ExpiresAt = x.ExpiresAt?.ToLocalTime(),\n                Retries = x.Retries,\n                StatusName = x.StatusName\n            })\n            .ToList();\n\n        var count = await collection.CountDocumentsAsync(filter).ConfigureAwait(false);\n\n        return new PagedQueryResult<MessageDto>\n            { Items = items, PageIndex = queryDto.CurrentPage, PageSize = queryDto.PageSize, Totals = count };\n    }\n\n    private ValueTask<int> GetNumberOfMessage(string collectionName, string statusName)\n    {\n        return collectionName.Equals(_options.PublishedCollection, StringComparison.InvariantCultureIgnoreCase)\n            ? GetNumberOfPublishedMessages(statusName)\n            : GetNumberOfReceivedMessages(statusName);\n    }\n\n    private async ValueTask<int> GetNumberOfReceivedMessages(string statusName)\n    {\n        var collection = _database.GetCollection<ReceivedMessage>(_options.ReceivedCollection);\n        var filter = Builders<ReceivedMessage>.Filter.Eq(x => x.StatusName, statusName);\n        var count = await collection.CountDocumentsAsync(filter).ConfigureAwait(false);\n        return int.Parse(count.ToString());\n    }\n\n    private async ValueTask<int> GetNumberOfPublishedMessages(string statusName)\n    {\n        var collection = _database.GetCollection<PublishedMessage>(_options.PublishedCollection);\n        var filter = Builders<PublishedMessage>.Filter.Eq(x => x.StatusName, statusName);\n        var count = await collection.CountDocumentsAsync(filter).ConfigureAwait(false);\n        return int.Parse(count.ToString());\n    }\n\n    private Task<IDictionary<DateTime, int>> GetHourlyTimelineStats(MessageType type, string statusName)\n    {\n        var endDate = DateTime.UtcNow;\n\n        var published = _database.GetCollection<PublishedMessage>(_options.PublishedCollection).AsQueryable();\n        var received = _database.GetCollection<PublishedMessage>(_options.PublishedCollection).AsQueryable();\n\n        var result = type == MessageType.Publish\n            ? published.Where(x => x.Added > endDate.AddHours(-24) && x.StatusName == statusName)\n                .GroupBy(x => new\n                {\n                    x.Added.Year,\n                    x.Added.Month,\n                    x.Added.Day,\n                    x.Added.Hour\n                })\n                .Select(kv => new { kv.Key, Count = kv.Count() })\n                .ToList()\n            : received.Where(x => x.Added > endDate.AddHours(-24) && x.StatusName == statusName)\n                .GroupBy(x => new\n                {\n                    x.Added.Year,\n                    x.Added.Month,\n                    x.Added.Day,\n                    x.Added.Hour\n                })\n                .Select(kv => new { kv.Key, Count = kv.Count() })\n                .ToList();\n\n        var dic = new Dictionary<DateTime, int>();\n        for (var i = 0; i < 24; i++)\n        {\n            dic.Add(DateTime.Parse(endDate.ToLocalTime().ToString(\"yyyy-MM-dd HH:00:00\")), 0);\n            endDate = endDate.AddHours(-1);\n        }\n\n        result.ForEach(d =>\n        {\n            var dateTime = new DateTime(d.Key.Year, d.Key.Month, d.Key.Day, d.Key.Hour, 0, 0);\n            dic[dateTime.ToLocalTime()] = d.Count;\n        });\n\n        return Task.FromResult<IDictionary<DateTime, int>>(dic);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.MongoDB/IStorageInitializer.MongoDB.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Persistence;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing MongoDB.Driver;\n\nnamespace DotNetCore.CAP.MongoDB;\n\npublic class MongoDBStorageInitializer : IStorageInitializer\n{\n    private readonly IOptions<CapOptions> _capOptions;\n    private readonly IMongoClient _client;\n    private readonly ILogger _logger;\n    private readonly IOptions<MongoDBOptions> _options;\n\n    public MongoDBStorageInitializer(\n        ILogger<MongoDBStorageInitializer> logger,\n        IMongoClient client,\n        IOptions<MongoDBOptions> options, IOptions<CapOptions> capOptions)\n    {\n        _capOptions = capOptions;\n        _options = options;\n        _logger = logger;\n        _client = client;\n    }\n\n    public string GetPublishedTableName()\n    {\n        return _options.Value.PublishedCollection;\n    }\n\n    public string GetReceivedTableName()\n    {\n        return _options.Value.ReceivedCollection;\n    }\n\n    public string GetLockTableName()\n    {\n        return _options.Value.LockCollection;\n    }\n\n    public async Task InitializeAsync(CancellationToken cancellationToken)\n    {\n        if (cancellationToken.IsCancellationRequested) return;\n\n        var options = _options.Value;\n        var database = _client.GetDatabase(options.DatabaseName);\n        var names =\n            (await database.ListCollectionNamesAsync(cancellationToken: cancellationToken).ConfigureAwait(false))\n            .ToList();\n\n        if (names.All(n => n != options.ReceivedCollection))\n            await database.CreateCollectionAsync(options.ReceivedCollection, cancellationToken: cancellationToken)\n                .ConfigureAwait(false);\n\n        if (names.All(n => n != options.PublishedCollection))\n            await database.CreateCollectionAsync(options.PublishedCollection, cancellationToken: cancellationToken)\n                .ConfigureAwait(false);\n\n        if (_capOptions.Value.UseStorageLock && names.All(n => n != options.LockCollection))\n            await database.CreateCollectionAsync(options.LockCollection, cancellationToken: cancellationToken)\n                .ConfigureAwait(false);\n\n        await Task.WhenAll(\n            DropReceivedMessageDeprecatedIndexesAsync(), \n            DropPublishedMessageDeprecatedIndexesAsync()).ConfigureAwait(false);\n\n        await Task.WhenAll(\n            CreateReceivedMessageIndexesAsync(),\n            CreatePublishedMessageIndexesAsync()).ConfigureAwait(false);\n\n        if (_capOptions.Value.UseStorageLock)\n        {\n            await database.GetCollection<Lock>(options.LockCollection)\n                .UpdateOneAsync(it => it.Key == $\"publish_retry_{_capOptions.Value.Version}\",\n                    Builders<Lock>.Update.Set(model => model.Key, $\"publish_retry_{_capOptions.Value.Version}\")\n                        .SetOnInsert(model => model.LastLockTime, DateTime.MinValue),\n                    new UpdateOptions { IsUpsert = true }, cancellationToken);\n\n            await database.GetCollection<Lock>(options.LockCollection)\n                .UpdateOneAsync(it => it.Key == $\"received_retry_{_capOptions.Value.Version}\",\n                    Builders<Lock>.Update.Set(model => model.Key, $\"received_retry_{_capOptions.Value.Version}\")\n                        .SetOnInsert(model => model.LastLockTime, DateTime.MinValue),\n                    new UpdateOptions { IsUpsert = true }, cancellationToken);\n        }\n\n        _logger.LogDebug(\"Ensuring all create database tables script are applied.\");\n\n        async Task CreateReceivedMessageIndexesAsync()\n        {\n            IndexKeysDefinitionBuilder<ReceivedMessage> builder = Builders<ReceivedMessage>.IndexKeys;\n            var col = database.GetCollection<ReceivedMessage>(options.ReceivedCollection);\n\n            CreateIndexModel<ReceivedMessage>[] indexes =\n            {\n                new(builder.Ascending(x => x.Name)),\n                new(builder.Ascending(x => x.Added)),\n                new(builder.Ascending(x => x.ExpiresAt)),\n                new(builder.Ascending(x => x.Retries)),\n                new(builder.Ascending(x => x.Version)),\n                new(builder.Ascending(x => x.StatusName).Ascending(x => x.ExpiresAt))\n            };\n\n            await col.Indexes.CreateManyAsync(indexes, cancellationToken);\n        }\n\n        async Task CreatePublishedMessageIndexesAsync()\n        {\n            IndexKeysDefinitionBuilder<PublishedMessage> builder = Builders<PublishedMessage>.IndexKeys;\n            var col = database.GetCollection<PublishedMessage>(options.PublishedCollection);\n\n            CreateIndexModel<PublishedMessage>[] indexes =\n            {\n                new(builder.Ascending(x => x.Name)),\n                new(builder.Ascending(x => x.Added)),\n                new(builder.Ascending(x => x.ExpiresAt)),\n                new(builder.Ascending(x => x.Retries)),\n                new(builder.Ascending(x => x.Version)),\n                new(builder.Ascending(x => x.StatusName).Ascending(x => x.ExpiresAt))\n            };\n\n            await col.Indexes.CreateManyAsync(indexes, cancellationToken);\n        }\n\n        async Task DropReceivedMessageDeprecatedIndexesAsync()\n        {\n            var obsoleteIndexes = new HashSet<string> { \"Name\", \"Added\", \"ExpiresAt\", \"StatusName\", \"Retries\", \"Version\" };\n           \n            var col = database.GetCollection<ReceivedMessage>(options.ReceivedCollection);\n           \n            await DropIndexesAsync(col, obsoleteIndexes);\n        }\n\n        async Task DropPublishedMessageDeprecatedIndexesAsync()\n        {\n            var obsoleteIndexes = new HashSet<string> { \"Name\", \"Added\", \"ExpiresAt\", \"StatusName\", \"Retries\", \"Version\" };\n            \n            var col = database.GetCollection<PublishedMessage>(options.PublishedCollection);\n           \n            await DropIndexesAsync(col, obsoleteIndexes);\n            \n        }\n\n        async Task DropIndexesAsync<T>(IMongoCollection<T> col, ISet<string> obsoleteIndexes)\n        {\n            using var cursor = await col.Indexes.ListAsync(cancellationToken);\n            var indexList = await cursor.ToListAsync(cancellationToken);\n\n            foreach (var index in indexList)\n            {\n                var indexName = index[\"name\"].AsString;\n                if (!obsoleteIndexes.Contains(indexName)) continue;\n\n                try\n                {\n                    await col.Indexes.DropOneAsync(indexName, cancellationToken);\n                }\n                catch (MongoCommandException ex) when (ex.CodeName == \"IndexNotFound\")\n                {\n                    _logger.LogWarning(\n                        \"Index '{IndexName}' on collection '{CollectionName}' was not found when attempting to drop it. \" +\n                        \"This may indicate concurrent initialization or an unexpected state. Verify deployment strategy if this happens repeatedly.\",\n                        indexName, col.CollectionNamespace.CollectionName);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP.MongoDB/StorageMessage.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing MongoDB.Bson;\nusing MongoDB.Bson.Serialization.Attributes;\nusing MongoDB.Bson.Serialization.IdGenerators;\n\nnamespace DotNetCore.CAP.MongoDB;\n\ninternal class ReceivedMessage\n{\n    public long Id { get; set; }\n\n    public string Version { get; set; } = default!;\n\n    public string Group { get; set; } = default!;\n\n    public string Name { get; set; } = default!;\n\n    public string Content { get; set; } = default!;\n\n    [BsonDateTimeOptions(Kind = DateTimeKind.Local)]\n    public DateTime Added { get; set; }\n\n    [BsonDateTimeOptions(Kind = DateTimeKind.Local)]\n    public DateTime? ExpiresAt { get; set; }\n\n    public int Retries { get; set; }\n\n    public string StatusName { get; set; } = default!;\n}\n\ninternal class PublishedMessage\n{\n    public long Id { get; set; }\n\n    public string Version { get; set; } = default!;\n\n    public string Name { get; set; } = default!;\n\n    public string Content { get; set; } = default!;\n\n    [BsonDateTimeOptions(Kind = DateTimeKind.Local)]\n    public DateTime Added { get; set; }\n\n    [BsonDateTimeOptions(Kind = DateTimeKind.Local)]\n    public DateTime? ExpiresAt { get; set; }\n\n    public int Retries { get; set; }\n\n    public string StatusName { get; set; } = default!;\n\n    // ReSharper disable once InconsistentNaming\n    public ObjectId _lockToken { get; set; }\n}\n\npublic class Lock\n{\n    [BsonId(IdGenerator = typeof(StringObjectIdGenerator))]\n    public string Key { get; set; } = default!;\n\n    public string Instance { get; set; } = default!;\n\n    [BsonDateTimeOptions(Kind = DateTimeKind.Local)]\n    public DateTime LastLockTime { get; set; }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.MySql/CAP.EFOptions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\npublic class EFOptions\n{\n    public const string DefaultSchema = \"cap\";\n\n    /// <summary>\n    /// Gets or sets the table name prefix to use when creating database objects.\n    /// </summary>\n    public string TableNamePrefix { get; set; } = DefaultSchema;\n\n    /// <summary>\n    /// EF db context type.\n    /// </summary>\n    internal Type? DbContextType { get; set; }\n\n    /// <summary>\n    /// Data version\n    /// </summary>\n    internal string Version { get; set; } = \"v1\";\n}"
  },
  {
    "path": "src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP.MySql;\nusing DotNetCore.CAP.Persistence;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Options;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\ninternal class MySqlCapOptionsExtension : ICapOptionsExtension\n{\n    private readonly Action<MySqlOptions> _configure;\n\n    public MySqlCapOptionsExtension(Action<MySqlOptions> configure)\n    {\n        _configure = configure;\n    }\n\n    public void AddServices(IServiceCollection services)\n    {\n        services.AddSingleton(new CapStorageMarkerService(\"MySql\"));\n        services.AddSingleton<IDataStorage, MySqlDataStorage>();\n\n        services.TryAddSingleton<IStorageInitializer, MySqlStorageInitializer>();\n\n        //Add MySqlOptions\n        services.Configure(_configure);\n        services.AddSingleton<IConfigureOptions<MySqlOptions>, ConfigureMySqlOptions>();\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.MySql/CAP.MySqlOptions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP.Internal;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\npublic class MySqlOptions : EFOptions\n{\n    /// <summary>\n    /// Gets or sets the database's connection string that will be used to store database entities.\n    /// </summary>\n    public string ConnectionString { get; set; } = default!;\n}\n\ninternal class ConfigureMySqlOptions : IConfigureOptions<MySqlOptions>\n{\n    private readonly IServiceScopeFactory _serviceScopeFactory;\n\n    public ConfigureMySqlOptions(IServiceScopeFactory serviceScopeFactory)\n    {\n        _serviceScopeFactory = serviceScopeFactory;\n    }\n\n    public void Configure(MySqlOptions options)\n    {\n        if (options.DbContextType != null)\n        {\n            if (Helper.IsUsingType<ICapPublisher>(options.DbContextType))\n                throw new InvalidOperationException(\n                    \"We detected that you are using ICapPublisher in DbContext, please change the configuration to use the storage extension directly to avoid circular references! eg:  x.UseMySql()\");\n\n            using var scope = _serviceScopeFactory.CreateScope();\n            var provider = scope.ServiceProvider;\n            using var dbContext = (DbContext)provider.GetRequiredService(options.DbContextType);\n            var connectionString = dbContext.Database.GetConnectionString();\n            if (string.IsNullOrEmpty(connectionString)) throw new ArgumentNullException(connectionString);\n            options.ConnectionString = connectionString;\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.MySql/CAP.Options.Extensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP;\nusing Microsoft.EntityFrameworkCore;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.Extensions.DependencyInjection;\n\npublic static class CapOptionsExtensions\n{\n    public static CapOptions UseMySql(this CapOptions options, string connectionString)\n    {\n        return options.UseMySql(opt => { opt.ConnectionString = connectionString; });\n    }\n\n    public static CapOptions UseMySql(this CapOptions options, Action<MySqlOptions> configure)\n    {\n        if (configure == null) throw new ArgumentNullException(nameof(configure));\n\n        configure += x => x.Version = options.Version;\n\n        options.RegisterExtension(new MySqlCapOptionsExtension(configure));\n\n        return options;\n    }\n\n    public static CapOptions UseEntityFramework<TContext>(this CapOptions options)\n        where TContext : DbContext\n    {\n        return options.UseEntityFramework<TContext>(opt => { });\n    }\n\n    public static CapOptions UseEntityFramework<TContext>(this CapOptions options, Action<EFOptions> configure)\n        where TContext : DbContext\n    {\n        if (configure == null) throw new ArgumentNullException(nameof(configure));\n\n        options.RegisterExtension(new MySqlCapOptionsExtension(x =>\n        {\n            configure(x);\n            x.DbContextType = typeof(TContext);\n            x.Version = options.Version;\n        }));\n\n        return options;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.MySql/DotNetCore.CAP.MySql.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>\n    <Nullable>enable</Nullable>\n    <PackageTags>$(PackageTags);MySQL</PackageTags>\n  </PropertyGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net8.0'\">\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.Relational\" Version=\"8.0.22\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net9.0'\">\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.Relational\" Version=\"9.0.11\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net10.0'\">\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.Relational\" Version=\"10.0.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"MySqlConnector\" Version=\"2.5.0\" />\n    <ProjectReference Include=\"..\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/DotNetCore.CAP.MySql/ICapTransaction.MySql.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Data;\nusing System.Data.Common;\nusing System.Diagnostics;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.Extensions.DependencyInjection;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\npublic class MySqlCapTransaction : CapTransactionBase\n{\n    public MySqlCapTransaction(\n        IDispatcher dispatcher) : base(dispatcher)\n    {\n    }\n\n    public override void Commit()\n    {\n        Debug.Assert(DbTransaction != null);\n\n        switch (DbTransaction)\n        {\n            case IDbTransaction dbTransaction:\n                dbTransaction.Commit();\n                break;\n            case IDbContextTransaction dbContextTransaction:\n                dbContextTransaction.Commit();\n                break;\n        }\n\n        Flush();\n    }\n\n    public override async Task CommitAsync(CancellationToken cancellationToken = default)\n    {\n        Debug.Assert(DbTransaction != null);\n\n        switch (DbTransaction)\n        {\n            case DbTransaction dbTransaction:\n                await dbTransaction.CommitAsync(cancellationToken).ConfigureAwait(false);\n                break;\n            case IDbContextTransaction dbContextTransaction:\n                await dbContextTransaction.CommitAsync(cancellationToken).ConfigureAwait(false);\n                break;\n        }\n\n        await FlushAsync();\n    }\n\n    public override void Rollback()\n    {\n        Debug.Assert(DbTransaction != null);\n\n        switch (DbTransaction)\n        {\n            case IDbTransaction dbTransaction:\n                dbTransaction.Rollback();\n                break;\n            case IDbContextTransaction dbContextTransaction:\n                dbContextTransaction.Rollback();\n                break;\n        }\n    }\n\n    public override async Task RollbackAsync(CancellationToken cancellationToken = default)\n    {\n        Debug.Assert(DbTransaction != null);\n\n        switch (DbTransaction)\n        {\n            case DbTransaction dbTransaction:\n                await dbTransaction.RollbackAsync(cancellationToken).ConfigureAwait(false);\n                break;\n            case IDbContextTransaction dbContextTransaction:\n                await dbContextTransaction.RollbackAsync(cancellationToken).ConfigureAwait(false);\n                break;\n        }\n    }\n}\n\npublic static class CapTransactionExtensions\n{\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"database\">The <see cref=\"DatabaseFacade\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <returns>The <see cref=\"IDbContextTransaction\" /> of EF DbContext transaction object.</returns>\n    public static IDbContextTransaction BeginTransaction(this DatabaseFacade database,\n        ICapPublisher publisher, bool autoCommit = false)\n    {\n        return BeginTransaction(database, IsolationLevel.Unspecified, publisher, autoCommit);\n    }\n\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"database\">The <see cref=\"DatabaseFacade\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"isolationLevel\">The <see cref=\"IsolationLevel\" /> to use</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <returns>The <see cref=\"IDbContextTransaction\" /> of EF DbContext transaction object.</returns>\n    public static IDbContextTransaction BeginTransaction(this DatabaseFacade database,\n        IsolationLevel isolationLevel, ICapPublisher publisher, bool autoCommit = false)\n    {\n        var dbTransaction = database.BeginTransaction(isolationLevel);\n        publisher.Transaction = ActivatorUtilities.CreateInstance<MySqlCapTransaction>(publisher.ServiceProvider);\n        publisher.Transaction.DbTransaction = dbTransaction;\n        publisher.Transaction.AutoCommit = autoCommit;\n        return new CapEFDbTransaction(publisher.Transaction);\n    }\n\n    /// <summary>\n    /// Start the CAP transaction async\n    /// </summary>\n    /// <param name=\"database\">The <see cref=\"DatabaseFacade\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <param name=\"cancellationToken\"></param>\n    /// <returns>The <see cref=\"IDbContextTransaction\" /> of EF DbContext transaction object.</returns>\n    public static Task<IDbContextTransaction> BeginTransactionAsync(this DatabaseFacade database,\n        ICapPublisher publisher, bool autoCommit = false, CancellationToken cancellationToken = default)\n    {\n        return BeginTransactionAsync(database, IsolationLevel.Unspecified, publisher, autoCommit, cancellationToken);\n    }\n\n    /// <summary>\n    /// Start the CAP transaction async\n    /// </summary>\n    /// <param name=\"database\">The <see cref=\"DatabaseFacade\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"isolationLevel\">The <see cref=\"IsolationLevel\" /> to use</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <param name=\"cancellationToken\"></param>\n    /// <returns>The <see cref=\"IDbContextTransaction\" /> of EF DbContext transaction object.</returns>\n    public static Task<IDbContextTransaction> BeginTransactionAsync(this DatabaseFacade database,\n        IsolationLevel isolationLevel, ICapPublisher publisher, bool autoCommit = false, CancellationToken cancellationToken = default)\n    {\n        var dbTransaction = database.BeginTransactionAsync(isolationLevel, cancellationToken).GetAwaiter().GetResult();\n        publisher.Transaction = ActivatorUtilities.CreateInstance<MySqlCapTransaction>(publisher.ServiceProvider);\n        publisher.Transaction.DbTransaction = dbTransaction;\n        publisher.Transaction.AutoCommit = autoCommit;\n        return Task.FromResult<IDbContextTransaction>(new CapEFDbTransaction(publisher.Transaction));\n    }\n\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"dbConnection\">The <see cref=\"IDbConnection\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <returns>The <see cref=\"ICapTransaction\" /> object.</returns>\n    public static ICapTransaction BeginTransaction(this IDbConnection dbConnection,\n        ICapPublisher publisher, bool autoCommit = false)\n    {\n        return BeginTransaction(dbConnection, IsolationLevel.Unspecified, publisher, autoCommit);\n    }\n\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"dbConnection\">The <see cref=\"IDbConnection\" />.</param>\n    /// <param name=\"isolationLevel\">The <see cref=\"IsolationLevel\" /> to use</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <returns>The <see cref=\"ICapTransaction\" /> object.</returns>\n    public static ICapTransaction BeginTransaction(this IDbConnection dbConnection,\n        IsolationLevel isolationLevel, ICapPublisher publisher, bool autoCommit = false)\n    {\n        if (dbConnection.State == ConnectionState.Closed) dbConnection.Open();\n\n        var dbTransaction = dbConnection.BeginTransaction(isolationLevel);\n        publisher.Transaction = ActivatorUtilities.CreateInstance<MySqlCapTransaction>(publisher.ServiceProvider);\n        publisher.Transaction.DbTransaction = dbTransaction;\n        publisher.Transaction.AutoCommit = autoCommit;\n        return publisher.Transaction;\n    }\n\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"dbConnection\">The <see cref=\"IDbConnection\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <param name=\"cancellationToken\"></param>\n    /// <returns>The <see cref=\"ICapTransaction\" /> object.</returns>\n    public static ValueTask<ICapTransaction> BeginTransactionAsync(this IDbConnection dbConnection,\n        ICapPublisher publisher, bool autoCommit = false, CancellationToken cancellationToken = default)\n    {\n        return BeginTransactionAsync(dbConnection, IsolationLevel.Unspecified, publisher, autoCommit, cancellationToken);\n    }\n\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"dbConnection\">The <see cref=\"IDbConnection\" />.</param>\n    /// <param name=\"isolationLevel\">The <see cref=\"IsolationLevel\" /> to use</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <param name=\"cancellationToken\"></param>\n    public static ValueTask<ICapTransaction> BeginTransactionAsync(this IDbConnection dbConnection,\n        IsolationLevel isolationLevel, ICapPublisher publisher, bool autoCommit = false, CancellationToken cancellationToken = default)\n    {\n        if (dbConnection.State == ConnectionState.Closed) ((DbConnection)dbConnection).OpenAsync(cancellationToken).GetAwaiter().GetResult();\n\n        var dbTransaction = ((DbConnection)dbConnection).BeginTransactionAsync(isolationLevel, cancellationToken).GetAwaiter().GetResult();\n        publisher.Transaction = ActivatorUtilities.CreateInstance<MySqlCapTransaction>(publisher.ServiceProvider);\n        publisher.Transaction.DbTransaction = dbTransaction;\n        publisher.Transaction.AutoCommit = autoCommit;\n        return ValueTask.FromResult(publisher.Transaction);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.MySql/IDataStorage.MySql.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Data;\nusing System.Data.Common;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Monitoring;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Serialization;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.Extensions.Options;\nusing MySqlConnector;\n\nnamespace DotNetCore.CAP.MySql;\n\npublic class MySqlDataStorage : IDataStorage\n{\n    private readonly IOptions<CapOptions> _capOptions;\n    private readonly IStorageInitializer _initializer;\n    private readonly string _lockName;\n    private readonly IOptions<MySqlOptions> _options;\n    private readonly string _pubName;\n    private readonly string _recName;\n    private readonly ISerializer _serializer;\n    private readonly ISnowflakeId _snowflakeId;\n\n    public MySqlDataStorage(\n        IOptions<MySqlOptions> options,\n        IOptions<CapOptions> capOptions,\n        IStorageInitializer initializer,\n        ISerializer serializer,\n        ISnowflakeId snowflakeId)\n    {\n        _options = options;\n        _capOptions = capOptions;\n        _initializer = initializer;\n        _serializer = serializer;\n        _snowflakeId = snowflakeId;\n        _pubName = initializer.GetPublishedTableName();\n        _recName = initializer.GetReceivedTableName();\n        _lockName = initializer.GetLockTableName();\n    }\n\n    private bool SupportSkipLocked => ((MySqlStorageInitializer)_initializer).IsSupportSkipLocked();\n\n    public async Task<bool> AcquireLockAsync(string key, TimeSpan ttl, string instance,\n        CancellationToken token = default)\n    {\n        var sql =\n            $\"UPDATE `{_lockName}` SET `Instance`=@Instance,`LastLockTime`=@LastLockTime WHERE `Key`=@Key AND `LastLockTime` < @TTL;\";\n        var connection = new MySqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        object[] sqlParams =\n        {\n            new MySqlParameter(\"@Instance\", instance),\n            new MySqlParameter(\"@LastLockTime\", DateTime.Now),\n            new MySqlParameter(\"@Key\", key),\n            new MySqlParameter(\"@TTL\", DateTime.Now.Subtract(ttl))\n        };\n        var opResult = await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n        return opResult > 0;\n    }\n\n    public async Task ReleaseLockAsync(string key, string instance, CancellationToken token = default)\n    {\n        var sql =\n            $\"UPDATE `{_lockName}` SET `Instance`='',`LastLockTime`=@LastLockTime WHERE `Key`=@Key AND `Instance`=@Instance;\";\n        var connection = new MySqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        object[] sqlParams =\n        {\n            new MySqlParameter(\"@Instance\", instance),\n            new MySqlParameter(\"@LastLockTime\", DateTime.MinValue),\n            new MySqlParameter(\"@Key\", key)\n        };\n        await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n    }\n\n    public async Task RenewLockAsync(string key, TimeSpan ttl, string instance, CancellationToken token = default)\n    {\n        var sql =\n            $\"UPDATE `{_lockName}` SET `LastLockTime`= date_add(`LastLockTime`, interval {ttl.TotalSeconds} second) WHERE `Key`=@Key AND `Instance`=@Instance;\";\n        var connection = new MySqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        object[] sqlParams =\n        {\n            new MySqlParameter(\"@Instance\", instance),\n            new MySqlParameter(\"@Key\", key)\n        };\n        await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n    }\n\n    public async Task ChangePublishStateToDelayedAsync(string[] ids)\n    {\n        var sql =\n            $\"UPDATE `{_pubName}` SET `StatusName`='{StatusName.Delayed}' WHERE `Id` IN ({string.Join(',', ids)});\";\n        var connection = new MySqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        await connection.ExecuteNonQueryAsync(sql).ConfigureAwait(false);\n    }\n\n    public async Task ChangePublishStateAsync(MediumMessage message, StatusName state, object? transaction = null)\n    {\n        await ChangeMessageStateAsync(_pubName, message, state, transaction).ConfigureAwait(false);\n    }\n\n    public async Task ChangeReceiveStateAsync(MediumMessage message, StatusName state)\n    {\n        await ChangeMessageStateAsync(_recName, message, state).ConfigureAwait(false);\n    }\n\n    public async Task<MediumMessage> StoreMessageAsync(string name, Message content, object? transaction = null)\n    {\n        var sql =\n            $\"INSERT INTO `{_pubName}`(`Id`,`Version`,`Name`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`)\" +\n            $\" VALUES(@Id,'{_options.Value.Version}',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);\";\n\n        var message = new MediumMessage\n        {\n            DbId = content.GetId(),\n            Origin = content,\n            Content = _serializer.Serialize(content),\n            Added = DateTime.Now,\n            ExpiresAt = null,\n            Retries = 0\n        };\n\n        object[] sqlParams =\n        {\n            new MySqlParameter(\"@Id\", message.DbId),\n            new MySqlParameter(\"@Name\", name),\n            new MySqlParameter(\"@Content\", message.Content),\n            new MySqlParameter(\"@Retries\", message.Retries),\n            new MySqlParameter(\"@Added\", message.Added),\n            new MySqlParameter(\"@ExpiresAt\", message.ExpiresAt.HasValue ? message.ExpiresAt.Value : DBNull.Value),\n            new MySqlParameter(\"@StatusName\", nameof(StatusName.Scheduled))\n        };\n\n        if (transaction == null)\n        {\n            var connection = new MySqlConnection(_options.Value.ConnectionString);\n            await using var _ = connection.ConfigureAwait(false);\n            await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n        }\n        else\n        {\n            var dbTrans = transaction as DbTransaction;\n            if (dbTrans == null && transaction is IDbContextTransaction dbContextTrans)\n                dbTrans = dbContextTrans.GetDbTransaction();\n\n            var conn = dbTrans!.Connection!;\n            await conn.ExecuteNonQueryAsync(sql, dbTrans, sqlParams).ConfigureAwait(false);\n        }\n\n        return message;\n    }\n\n    public async Task StoreReceivedExceptionMessageAsync(string name, string group, string content)\n    {\n        object[] sqlParams =\n        {\n            new MySqlParameter(\"@Id\", _snowflakeId.NextId().ToString()),\n            new MySqlParameter(\"@Name\", name),\n            new MySqlParameter(\"@Group\", group),\n            new MySqlParameter(\"@Content\", content),\n            new MySqlParameter(\"@Retries\", _capOptions.Value.FailedRetryCount),\n            new MySqlParameter(\"@Added\", DateTime.Now),\n            new MySqlParameter(\"@ExpiresAt\", DateTime.Now.AddSeconds(_capOptions.Value.FailedMessageExpiredAfter)),\n            new MySqlParameter(\"@StatusName\", nameof(StatusName.Failed))\n        };\n\n        await StoreReceivedMessage(sqlParams).ConfigureAwait(false);\n    }\n\n    public async Task<MediumMessage> StoreReceivedMessageAsync(string name, string group, Message message)\n    {\n        var mdMessage = new MediumMessage\n        {\n            DbId = _snowflakeId.NextId().ToString(),\n            Origin = message,\n            Added = DateTime.Now,\n            ExpiresAt = null,\n            Retries = 0\n        };\n\n        object[] sqlParams =\n        {\n            new MySqlParameter(\"@Id\", mdMessage.DbId),\n            new MySqlParameter(\"@Name\", name),\n            new MySqlParameter(\"@Group\", group),\n            new MySqlParameter(\"@Content\", _serializer.Serialize(mdMessage.Origin)),\n            new MySqlParameter(\"@Retries\", mdMessage.Retries),\n            new MySqlParameter(\"@Added\", mdMessage.Added),\n            new MySqlParameter(\"@ExpiresAt\", mdMessage.ExpiresAt.HasValue ? mdMessage.ExpiresAt.Value : DBNull.Value),\n            new MySqlParameter(\"@StatusName\", nameof(StatusName.Scheduled))\n        };\n\n        await StoreReceivedMessage(sqlParams).ConfigureAwait(false);\n        return mdMessage;\n    }\n\n    public async Task<int> DeleteExpiresAsync(string table, DateTime timeout, int batchCount = 1000,\n        CancellationToken token = default)\n    {\n        var connection = new MySqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n\n        return await connection.ExecuteNonQueryAsync(\n            $@\"DELETE P FROM `{table}` AS P\n               JOIN (\n                   SELECT Id\n                   FROM `{table}`\n                   WHERE ExpiresAt < @timeout\n                   AND StatusName IN ('{StatusName.Succeeded}', '{StatusName.Failed}')\n                   ORDER BY Id\n                   LIMIT @batchCount\n                   { (SupportSkipLocked ? \"FOR UPDATE SKIP LOCKED\" : \"FOR UPDATE\")}\n               ) AS T ON P.Id = T.Id;\",\n            null,\n            new MySqlParameter(\"@timeout\", timeout),\n            new MySqlParameter(\"@batchCount\", batchCount)).ConfigureAwait(false);\n    }\n\n    public Task<IEnumerable<MediumMessage>> GetPublishedMessagesOfNeedRetry(TimeSpan lookbackSeconds)\n    {\n        return GetMessagesOfNeedRetryAsync(_pubName, lookbackSeconds);\n    }\n\n    public Task<IEnumerable<MediumMessage>> GetReceivedMessagesOfNeedRetry(TimeSpan lookbackSeconds)\n    {\n        return GetMessagesOfNeedRetryAsync(_recName, lookbackSeconds);\n    }\n\n    public async Task<int> DeleteReceivedMessageAsync(long id)\n    {\n        var sql = $\"DELETE FROM `{_recName}` WHERE Id={id};\";\n\n        var connection = new MySqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        var result = await connection.ExecuteNonQueryAsync(sql).ConfigureAwait(false);\n        return result;\n    }\n\n    public async Task<int> DeletePublishedMessageAsync(long id)\n    {\n        var sql = $\"DELETE FROM `{_pubName}` WHERE Id={id};\";\n\n        var connection = new MySqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        var result = await connection.ExecuteNonQueryAsync(sql).ConfigureAwait(false);\n        return result;\n    }\n\n    public async Task ScheduleMessagesOfDelayedAsync(Func<object, IEnumerable<MediumMessage>, Task> scheduleTask,\n        CancellationToken token = default)\n    {\n        var lockSql = SupportSkipLocked ? \"FOR UPDATE SKIP LOCKED\" : \"FOR UPDATE\";\n\n        var sql =\n            $\"SELECT `Id`,`Content`,`Retries`,`Added`,`ExpiresAt` FROM `{_pubName}` WHERE `Version`=@Version \" +\n            $\"AND ((`ExpiresAt`< @TwoMinutesLater AND `StatusName` = '{StatusName.Delayed}') OR (`ExpiresAt`< @OneMinutesAgo AND `StatusName` = '{StatusName.Queued}')) LIMIT @BatchSize {lockSql};\";\n\n        object[] sqlParams =\n        {\n            new MySqlParameter(\"@Version\", _capOptions.Value.Version),\n            new MySqlParameter(\"@TwoMinutesLater\", DateTime.Now.AddMinutes(2)),\n            new MySqlParameter(\"@OneMinutesAgo\", DateTime.Now.AddMinutes(-1)),\n            new MySqlParameter(\"@BatchSize\", _capOptions.Value.SchedulerBatchSize)\n        };\n\n        await using var connection = new MySqlConnection(_options.Value.ConnectionString);\n\n        await connection.OpenAsync(token);\n        await using var transaction = await connection.BeginTransactionAsync(IsolationLevel.ReadCommitted, token);\n        var messageList = await connection.ExecuteReaderAsync(sql, async reader =>\n        {\n            var messages = new List<MediumMessage>();\n            while (await reader.ReadAsync(token).ConfigureAwait(false))\n            {\n                messages.Add(new MediumMessage\n                {\n                    DbId = reader.GetInt64(0).ToString(),\n                    Origin = _serializer.Deserialize(reader.GetString(1))!,\n                    Retries = reader.GetInt32(2),\n                    Added = reader.GetDateTime(3),\n                    ExpiresAt = reader.GetDateTime(4)\n                });\n            }\n\n            return messages;\n        }, transaction, sqlParams).ConfigureAwait(false);\n\n        await scheduleTask(transaction, messageList);\n\n        await transaction.CommitAsync(token);\n    }\n\n    public IMonitoringApi GetMonitoringApi()\n    {\n        return new MySqlMonitoringApi(_options, _initializer, _serializer);\n    }\n\n    private async Task ChangeMessageStateAsync(string tableName, MediumMessage message, StatusName state,\n        object? transaction = null)\n    {\n        var sql =\n            $\"UPDATE `{tableName}` SET `Content`=@Content,`Retries`=@Retries,`ExpiresAt`=@ExpiresAt,`StatusName`=@StatusName WHERE `Id`=@Id;\";\n\n        object[] sqlParams =\n        {\n            new MySqlParameter(\"@Id\", message.DbId),\n            new MySqlParameter(\"@Content\", _serializer.Serialize(message.Origin)),\n            new MySqlParameter(\"@Retries\", message.Retries),\n            new MySqlParameter(\"@ExpiresAt\", message.ExpiresAt),\n            new MySqlParameter(\"@StatusName\", state.ToString(\"G\"))\n        };\n\n        if (transaction is DbTransaction dbTransaction)\n        {\n            var connection = (MySqlConnection)dbTransaction.Connection!;\n            await connection.ExecuteNonQueryAsync(sql, dbTransaction, sqlParams).ConfigureAwait(false);\n        }\n        else\n        {\n            await using var connection = new MySqlConnection(_options.Value.ConnectionString);\n            await using var _ = connection.ConfigureAwait(false);\n            await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n        }\n    }\n\n    private async Task StoreReceivedMessage(object[] sqlParams)\n    {\n        var sql =\n            $@\"INSERT INTO `{_recName}`(`Id`,`Version`,`Name`,`Group`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`) \" +\n            $\"VALUES(@Id,'{_options.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);\";\n\n        var connection = new MySqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n    }\n\n    private async Task<IEnumerable<MediumMessage>> GetMessagesOfNeedRetryAsync(string tableName, TimeSpan lookbackSeconds)\n    {\n        var fourMinAgo = DateTime.Now.Subtract(lookbackSeconds);\n        var sql =\n            $\"SELECT `Id`,`Content`,`Retries`,`Added` FROM `{tableName}` WHERE `Retries`<@Retries \" +\n            $\"AND `Version`=@Version AND `Added`<@Added AND `StatusName` IN ('{StatusName.Failed}','{StatusName.Scheduled}') LIMIT 200;\";\n\n        object[] sqlParams =\n        {\n            new MySqlParameter(\"@Retries\", _capOptions.Value.FailedRetryCount),\n            new MySqlParameter(\"@Version\", _capOptions.Value.Version),\n            new MySqlParameter(\"@Added\", fourMinAgo)\n        };\n\n        var connection = new MySqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        var result = await connection.ExecuteReaderAsync(sql, async reader =>\n        {\n            var messages = new List<MediumMessage>();\n            while (await reader.ReadAsync().ConfigureAwait(false))\n            {\n                messages.Add(new MediumMessage\n                {\n                    DbId = reader.GetInt64(0).ToString(),\n                    Origin = _serializer.Deserialize(reader.GetString(1))!,\n                    Retries = reader.GetInt32(2),\n                    Added = reader.GetDateTime(3)\n                });\n            }\n\n            return messages;\n        }, sqlParams: sqlParams).ConfigureAwait(false);\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP.MySql/IDbConnection.Extensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.ComponentModel;\nusing System.Data;\nusing System.Data.Common;\nusing System.Threading.Tasks;\n\nnamespace DotNetCore.CAP.MySql;\n\ninternal static class DbConnectionExtensions\n{\n    public static async Task<int> ExecuteNonQueryAsync(this DbConnection connection, string sql,\n        DbTransaction? transaction = null, params object[] sqlParams)\n    {\n        if (connection.State == ConnectionState.Closed) await connection.OpenAsync().ConfigureAwait(false);\n\n        var command = connection.CreateCommand();\n\n        await using var _ = command.ConfigureAwait(false);\n        command.CommandType = CommandType.Text;\n        command.CommandText = sql;\n        foreach (var param in sqlParams)\n        {\n            command.Parameters.Add(param);\n        }\n\n        if (transaction != null) command.Transaction = transaction;\n\n        return await command.ExecuteNonQueryAsync().ConfigureAwait(false);\n    }\n\n    public static async Task<T> ExecuteReaderAsync<T>(this DbConnection connection, string sql,\n        Func<DbDataReader, Task<T>>? readerFunc, DbTransaction? transaction = null, params object[] sqlParams)\n    {\n        if (connection.State == ConnectionState.Closed) await connection.OpenAsync().ConfigureAwait(false);\n\n        var command = connection.CreateCommand();\n        await using var _ = command.ConfigureAwait(false);\n        command.CommandType = CommandType.Text;\n        command.CommandText = sql;\n        foreach (var param in sqlParams)\n        {\n            command.Parameters.Add(param);\n        }\n\n        if (transaction != null) command.Transaction = transaction;\n\n        await using var reader = await command.ExecuteReaderAsync().ConfigureAwait(false);\n\n        T result = default!;\n        if (readerFunc != null) result = await readerFunc(reader).ConfigureAwait(false);\n\n        return result;\n    }\n\n    public static async Task<T> ExecuteScalarAsync<T>(this DbConnection connection, string sql,\n        params object[] sqlParams)\n    {\n        if (connection.State == ConnectionState.Closed) await connection.OpenAsync().ConfigureAwait(false);\n\n        var command = connection.CreateCommand();\n        await using var _ = command.ConfigureAwait(false);\n        command.CommandType = CommandType.Text;\n        command.CommandText = sql;\n        foreach (var param in sqlParams)\n        {\n            command.Parameters.Add(param);\n        }\n\n        var objValue = await command.ExecuteScalarAsync().ConfigureAwait(false);\n\n        T result = default!;\n        if (objValue != null)\n        {\n            var returnType = typeof(T);\n            var converter = TypeDescriptor.GetConverter(returnType);\n            if (converter.CanConvertFrom(objValue.GetType()))\n                result = (T)converter.ConvertFrom(objValue)!;\n            else\n                result = (T)Convert.ChangeType(objValue, returnType);\n        }\n\n        return result;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.MySql/IDbContextTransaction.CAP.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Data.Common;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.EntityFrameworkCore.Storage;\n\n// ReSharper disable once InconsistentNaming\ninternal class CapEFDbTransaction : IDbContextTransaction, IInfrastructure<DbTransaction>\n{\n    private readonly ICapTransaction _transaction;\n\n    public CapEFDbTransaction(ICapTransaction transaction)\n    {\n        _transaction = transaction;\n        var dbContextTransaction = (IDbContextTransaction)_transaction.DbTransaction!;\n        TransactionId = dbContextTransaction.TransactionId;\n    }\n\n    public Guid TransactionId { get; }\n\n    public void Dispose()\n    {\n        _transaction.Dispose();\n    }\n\n    public void Commit()\n    {\n        _transaction.Commit();\n    }\n\n    public Task CommitAsync(CancellationToken cancellationToken = default)\n    {\n        return _transaction.CommitAsync(cancellationToken);\n    }\n\n    public void Rollback()\n    {\n        _transaction.Rollback();\n    }\n\n    public Task RollbackAsync(CancellationToken cancellationToken = default)\n    {\n        return _transaction.RollbackAsync(cancellationToken);\n    }\n\n    public ValueTask DisposeAsync()\n    {\n        Dispose();\n        return new ValueTask();\n    }\n\n    public DbTransaction Instance\n    {\n        get\n        {\n            var dbContextTransaction = (IDbContextTransaction)_transaction.DbTransaction!;\n            return dbContextTransaction.GetDbTransaction();\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Monitoring;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Serialization;\nusing Microsoft.Extensions.Options;\nusing MySqlConnector;\n\nnamespace DotNetCore.CAP.MySql;\n\ninternal class MySqlMonitoringApi : IMonitoringApi\n{\n    private readonly MySqlOptions _options;\n    private readonly string _pubName;\n    private readonly string _recName;\n    private readonly ISerializer _serializer;\n\n    public MySqlMonitoringApi(IOptions<MySqlOptions> options, IStorageInitializer initializer, ISerializer serializer)\n    {\n        _serializer = serializer;\n        _options = options.Value ?? throw new ArgumentNullException(nameof(options));\n        _pubName = initializer.GetPublishedTableName();\n        _recName = initializer.GetReceivedTableName();\n    }\n\n    public async Task<StatisticsDto> GetStatisticsAsync()\n    {\n        var sql = $@\"\nSELECT\n(\n    SELECT COUNT(Id) FROM `{_pubName}` WHERE StatusName = N'Succeeded'\n) AS PublishedSucceeded,\n(\n    SELECT COUNT(Id) FROM `{_recName}` WHERE StatusName = N'Succeeded'\n) AS ReceivedSucceeded,\n(\n    SELECT COUNT(Id) FROM `{_pubName}` WHERE StatusName = N'Failed'\n) AS PublishedFailed,\n(\n    SELECT COUNT(Id) FROM `{_recName}` WHERE StatusName = N'Failed'\n) AS ReceivedFailed,\n(\n    SELECT COUNT(Id) FROM `{_pubName}` WHERE StatusName = N'Delayed'\n) AS PublishedDelayed;\";\n\n        var connection = new MySqlConnection(_options.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        var statistics = await connection.ExecuteReaderAsync(sql, async reader =>\n        {\n            var statisticsDto = new StatisticsDto();\n\n            while (await reader.ReadAsync().ConfigureAwait(false))\n            {\n                statisticsDto.PublishedSucceeded = reader.GetInt32(0);\n                statisticsDto.ReceivedSucceeded = reader.GetInt32(1);\n                statisticsDto.PublishedFailed = reader.GetInt32(2);\n                statisticsDto.ReceivedFailed = reader.GetInt32(3);\n                statisticsDto.PublishedDelayed = reader.GetInt32(4);\n            }\n\n            return statisticsDto;\n        }).ConfigureAwait(false);\n\n        return statistics;\n    }\n\n    public async Task<IDictionary<DateTime, int>> HourlyFailedJobs(MessageType type)\n    {\n        var tableName = type == MessageType.Publish ? _pubName : _recName;\n        return await GetHourlyTimelineStats(tableName, nameof(StatusName.Failed)).ConfigureAwait(false);\n    }\n\n    public async Task<IDictionary<DateTime, int>> HourlySucceededJobs(MessageType type)\n    {\n        var tableName = type == MessageType.Publish ? _pubName : _recName;\n        return await GetHourlyTimelineStats(tableName, nameof(StatusName.Succeeded)).ConfigureAwait(false);\n    }\n\n    public async Task<PagedQueryResult<MessageDto>> GetMessagesAsync(MessageQueryDto queryDto)\n    {\n        var tableName = queryDto.MessageType == MessageType.Publish ? _pubName : _recName;\n        var where = string.Empty;\n        if (!string.IsNullOrEmpty(queryDto.StatusName)) where += \" AND StatusName=@StatusName\";\n\n        if (!string.IsNullOrEmpty(queryDto.Name)) where += \" AND Name=@Name\";\n\n        if (!string.IsNullOrEmpty(queryDto.Group)) where += \" AND `Group`=@Group\";\n\n        if (!string.IsNullOrEmpty(queryDto.Content)) where += \" AND Content LIKE CONCAT('%',@Content,'%')\";\n\n        var sqlQuery =\n            $\"SELECT * FROM `{tableName}` WHERE 1=1 {where} ORDER BY Added DESC LIMIT @Limit OFFSET @Offset\";\n\n        object[] sqlParams =\n        {\n            new MySqlParameter(\"@StatusName\", queryDto.StatusName ?? string.Empty),\n            new MySqlParameter(\"@Group\", queryDto.Group ?? string.Empty),\n            new MySqlParameter(\"@Name\", queryDto.Name ?? string.Empty),\n            new MySqlParameter(\"@Content\", $\"%{queryDto.Content}%\"),\n            new MySqlParameter(\"@Offset\", queryDto.CurrentPage * queryDto.PageSize),\n            new MySqlParameter(\"@Limit\", queryDto.PageSize)\n        };\n\n        var connection = new MySqlConnection(_options.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n\n        var count = await connection.ExecuteScalarAsync<int>($\"select count(1) from `{tableName}` where 1=1 {where}\",\n            new MySqlParameter(\"@StatusName\", queryDto.StatusName ?? string.Empty),\n            new MySqlParameter(\"@Group\", queryDto.Group ?? string.Empty),\n            new MySqlParameter(\"@Name\", queryDto.Name ?? string.Empty),\n            new MySqlParameter(\"@Content\", $\"%{queryDto.Content}%\")).ConfigureAwait(false);\n\n        var items = await connection.ExecuteReaderAsync(sqlQuery, async reader =>\n        {\n            var messages = new List<MessageDto>();\n\n            while (await reader.ReadAsync())\n            {\n                var index = 0;\n                messages.Add(new MessageDto\n                {\n                    Id = reader.GetInt64(index++).ToString(),\n                    Version = reader.GetString(index++),\n                    Name = reader.GetString(index++),\n                    Group = queryDto.MessageType == MessageType.Subscribe ? reader.GetString(index++) : default,\n                    Content = reader.GetString(index++),\n                    Retries = reader.GetInt32(index++),\n                    Added = reader.GetDateTime(index++),\n                    ExpiresAt = reader.IsDBNull(index++) ? null : reader.GetDateTime(index - 1),\n                    StatusName = reader.GetString(index)\n                });\n            }\n\n            return messages;\n        }, sqlParams: sqlParams).ConfigureAwait(false);\n\n        return new PagedQueryResult<MessageDto>\n            { Items = items, PageIndex = queryDto.CurrentPage, PageSize = queryDto.PageSize, Totals = count };\n    }\n\n    public ValueTask<int> PublishedFailedCount()\n    {\n        return GetNumberOfMessage(_pubName, nameof(StatusName.Failed));\n    }\n\n    public ValueTask<int> PublishedSucceededCount()\n    {\n        return GetNumberOfMessage(_pubName, nameof(StatusName.Succeeded));\n    }\n\n    public ValueTask<int> ReceivedFailedCount()\n    {\n        return GetNumberOfMessage(_recName, nameof(StatusName.Failed));\n    }\n\n    public ValueTask<int> ReceivedSucceededCount()\n    {\n        return GetNumberOfMessage(_recName, nameof(StatusName.Succeeded));\n    }\n\n    public async Task<MediumMessage?> GetPublishedMessageAsync(long id)\n    {\n        return await GetMessageAsync(_pubName, id).ConfigureAwait(false);\n    }\n\n    public async Task<MediumMessage?> GetReceivedMessageAsync(long id)\n    {\n        return await GetMessageAsync(_recName, id).ConfigureAwait(false);\n    }\n\n    private async ValueTask<int> GetNumberOfMessage(string tableName, string statusName)\n    {\n        var sqlQuery = $\"SELECT COUNT(Id) FROM `{tableName}` WHERE StatusName = @State\";\n        var connection = new MySqlConnection(_options.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        return await connection.ExecuteScalarAsync<int>(sqlQuery, new MySqlParameter(\"@State\", statusName))\n            .ConfigureAwait(false);\n    }\n\n    private Task<Dictionary<DateTime, int>> GetHourlyTimelineStats(string tableName, string statusName)\n    {\n        var endDate = DateTime.Now;\n        var dates = new List<DateTime>();\n        for (var i = 0; i < 24; i++)\n        {\n            dates.Add(endDate);\n            endDate = endDate.AddHours(-1);\n        }\n\n        var keyMaps = dates.ToDictionary(x => x.ToString(\"yyyy-MM-dd-HH\"), x => x);\n\n        return GetTimelineStats(tableName, statusName, keyMaps);\n    }\n\n    private async Task<Dictionary<DateTime, int>> GetTimelineStats(\n        string tableName,\n        string statusName,\n        IDictionary<string, DateTime> keyMaps)\n    {\n        var sqlQuery = $@\"\nSELECT Aggr.*\nFROM (\n         SELECT DATE_FORMAT(`Added`, '%Y-%m-%d-%H') AS `Key`,\n                COUNT(`Id`) AS `Count`\n         FROM `{tableName}`\n         WHERE `StatusName` = @StatusName\n         GROUP BY DATE_FORMAT(`Added`, '%Y-%m-%d-%H')\n     ) AS Aggr\nWHERE `Key` >= @MinKey\n  AND `Key` <= @MaxKey;\";\n\n        object[] sqlParams =\n        {\n            new MySqlParameter(\"@StatusName\", statusName),\n            new MySqlParameter(\"@MinKey\", keyMaps.Keys.Min()),\n            new MySqlParameter(\"@MaxKey\", keyMaps.Keys.Max())\n        };\n\n        Dictionary<string, int> valuesMap;\n        var connection = new MySqlConnection(_options.ConnectionString);\n        await using (connection.ConfigureAwait(false))\n        {\n            valuesMap = await connection.ExecuteReaderAsync(sqlQuery, async reader =>\n            {\n                var dictionary = new Dictionary<string, int>();\n\n                while (await reader.ReadAsync())\n                {\n                    dictionary.Add(reader.GetString(0), reader.GetInt32(1));\n                }\n\n                return dictionary;\n            }, sqlParams: sqlParams).ConfigureAwait(false);\n        }\n\n        foreach (var key in keyMaps.Keys)\n        {\n            if (!valuesMap.ContainsKey(key))\n                valuesMap.Add(key, 0);\n        }\n\n        var result = new Dictionary<DateTime, int>();\n        for (var i = 0; i < keyMaps.Count; i++)\n        {\n            var value = valuesMap[keyMaps.ElementAt(i).Key];\n            result.Add(keyMaps.ElementAt(i).Value, value);\n        }\n\n        return result;\n    }\n\n    private async Task<MediumMessage?> GetMessageAsync(string tableName, long id)\n    {\n        var sql = $\"SELECT `Id` as DbId, `Content`,`Added`,`ExpiresAt`,`Retries` FROM `{tableName}` WHERE Id={id};\";\n\n        var connection = new MySqlConnection(_options.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        var mediumMessage = await connection.ExecuteReaderAsync(sql, async reader =>\n        {\n            MediumMessage? message = null;\n\n            while (await reader.ReadAsync().ConfigureAwait(false))\n            {\n                message = new MediumMessage\n                {\n                    DbId = reader.GetInt64(0).ToString(),\n                    Origin = _serializer.Deserialize(reader.GetString(1))!,\n                    Content = reader.GetString(1),\n                    Added = reader.GetDateTime(2),\n                    ExpiresAt = reader.GetDateTime(3),\n                    Retries = reader.GetInt32(4)\n                };\n            }\n\n            return message;\n        }).ConfigureAwait(false);\n\n        return mediumMessage;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.MySql/IStorageInitializer.MySql.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Persistence;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing MySqlConnector;\n\nnamespace DotNetCore.CAP.MySql;\n\npublic class MySqlStorageInitializer : IStorageInitializer\n{\n    private readonly IOptions<CapOptions> _capOptions;\n    private readonly ILogger _logger;\n    private readonly IOptions<MySqlOptions> _options;\n\n    private ServerVersion? _serverVersion;\n\n    public MySqlStorageInitializer(\n        ILogger<MySqlStorageInitializer> logger,\n        IOptions<MySqlOptions> options,\n        IOptions<CapOptions> capOptions)\n    {\n        _options = options;\n        _logger = logger;\n        _capOptions = capOptions;\n    }\n\n    public virtual string GetPublishedTableName()\n    {\n        return $\"{_options.Value.TableNamePrefix}.published\";\n    }\n\n    public virtual string GetReceivedTableName()\n    {\n        return $\"{_options.Value.TableNamePrefix}.received\";\n    }\n\n    public virtual string GetLockTableName()\n    {\n        return $\"{_options.Value.TableNamePrefix}.lock\";\n    }\n\n    public async Task InitializeAsync(CancellationToken cancellationToken)\n    {\n        if (cancellationToken.IsCancellationRequested) return;\n\n        var sql = CreateDbTablesScript();\n        var connection = new MySqlConnection(_options.Value.ConnectionString);\n        await using (connection.ConfigureAwait(false))\n        {\n            await connection.OpenAsync(cancellationToken);\n            _serverVersion = ServerVersion.Parse(connection.ServerVersion);\n            object[] sqlParams =\n            {\n                new MySqlParameter(\"@PubKey\", $\"publish_retry_{_capOptions.Value.Version}\"),\n                new MySqlParameter(\"@RecKey\", $\"received_retry_{_capOptions.Value.Version}\"),\n                new MySqlParameter(\"@LastLockTime\", DateTime.MinValue)\n            };\n            await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n        }\n\n        _logger.LogDebug(\"Ensuring all create database tables script are applied.\");\n    }\n\n    public virtual bool IsSupportSkipLocked()\n    {\n        if (_serverVersion == null) return false;\n\n        switch (_serverVersion.Type)\n        {\n            case ServerVersion.ServerType.MySql when _serverVersion.Version.Major >= 8:\n            case ServerVersion.ServerType.MariaDb when _serverVersion.Version.Major > 10:\n            case ServerVersion.ServerType.MariaDb\n                when _serverVersion.Version.Major == 10 && _serverVersion.Version.Minor >= 6:\n                return true;\n            default:\n                return false;\n        }\n    }\n\n\n    protected virtual string CreateDbTablesScript()\n    {\n        var batchSql =\n            $@\"\nCREATE TABLE IF NOT EXISTS `{GetReceivedTableName()}` (\n  `Id` bigint NOT NULL,\n  `Version` varchar(20) DEFAULT NULL,\n  `Name` varchar(400) NOT NULL,\n  `Group` varchar(200) DEFAULT NULL,\n  `Content` longtext,\n  `Retries` int(11) DEFAULT NULL,\n  `Added` datetime NOT NULL,\n  `ExpiresAt` datetime DEFAULT NULL,\n  `StatusName` varchar(50) NOT NULL,\n  PRIMARY KEY (`Id`),\n  INDEX `IX_Version_ExpiresAt_StatusName` (`Version`, `ExpiresAt`, `StatusName`),\n  INDEX `IX_ExpiresAt_StatusName` (`ExpiresAt`, `StatusName`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n\nCREATE TABLE IF NOT EXISTS `{GetPublishedTableName()}` (\n  `Id` bigint NOT NULL,\n  `Version` varchar(20) DEFAULT NULL,\n  `Name` varchar(200) NOT NULL,\n  `Content` longtext,\n  `Retries` int(11) DEFAULT NULL,\n  `Added` datetime NOT NULL,\n  `ExpiresAt` datetime DEFAULT NULL,\n  `StatusName` varchar(40) NOT NULL,\n  PRIMARY KEY (`Id`),\n  INDEX `IX_Version_ExpiresAt_StatusName` (`Version`, `ExpiresAt`, `StatusName`),\n  INDEX `IX_ExpiresAt_StatusName` (`ExpiresAt`, `StatusName`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n\";\n        if (_capOptions.Value.UseStorageLock)\n            batchSql += $@\"\nCREATE TABLE IF NOT EXISTS `{GetLockTableName()}` (\n  `Key` varchar(128) NOT NULL,\n  `Instance` varchar(256) DEFAULT NULL,\n  `LastLockTime` datetime DEFAULT NULL,\n  PRIMARY KEY (`Key`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n\nINSERT IGNORE INTO `{GetLockTableName()}` (`Key`,`Instance`,`LastLockTime`) VALUES(@PubKey,'',@LastLockTime);\nINSERT IGNORE INTO `{GetLockTableName()}` (`Key`,`Instance`,`LastLockTime`) VALUES(@RecKey,'',@LastLockTime);\";\n\n        return batchSql;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.MySql/ServerVersion.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Text.RegularExpressions;\n\nnamespace DotNetCore.CAP.MySql;\n\ninternal class ServerVersion\n{\n    public enum ServerType\n    {\n        MySql = 0,\n        MariaDb = 1\n    }\n\n    private static readonly Regex VersionRegex = new(\"\\\\d+\\\\.\\\\d+\\\\.?(?:\\\\d+)?\");\n\n    public ServerVersion(ServerType serverType, Version version)\n    {\n        Type = serverType;\n        Version = version;\n    }\n\n    public Version Version { get; }\n\n    public ServerType Type { get; }\n\n    public static ServerVersion? Parse(string versionString)\n    {\n        var mariaDbTypeIdentifier = \"MariaDb\".ToLowerInvariant();\n        var matchCollection = VersionRegex.Matches(versionString);\n        if (matchCollection.Count > 0)\n        {\n            var serverType = (ServerType)(versionString.ToLower().Contains(mariaDbTypeIdentifier) ? 1 : 0);\n            var version = serverType != ServerType.MariaDb || matchCollection.Count <= 1\n                ? Version.Parse(matchCollection[0].Value)\n                : Version.Parse(matchCollection[1].Value);\n            return new ServerVersion(serverType, version);\n        }\n\n        return null;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.NATS/CAP.NATSCapOptionsExtension.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP.NATS;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.DependencyInjection;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\ninternal sealed class NATSCapOptionsExtension : ICapOptionsExtension\n{\n    private readonly Action<NATSOptions> _configure;\n\n    public NATSCapOptionsExtension(Action<NATSOptions> configure)\n    {\n        _configure = configure;\n    }\n\n    public void AddServices(IServiceCollection services)\n    {\n        services.AddSingleton(new CapMessageQueueMakerService(\"NATS JetStream\"));\n\n        services.Configure(_configure);\n\n        services.AddSingleton<ITransport, NATSTransport>();\n        services.AddSingleton<IConsumerClientFactory, NATSConsumerClientFactory>();\n        services.AddSingleton<IConnectionPool, ConnectionPool>();\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.NATS/CAP.NATSOptions.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing NATS.Client;\nusing NATS.Client.JetStream;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\n/// <summary>\n/// Provides programmatic configuration for the CAP NATS project.\n/// </summary>\npublic class NATSOptions\n{\n    /// <summary>\n    /// Gets or sets the server url/urls used to connect to the NATs server.\n    /// </summary>\n    /// <remarks>This may contain username/password information.</remarks>\n    public string Servers { get; set; } = \"nats://127.0.0.1:4222\";\n\n    /// <summary>\n    /// connection pool size, default is 10\n    /// </summary>\n    public int ConnectionPoolSize { get; set; } = 10;\n\n    /// <summary>\n    /// Allows a nats consumer client to dynamically create a stream and configure the expected subjects on the stream. Defaults to true.\n    /// </summary>\n    public bool EnableSubscriberClientStreamAndSubjectCreation { get; set; } = true;\n\n    /// <summary>\n    /// Used to setup all NATs client options\n    /// </summary>\n    public Options? Options { get; set; }\n\n    public Action<StreamConfiguration.StreamConfigurationBuilder>? StreamOptions { get; set; }\n\n    public Action<ConsumerConfiguration.ConsumerConfigurationBuilder>? ConsumerOptions { get; set; }\n\n    /// <summary>\n    /// If you need to get additional native delivery args, you can use this function to write into <see cref=\"CapHeader\" />.\n    /// </summary>\n    public Func<MsgHandlerEventArgs, IServiceProvider, List<KeyValuePair<string, string>>>? CustomHeadersBuilder { get; set; }\n\n    public Func<string, string> NormalizeStreamName { get; set; } = origin => origin.Split('.')[0];\n}"
  },
  {
    "path": "src/DotNetCore.CAP.NATS/CAP.Options.Extensions.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.Extensions.DependencyInjection;\n\npublic static class CapOptionsExtensions\n{\n    /// <summary>\n    /// Configuration to use NATS in CAP.\n    /// </summary>\n    /// <param name=\"options\">CAP configuration options</param>\n    /// <param name=\"bootstrapServers\">NATS bootstrap server urls.</param>\n    public static CapOptions UseNATS(this CapOptions options, string? bootstrapServers = null)\n    {\n        return options.UseNATS(opt =>\n        {\n            if (bootstrapServers != null)\n                opt.Servers = bootstrapServers;\n        });\n    }\n\n    /// <summary>\n    /// Configuration to use NATS in CAP.\n    /// </summary>\n    /// <param name=\"options\">CAP configuration options</param>\n    /// <param name=\"configure\">Provides programmatic configuration for the NATS.</param>\n    /// <returns></returns>\n    public static CapOptions UseNATS(this CapOptions options, Action<NATSOptions> configure)\n    {\n        if (configure == null)\n        {\n            throw new ArgumentNullException(nameof(configure));\n        }\n\n        options.RegisterExtension(new NATSCapOptionsExtension(configure));\n\n        return options;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.NATS/DotNetCore.CAP.NATS.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\t<Nullable>enable</Nullable>\n    <PackageTags>$(PackageTags);NATS</PackageTags>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"NATS.Client\" Version=\"1.1.8\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "src/DotNetCore.CAP.NATS/IConnectionPool.Default.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Concurrent;\nusing System.Threading;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing NATS.Client;\n\nnamespace DotNetCore.CAP.NATS;\n\npublic class ConnectionPool : IConnectionPool, IDisposable\n{\n    private readonly NATSOptions _options;\n    private readonly ConcurrentQueue<IConnection> _connectionPool;\n\n    private readonly ConnectionFactory _connectionFactory;\n    private int _pCount;\n    private int _maxSize;\n\n    public ConnectionPool(ILogger<ConnectionPool> logger, IOptions<NATSOptions> options)\n    {\n        _options = options.Value;\n        _connectionPool = new ConcurrentQueue<IConnection>();\n        _connectionFactory = new ConnectionFactory();\n        _maxSize = _options.ConnectionPoolSize;\n\n        logger.LogDebug(\"NATS configuration: {0}\", options.Value.Options);\n    }\n\n    public string ServersAddress => _options.Servers;\n\n    public IConnection RentConnection()\n    {\n        if (_connectionPool.TryDequeue(out var connection))\n        {\n            Interlocked.Decrement(ref _pCount);\n\n            return connection;\n        }\n\n        if (_options.Options != null)\n        {\n            _options.Options.Url = _options.Servers;\n            connection = _connectionFactory.CreateConnection(_options.Options);\n        }\n        else\n        {\n            connection = _connectionFactory.CreateConnection(_options.Servers);\n        }\n\n        return connection;\n    }\n\n    public bool Return(IConnection connection)\n    {\n        if (Interlocked.Increment(ref _pCount) <= _maxSize && connection.State == ConnState.CONNECTED)\n        {\n            _connectionPool.Enqueue(connection);\n\n            return true;\n        }\n\n        if (!connection.IsReconnecting())\n        {\n            connection.Dispose();\n        }\n\n        Interlocked.Decrement(ref _pCount);\n\n        return false;\n    }\n\n    public void Dispose()\n    {\n        _maxSize = 0;\n\n        while (_connectionPool.TryDequeue(out var context))\n        {\n            context.Dispose();\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.NATS/IConnectionPool.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing NATS.Client;\n\nnamespace DotNetCore.CAP.NATS;\n\npublic interface IConnectionPool\n{\n    string ServersAddress { get; }\n\n    IConnection RentConnection();\n\n    bool Return(IConnection connection);\n}"
  },
  {
    "path": "src/DotNetCore.CAP.NATS/ITransport.NATS.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Logging;\nusing NATS.Client;\nusing NATS.Client.JetStream;\n\nnamespace DotNetCore.CAP.NATS;\n\ninternal class NATSTransport : ITransport\n{\n    private readonly IConnectionPool _connectionPool;\n    private readonly ILogger _logger;\n    private readonly JetStreamOptions _jetStreamOptions;\n\n    public NATSTransport(ILogger<NATSTransport> logger, IConnectionPool connectionPool)\n    {\n        _logger = logger;\n        _connectionPool = connectionPool;\n\n        _jetStreamOptions = JetStreamOptions.Builder().WithPublishNoAck(false).WithRequestTimeout(3000).Build();\n    }\n\n    public BrokerAddress BrokerAddress => new BrokerAddress(\"NATS\", _connectionPool.ServersAddress);\n\n    public async Task<OperateResult> SendAsync(TransportMessage message)\n    {\n        var connection = _connectionPool.RentConnection();\n\n        try\n        {\n            var msg = new Msg(message.GetName(), message.Body.ToArray());\n            foreach (var header in message.Headers)\n            {\n                msg.Header[header.Key] = header.Value;\n            }\n\n            var js = connection.CreateJetStreamContext(_jetStreamOptions);\n\n            var builder = PublishOptions.Builder().WithMessageId(message.GetId());\n\n            var resp = await js.PublishAsync(msg, builder.Build());\n\n            if (resp.Seq > 0)\n            {\n                _logger.LogDebug($\"NATS stream message [{message.GetName()}] has been published.\");\n\n                return OperateResult.Success;\n            }\n\n            throw new PublisherSentFailedException(\"NATS message send failed, no consumer reply!\");\n        }\n        catch (Exception ex)\n        {\n            var warpEx = new PublisherSentFailedException(ex.Message, ex);\n\n            return OperateResult.Failed(warpEx);\n        }\n        finally\n        {\n            _connectionPool.Return(connection);\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.NATS/NATSConsumerClient.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Options;\nusing NATS.Client;\nusing NATS.Client.JetStream;\n\nnamespace DotNetCore.CAP.NATS;\n\ninternal sealed class NATSConsumerClient : IConsumerClient\n{\n    private static readonly object ConnectionLock = new();\n\n    private readonly string _groupName;\n    private readonly byte _groupConcurrent;\n    private readonly IServiceProvider _serviceProvider;\n    private readonly NATSOptions _natsOptions;\n    private readonly SemaphoreSlim _semaphore;\n    private IConnection? _consumerClient;\n\n    public NATSConsumerClient(string groupName, byte groupConcurrent, IOptions<NATSOptions> options, IServiceProvider serviceProvider)\n    {\n        _groupName = groupName;\n        _groupConcurrent = groupConcurrent;\n        _serviceProvider = serviceProvider;\n        _semaphore = new SemaphoreSlim(groupConcurrent);\n        _natsOptions = options.Value ?? throw new ArgumentNullException(nameof(options));\n    }\n\n    public Func<TransportMessage, object?, Task>? OnMessageCallback { get; set; }\n\n    public Action<LogMessageEventArgs>? OnLogCallback { get; set; }\n\n    public BrokerAddress BrokerAddress => new(\"nats\", _natsOptions.Servers);\n\n    public Task<ICollection<string>> FetchTopicsAsync(IEnumerable<string> topicNames)\n    {\n        if (_natsOptions.EnableSubscriberClientStreamAndSubjectCreation)\n        {\n            Connect();\n\n            var jsm = _consumerClient!.CreateJetStreamManagementContext();\n\n            var streamSubjectsGroups = topicNames.GroupBy(x => _natsOptions.NormalizeStreamName(x));\n\n            foreach (var streamSubjectsGroup in streamSubjectsGroups)\n            {\n                var builder = StreamConfiguration.Builder()\n                    .WithName(streamSubjectsGroup.Key)\n                    .WithNoAck(false)\n                    .WithStorageType(StorageType.Memory)\n                    .WithSubjects(streamSubjectsGroup.ToList());\n\n                _natsOptions.StreamOptions?.Invoke(builder);\n\n                try\n                {\n                    jsm.GetStreamInfo(streamSubjectsGroup.Key); // this throws if the stream does not exist\n\n                    jsm.UpdateStream(builder.Build());\n                }\n                catch (NATSJetStreamException)\n                {\n                    try\n                    {\n                        jsm.AddStream(builder.Build());\n                    }\n                    catch\n                    {\n                        // ignored\n                    }\n                }\n            }\n        }\n\n        return Task.FromResult<ICollection<string>>(topicNames.ToList());\n    }\n\n    public Task SubscribeAsync(IEnumerable<string> topics)\n    {\n        if (topics == null)\n        {\n            throw new ArgumentNullException(nameof(topics));\n        }\n\n        Connect();\n\n        var js = _consumerClient!.CreateJetStreamContext();\n        var streamGroup = topics.GroupBy(x => _natsOptions.NormalizeStreamName(x));\n\n        lock (ConnectionLock)\n        {\n            foreach (var subjectStream in streamGroup)\n            {\n                var groupName = Helper.Normalized(_groupName);\n\n                foreach (var subject in subjectStream)\n                {\n                    try\n                    {\n                        var consumerConfig = ConsumerConfiguration.Builder()\n                                  .WithDurable(Helper.Normalized(groupName + \"-\" + subject))\n                                  .WithDeliverPolicy(DeliverPolicy.New)\n                                  .WithAckWait(30000)\n                                  .WithAckPolicy(AckPolicy.Explicit);\n\n                        _natsOptions.ConsumerOptions?.Invoke(consumerConfig);\n\n                        var pso = PushSubscribeOptions.Builder()\n                            .WithStream(subjectStream.Key)\n                            .WithConfiguration(consumerConfig.Build())\n                            .Build();\n\n                        js.PushSubscribeAsync(subject, groupName, SubscriptionMessageHandler, false, pso);\n                    }\n                    catch (Exception e)\n                    {\n                        OnLogCallback!(new LogMessageEventArgs()\n                        {\n                            LogType = MqLogType.ConnectError,\n                            Reason = $\"An error was encountered when attempting to subscribe to subject: {subject}.{Environment.NewLine}\" +\n                            $\"{e.Message}\"\n                        });\n                    }\n                }\n            }\n        }\n        return Task.CompletedTask;\n    }\n\n    public Task ListeningAsync(TimeSpan timeout, CancellationToken cancellationToken)\n    {\n        while (true)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            cancellationToken.WaitHandle.WaitOne(timeout);\n        }\n    }\n\n    private async void SubscriptionMessageHandler(object? sender, MsgHandlerEventArgs e)\n    {\n        if (_groupConcurrent > 0)\n        {\n            await _semaphore.WaitAsync().ConfigureAwait(false);\n            _ = Task.Run(ConsumeAsync);\n        }\n        else\n        {\n            await ConsumeAsync();\n        }\n\n        Task ConsumeAsync()\n        {\n            var headers = new Dictionary<string, string?>();\n\n            foreach (string h in e.Message.Header.Keys)\n            {\n                headers.Add(h, e.Message.Header[h]);\n            }\n\n            headers[Headers.Group] = _groupName;\n\n            if (_natsOptions.CustomHeadersBuilder != null)\n            {\n                var customHeaders = _natsOptions.CustomHeadersBuilder(e, _serviceProvider);\n                foreach (var customHeader in customHeaders)\n                {\n                    headers[customHeader.Key] = customHeader.Value;\n                }\n            }\n\n            return OnMessageCallback!(new TransportMessage(headers, e.Message.Data), e.Message);\n        }\n    }\n\n    public Task CommitAsync(object? sender)\n    {\n        try\n        {\n            if (sender is Msg msg)\n            {\n                msg.Ack();\n            }\n        }\n        catch (Exception ex)\n        {\n            OnLogCallback?.Invoke(new LogMessageEventArgs\n            {\n                LogType = MqLogType.AsyncErrorEvent,\n                Reason = $\"NATS message ACK failed: {ex}\"\n            });\n        }\n        finally\n        {\n            if (_groupConcurrent > 0)\n            {\n                try\n                {\n                    _semaphore.Release();\n                }\n                catch (SemaphoreFullException)\n                {\n                    // ignore (defensive)\n                }\n            }\n        }\n        return Task.CompletedTask;\n    }\n\n    public Task RejectAsync(object? sender)\n    {\n        try\n        {\n            if (sender is Msg msg)\n            {\n                msg.Nak();\n            }\n        }\n        catch (Exception ex)\n        {\n            OnLogCallback?.Invoke(new LogMessageEventArgs\n            {\n                LogType = MqLogType.AsyncErrorEvent,\n                Reason = $\"NATS message NAK failed: {ex}\"\n            });\n        }\n        finally\n        {\n            if (_groupConcurrent > 0)\n            {\n                try\n                {\n                    _semaphore.Release();\n                }\n                catch (SemaphoreFullException)\n                {\n                    // ignore (defensive)\n                }\n            }\n        }\n        return Task.CompletedTask;\n    }\n\n    public ValueTask DisposeAsync()\n    {\n        _consumerClient?.Dispose();\n        return ValueTask.CompletedTask;\n    }\n\n    public void Connect()\n    {\n        if (_consumerClient != null)\n        {\n            return;\n        }\n\n        lock (ConnectionLock)\n        {\n            if (_consumerClient == null)\n            {\n                var opts = _natsOptions.Options ?? ConnectionFactory.GetDefaultOptions();\n                opts.Url ??= _natsOptions.Servers;\n                opts.DisconnectedEventHandler = DisconnectedEventHandler;\n                opts.AsyncErrorEventHandler = AsyncErrorEventHandler;\n                opts.Timeout = 5000;\n                opts.AllowReconnect = false;\n                opts.NoEcho = true;\n\n                _consumerClient = new ConnectionFactory().CreateConnection(opts);\n            }\n        }\n    }\n\n    private void DisconnectedEventHandler(object? sender, ConnEventArgs e)\n    {\n        if (e.Error is null) return;\n\n        var logArgs = new LogMessageEventArgs\n        {\n            LogType = MqLogType.ConnectError,\n            Reason = e.Error.ToString()\n        };\n        OnLogCallback!(logArgs);\n    }\n\n    private void AsyncErrorEventHandler(object? sender, ErrEventArgs e)\n    {\n        var logArgs = new LogMessageEventArgs\n        {\n            LogType = MqLogType.AsyncErrorEvent,\n            Reason = e.Error\n        };\n        OnLogCallback!(logArgs);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.NATS/NATSConsumerClientFactory.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.NATS;\n\ninternal sealed class NATSConsumerClientFactory : IConsumerClientFactory\n{\n    private readonly IOptions<NATSOptions> _natsOptions;\n    private readonly IServiceProvider _serviceProvider;\n\n    public NATSConsumerClientFactory(IOptions<NATSOptions> natsOptions, IServiceProvider serviceProvider)\n    {\n        _natsOptions = natsOptions;\n        _serviceProvider = serviceProvider;\n    }\n\n    public Task<IConsumerClient> CreateAsync(string groupName, byte groupConcurrent)\n    {\n        try\n        {\n            var client = new NATSConsumerClient(groupName, groupConcurrent, _natsOptions, _serviceProvider);\n            client.Connect();\n            return Task.FromResult<IConsumerClient>(client);\n        }\n        catch (System.Exception e)\n        {\n            throw new BrokerConnectionException(e);\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.OpenTelemetry/CapInstrumentation.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\n\nnamespace DotNetCore.CAP.OpenTelemetry;\n\n/// <summary>\n/// CAP instrumentation.\n/// </summary>\ninternal class CapInstrumentation : IDisposable\n{\n    private readonly DiagnosticSourceSubscriber? _diagnosticSourceSubscriber;\n\n    public CapInstrumentation(DiagnosticListener diagnosticListener)\n    {\n        _diagnosticSourceSubscriber = new DiagnosticSourceSubscriber(diagnosticListener, null);\n        _diagnosticSourceSubscriber.Subscribe();\n    }\n\n    /// <inheritdoc />\n    public void Dispose()\n    {\n        _diagnosticSourceSubscriber?.Dispose();\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.OpenTelemetry/DiagnosticListener.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing DotNetCore.CAP.Diagnostics;\nusing OpenTelemetry;\nusing OpenTelemetry.Context.Propagation;\nusing CapEvents = DotNetCore.CAP.Diagnostics.CapDiagnosticListenerNames;\n\nnamespace DotNetCore.CAP.OpenTelemetry;\n\ninternal class DiagnosticListener : IObserver<KeyValuePair<string, object?>>\n{\n    public const string SourceName = \"DotNetCore.CAP.OpenTelemetry\";\n\n    private const string OperateNamePrefix = \"CAP/\";\n    private const string ProducerOperateNameSuffix = \"/Publisher\";\n    private const string ConsumerOperateNameSuffix = \"/Subscriber\";\n    private static readonly ActivitySource ActivitySource = new(SourceName, \"1.0.0\");\n    private static readonly TextMapPropagator Propagator = Propagators.DefaultTextMapPropagator;\n\n    public void OnCompleted()\n    {\n    }\n\n    public void OnError(Exception error)\n    {\n    }\n\n    public void OnNext(KeyValuePair<string, object?> evt)\n    {\n        switch (evt.Key)\n        {\n            case CapEvents.BeforePublishMessageStore:\n                {\n                    var eventData = (CapEventDataPubStore)evt.Value!;\n                    ActivityContext parentContext = Propagator.Extract(default, eventData.Message, (msg, key) =>\n                    {\n                        if (msg.Headers.TryGetValue(key, out var value) && value != null) return new string[] { value };\n                        return Enumerable.Empty<string>();\n                    }).ActivityContext;\n\n                    if (parentContext == default)\n                    {\n                        parentContext = Activity.Current?.Context ?? default;\n                    }\n                    var activity = ActivitySource.StartActivity(\"Event Persistence: \" + eventData.Operation,\n                        ActivityKind.Internal, parentContext);\n                    if (activity != null)\n                    {\n                        activity.SetTag(\"messaging.destination.name\", eventData.Operation);\n                        activity.AddEvent(new ActivityEvent(\"CAP message persistence start...\",\n                            DateTimeOffset.FromUnixTimeMilliseconds(eventData.OperationTimestamp!.Value)));\n\n                        if (parentContext != default && Activity.Current != null)\n                        {\n                            Propagator.Inject(new PropagationContext(Activity.Current.Context, Baggage.Current),\n                                eventData.Message,\n                                (msg, key, value) => { msg.Headers[key] = value; });\n                        }\n                        ;\n                    }\n                }\n                break;\n            case CapEvents.AfterPublishMessageStore:\n                {\n                    var eventData = (CapEventDataPubStore)evt.Value!;\n\n                    Activity.Current?.AddEvent(new ActivityEvent(\"CAP message persistence succeeded!\",\n                        DateTimeOffset.FromUnixTimeMilliseconds(eventData.OperationTimestamp!.Value),\n                        new ActivityTagsCollection { new(\"cap.persistence.duration\", eventData.ElapsedTimeMs) })\n                    );\n\n                    Activity.Current?.Stop();\n                }\n                break;\n            case CapEvents.ErrorPublishMessageStore:\n                {\n                    var eventData = (CapEventDataPubStore)evt.Value!;\n                    if (Activity.Current is { } activity)\n                    {\n                        var exception = eventData.Exception!;\n                        activity.SetStatus(ActivityStatusCode.Error, exception.Message);\n                        activity.AddException(exception);\n                        activity.Stop();\n                    }\n                }\n                break;\n            case CapEvents.BeforePublish:\n                {\n                    var eventData = (CapEventDataPubSend)evt.Value!;\n                    var parentContext = Propagator.Extract(default, eventData.TransportMessage, (msg, key) =>\n                    {\n                        if (msg.Headers.TryGetValue(key, out var value) && !string.IsNullOrEmpty(value))\n                        {\n                            return new string[] { value };\n                        }\n\n                        return Enumerable.Empty<string>();\n                    });\n\n                    var activity = ActivitySource.StartActivity(\n                        OperateNamePrefix + eventData.Operation + ProducerOperateNameSuffix, ActivityKind.Producer,\n                        parentContext.ActivityContext);\n                    if (activity != null)\n                    {\n                        activity.SetTag(\"messaging.system\", eventData.BrokerAddress.Name);\n                        activity.SetTag(\"messaging.message.id\", eventData.TransportMessage.GetId());\n                        activity.SetTag(\"messaging.message.body.size\", eventData.TransportMessage.Body.Length);\n                        activity.SetTag(\"messaging.message.conversation_id\", eventData.TransportMessage.GetCorrelationId());\n                        activity.SetTag(\"messaging.destination.name\", eventData.Operation);\n                        if (eventData.BrokerAddress.Endpoint is { } endpoint)\n                        {\n                            var parts = endpoint.Split(':');\n                            if (parts.Length > 0)\n                            {\n                                activity.SetTag(\"server.address\", parts[0]);\n                            }\n                            if (parts.Length > 1 && int.TryParse(parts[1], out var port))\n                            {\n                                activity.SetTag(\"server.port\", port);\n                            }\n                        }\n                        activity.AddEvent(new ActivityEvent(\"Message publishing start...\",\n                            DateTimeOffset.FromUnixTimeMilliseconds(eventData.OperationTimestamp!.Value)));\n\n                        Propagator.Inject(new PropagationContext(activity.Context, Baggage.Current),\n                            eventData.TransportMessage,\n                            (msg, key, value) => { msg.Headers[key] = value; });\n                    }\n                }\n                break;\n            case CapEvents.AfterPublish:\n                {\n                    var eventData = (CapEventDataPubSend)evt.Value!;\n                    if (Activity.Current is { } activity)\n                    {\n                        activity.AddEvent(new ActivityEvent(\"Message publishing succeeded!\",\n                            DateTimeOffset.FromUnixTimeMilliseconds(eventData.OperationTimestamp!.Value),\n                            new ActivityTagsCollection { new(\"cap.send.duration\", eventData.ElapsedTimeMs) })\n                        );\n                        activity.Stop();\n                    }\n                }\n                break;\n            case CapEvents.ErrorPublish:\n                {\n                    var eventData = (CapEventDataPubSend)evt.Value!;\n                    if (Activity.Current is { } activity)\n                    {\n                        var exception = eventData.Exception!;\n                        activity.SetStatus(ActivityStatusCode.Error, exception.Message);\n                        activity.AddException(exception);\n                        activity.Stop();\n                    }\n                }\n                break;\n            case CapEvents.BeforeConsume:\n                {\n                    var eventData = (CapEventDataSubStore)evt.Value!;\n                    var parentContext = Propagator.Extract(default, eventData.TransportMessage, (msg, key) =>\n                    {\n                        if (msg.Headers.TryGetValue(key, out var value) && value != null) return new string[] { value };\n                        return Enumerable.Empty<string>();\n                    });\n\n                    Baggage.Current = parentContext.Baggage;\n                    var activity = ActivitySource.StartActivity(\n                        OperateNamePrefix + eventData.Operation + ConsumerOperateNameSuffix,\n                        ActivityKind.Consumer,\n                        parentContext.ActivityContext);\n\n                    if (activity != null)\n                    {\n                        activity.SetTag(\"messaging.system\", eventData.BrokerAddress.Name);\n                        activity.SetTag(\"messaging.message.id\", eventData.TransportMessage.GetId());\n                        activity.SetTag(\"messaging.message.body.size\", eventData.TransportMessage.Body.Length);\n                        activity.SetTag(\"messaging.operation.type\", \"receive\");\n                        activity.SetTag(\"messaging.client.id\", eventData.TransportMessage.GetExecutionInstanceId());\n                        activity.SetTag(\"messaging.destination.name\", eventData.Operation);\n                        activity.SetTag(\"messaging.consumer.group.name\", eventData.TransportMessage.GetGroup());\n                        if (eventData.BrokerAddress.Endpoint is { } endpoint)\n                        {\n                            var parts = endpoint.Split(':');\n                            if (parts.Length > 0)\n                            {\n                                activity.SetTag(\"server.address\", parts[0]);\n                            }\n                            if (parts.Length > 1 && int.TryParse(parts[1], out var port))\n                            {\n                                activity.SetTag(\"server.port\", port);\n                            }\n                        }\n                        activity.AddEvent(new ActivityEvent(\"CAP message persistence start...\",\n                            DateTimeOffset.FromUnixTimeMilliseconds(eventData.OperationTimestamp!.Value)));\n                    }\n                }\n                break;\n            case CapEvents.AfterConsume:\n                {\n                    var eventData = (CapEventDataSubStore)evt.Value!;\n                    if (Activity.Current is { } activity)\n                    {\n                        activity.AddEvent(new ActivityEvent(\"CAP message persistence succeeded!\",\n                            DateTimeOffset.FromUnixTimeMilliseconds(eventData.OperationTimestamp!.Value),\n                            new ActivityTagsCollection { new(\"cap.receive.duration\", eventData.ElapsedTimeMs) }));\n\n                        activity.Stop();\n                    }\n                }\n                break;\n            case CapEvents.ErrorConsume:\n                {\n                    var eventData = (CapEventDataSubStore)evt.Value!;\n                    if (Activity.Current is { } activity)\n                    {\n                        var exception = eventData.Exception!;\n                        activity.SetStatus(ActivityStatusCode.Error, exception.Message);\n                        activity.AddException(exception);\n                        activity.Stop();\n                    }\n                }\n                break;\n            case CapEvents.BeforeSubscriberInvoke:\n                {\n                    ActivityContext context = default;\n                    var eventData = (CapEventDataSubExecute)evt.Value!;\n                    var propagatedContext = Propagator.Extract(default, eventData.Message, (msg, key) =>\n                    {\n                        if (msg.Headers.TryGetValue(key, out var value) && value != null) return new string[] { value };\n                        return Enumerable.Empty<string>();\n                    });\n\n                    if (propagatedContext != default)\n                    {\n                        context = propagatedContext.ActivityContext;\n                        Baggage.Current = propagatedContext.Baggage;\n                    }\n\n                    var activity = ActivitySource.StartActivity(\"Subscriber Invoke: \" + eventData.MethodInfo!.Name,\n                        ActivityKind.Internal,\n                        context);\n\n                    if (activity != null)\n                    {\n                        activity.SetTag(\"code.function.name\", eventData.MethodInfo.Name);\n\n                        activity.AddEvent(new ActivityEvent(\"Begin invoke the subscriber:\" + eventData.MethodInfo.Name,\n                            DateTimeOffset.FromUnixTimeMilliseconds(eventData.OperationTimestamp!.Value)));\n                    }\n                }\n                break;\n            case CapEvents.AfterSubscriberInvoke:\n                {\n                    var eventData = (CapEventDataSubExecute)evt.Value!;\n                    if (Activity.Current is { } activity)\n                    {\n                        activity.AddEvent(new ActivityEvent(\"Subscriber invoke succeeded!\",\n                            DateTimeOffset.FromUnixTimeMilliseconds(eventData.OperationTimestamp!.Value),\n                            new ActivityTagsCollection { new(\"cap.invoke.duration\", eventData.ElapsedTimeMs) }));\n\n                        activity.Stop();\n                    }\n                }\n                break;\n            case CapEvents.ErrorSubscriberInvoke:\n                {\n                    var eventData = (CapEventDataSubExecute)evt.Value!;\n                    if (Activity.Current is { } activity)\n                    {\n                        var exception = eventData.Exception!;\n                        activity.SetStatus(ActivityStatusCode.Error, exception.Message);\n                        activity.AddException(exception);\n                        activity.Stop();\n                    }\n                }\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP.OpenTelemetry/DiagnosticSourceSubscriber.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing DotNetCore.CAP.Diagnostics;\n\nnamespace DotNetCore.CAP.OpenTelemetry;\n\ninternal class DiagnosticSourceSubscriber : IDisposable, IObserver<System.Diagnostics.DiagnosticListener>\n{\n    private readonly Func<System.Diagnostics.DiagnosticListener, bool> _diagnosticSourceFilter;\n    private readonly Func<string, DiagnosticListener> _handlerFactory;\n    private readonly Func<string, object?, object?, bool>? _isEnabledFilter;\n    private readonly List<IDisposable> _listenerSubscriptions;\n    private IDisposable? _allSourcesSubscription;\n    private long _disposed;\n\n    public DiagnosticSourceSubscriber(\n        DiagnosticListener handler,\n        Func<string, object?, object?, bool>? isEnabledFilter)\n        : this(_ => handler,\n            value => CapDiagnosticListenerNames.DiagnosticListenerName == value.Name,\n            isEnabledFilter)\n    {\n    }\n\n    public DiagnosticSourceSubscriber(\n        Func<string, DiagnosticListener> handlerFactory,\n        Func<System.Diagnostics.DiagnosticListener, bool> diagnosticSourceFilter,\n        Func<string, object?, object?, bool>? isEnabledFilter)\n    {\n        _listenerSubscriptions = new List<IDisposable>();\n        _handlerFactory = handlerFactory ?? throw new ArgumentNullException(nameof(handlerFactory));\n        _diagnosticSourceFilter = diagnosticSourceFilter;\n        _isEnabledFilter = isEnabledFilter;\n    }\n\n    /// <inheritdoc />\n    public void Dispose()\n    {\n        Dispose(true);\n        GC.SuppressFinalize(this);\n    }\n\n    public void OnNext(System.Diagnostics.DiagnosticListener value)\n    {\n        if (Interlocked.Read(ref _disposed) == 0 && _diagnosticSourceFilter(value))\n        {\n            var handler = _handlerFactory(value.Name);\n            var subscription = _isEnabledFilter == null\n                ? value.Subscribe(handler)\n                : value.Subscribe(handler, _isEnabledFilter);\n\n            lock (_listenerSubscriptions)\n            {\n                _listenerSubscriptions.Add(subscription);\n            }\n        }\n    }\n\n    public void OnCompleted()\n    {\n    }\n\n    public void OnError(Exception error)\n    {\n    }\n\n    public void Subscribe()\n    {\n        _allSourcesSubscription ??= System.Diagnostics.DiagnosticListener.AllListeners.Subscribe(this);\n    }\n\n    protected virtual void Dispose(bool disposing)\n    {\n        if (Interlocked.CompareExchange(ref _disposed, 1, 0) == 1) return;\n\n        lock (_listenerSubscriptions)\n        {\n            foreach (var listenerSubscription in _listenerSubscriptions)\n            {\n                listenerSubscription?.Dispose();\n            }\n\n            _listenerSubscriptions.Clear();\n        }\n\n        _allSourcesSubscription?.Dispose();\n        _allSourcesSubscription = null;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.OpenTelemetry/DotNetCore.CAP.OpenTelemetry.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\t<Nullable>enable</Nullable>\n\t<Description>CAP instrumentation for OpenTelemetry .NET</Description>\n    <PackageTags>$(PackageTags);distributed-tracing;opentelemetry;</PackageTags>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"OpenTelemetry\" Version=\"1.14.0\" />\n  </ItemGroup> \n  \n  <ItemGroup>\n    <ProjectReference Include=\"..\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n  </ItemGroup>\n \n</Project>\n"
  },
  {
    "path": "src/DotNetCore.CAP.OpenTelemetry/TracerProviderBuilder.Extension.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP.OpenTelemetry;\n\n// ReSharper disable once CheckNamespace\nnamespace OpenTelemetry.Trace;\n\npublic static class TracerProviderBuilderExtensions\n{\n    /// <summary>\n    /// Enables the message eventing data collection for CAP.\n    /// </summary>\n    /// <param name=\"builder\"><see cref=\"TracerProviderBuilder\" /> being configured.</param>\n    /// <returns>The instance of <see cref=\"TracerProviderBuilder\" /> to chain the calls.</returns>\n    public static TracerProviderBuilder AddCapInstrumentation(this TracerProviderBuilder builder)\n    {\n        if (builder == null) throw new ArgumentNullException(nameof(builder));\n\n        builder.AddSource(DiagnosticListener.SourceName);\n\n        var instrumentation = new CapInstrumentation(new DiagnosticListener());\n\n        return builder.AddInstrumentation(() => instrumentation);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.PostgreSql/CAP.EFOptions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\npublic class EFOptions\n{\n    public const string DefaultSchema = \"cap\";\n\n    /// <summary>\n    /// Gets or sets the schema to use when creating database objects.\n    /// Default is <see cref=\"DefaultSchema\" />.\n    /// </summary>\n    public string Schema { get; set; } = DefaultSchema;\n\n    internal Type? DbContextType { get; set; }\n\n    /// <summary>\n    /// Data version\n    /// </summary>\n    internal string Version { get; set; } = default!;\n}"
  },
  {
    "path": "src/DotNetCore.CAP.PostgreSql/CAP.Options.Extensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP;\nusing Microsoft.EntityFrameworkCore;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.Extensions.DependencyInjection;\n\npublic static class CapOptionsExtensions\n{\n    public static CapOptions UsePostgreSql(this CapOptions options, string connectionString)\n    {\n        return options.UsePostgreSql(opt => { opt.ConnectionString = connectionString; });\n    }\n\n    public static CapOptions UsePostgreSql(this CapOptions options, Action<PostgreSqlOptions> configure)\n    {\n        if (configure == null) throw new ArgumentNullException(nameof(configure));\n\n        configure += x => x.Version = options.Version;\n\n        options.RegisterExtension(new PostgreSqlCapOptionsExtension(configure));\n\n        return options;\n    }\n\n    public static CapOptions UseEntityFramework<TContext>(this CapOptions options)\n        where TContext : DbContext\n    {\n        return options.UseEntityFramework<TContext>(opt => { });\n    }\n\n    public static CapOptions UseEntityFramework<TContext>(this CapOptions options, Action<EFOptions> configure)\n        where TContext : DbContext\n    {\n        if (configure == null) throw new ArgumentNullException(nameof(configure));\n\n        options.RegisterExtension(new PostgreSqlCapOptionsExtension(x =>\n        {\n            configure(x);\n            x.Version = options.Version;\n            x.DbContextType = typeof(TContext);\n        }));\n\n        return options;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.PostgreSql/CAP.PostgreSqlCapOptionsExtension.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.PostgreSql;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\ninternal class PostgreSqlCapOptionsExtension : ICapOptionsExtension\n{\n    private readonly Action<PostgreSqlOptions> _configure;\n\n    public PostgreSqlCapOptionsExtension(Action<PostgreSqlOptions> configure)\n    {\n        _configure = configure;\n    }\n\n    public void AddServices(IServiceCollection services)\n    {\n        services.AddSingleton(new CapStorageMarkerService(\"PostgreSql\"));\n        services.Configure(_configure);\n        services.AddSingleton<IConfigureOptions<PostgreSqlOptions>, ConfigurePostgreSqlOptions>();\n\n        services.AddSingleton<IDataStorage, PostgreSqlDataStorage>();\n        services.AddSingleton<IStorageInitializer, PostgreSqlStorageInitializer>();\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.PostgreSql/CAP.PostgreSqlOptions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Linq;\nusing DotNetCore.CAP.Internal;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Npgsql;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\npublic class PostgreSqlOptions : EFOptions\n{\n    /// <summary>\n    /// Gets or sets the database's connection string that will be used to store database entities.\n    /// </summary>\n    public string? ConnectionString { get; set; }\n\n    /// <summary>\n    /// Gets or sets the Npgsql data source that will be used to store database entities.\n    /// </summary>\n    public NpgsqlDataSource? DataSource { get; set; }\n\n    /// <summary>\n    /// Creates an Npgsql connection from the configured data source.\n    /// </summary>\n    internal NpgsqlConnection CreateConnection()\n    {\n        return DataSource != null ? DataSource.CreateConnection() : new NpgsqlConnection(ConnectionString);\n    }\n}\n\ninternal class ConfigurePostgreSqlOptions : IConfigureOptions<PostgreSqlOptions>\n{\n    private readonly IServiceScopeFactory _serviceScopeFactory;\n\n    public ConfigurePostgreSqlOptions(IServiceScopeFactory serviceScopeFactory)\n    {\n        _serviceScopeFactory = serviceScopeFactory;\n    }\n\n    public void Configure(PostgreSqlOptions options)\n    {\n        if (options.DbContextType == null) return;\n\n        if (Helper.IsUsingType<ICapPublisher>(options.DbContextType))\n            throw new InvalidOperationException(\n                \"We detected that you are using ICapPublisher in DbContext, please change the configuration to use the storage extension directly to avoid circular references! eg:  x.UsePostgreSql()\");\n\n        using var scope = _serviceScopeFactory.CreateScope();\n        var provider = scope.ServiceProvider;\n        using var dbContext = (DbContext)provider.GetRequiredService(options.DbContextType);\n\n        var coreOptions = dbContext.GetService<IDbContextOptions>();\n        var extension = coreOptions.Extensions.First(x => x.Info.IsDatabaseProvider);\n        options.DataSource = extension.GetType().GetProperty(nameof(options.DataSource))?.GetValue(extension) as NpgsqlDataSource;\n        if (options.DataSource == null)\n        {\n            options.ConnectionString = extension.GetType().GetProperty(nameof(options.ConnectionString))?.GetValue(extension) as string;\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.PostgreSql/DotNetCore.CAP.PostgreSql.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>\n    <PackageTags>$(PackageTags);PostgreSQL</PackageTags>\n  </PropertyGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net8.0'\">\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.Relational\" Version=\"8.0.18\" />\n  </ItemGroup>\n\t\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net9.0'\">\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.Relational\" Version=\"9.0.11\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net10.0'\">\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.Relational\" Version=\"10.0.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Npgsql\" Version=\"9.0.4\" />\n    <ProjectReference Include=\"..\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/DotNetCore.CAP.PostgreSql/ICapTransaction.PostgreSql.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Data;\nusing System.Data.Common;\nusing System.Diagnostics;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.Extensions.DependencyInjection;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\npublic class PostgreSqlCapTransaction : CapTransactionBase\n{\n    public PostgreSqlCapTransaction(IDispatcher dispatcher) : base(dispatcher)\n    {\n    }\n\n    public override void Commit()\n    {\n        Debug.Assert(DbTransaction != null);\n\n        switch (DbTransaction)\n        {\n            case IDbTransaction dbTransaction:\n                dbTransaction.Commit();\n                break;\n            case IDbContextTransaction dbContextTransaction:\n                dbContextTransaction.Commit();\n                break;\n        }\n\n        Flush();\n    }\n\n    public override async Task CommitAsync(CancellationToken cancellationToken = default)\n    {\n        Debug.Assert(DbTransaction != null);\n\n        switch (DbTransaction)\n        {\n            case DbTransaction dbTransaction:\n                await dbTransaction.CommitAsync(cancellationToken).ConfigureAwait(false);\n                break;\n            case IDbContextTransaction dbContextTransaction:\n                await dbContextTransaction.CommitAsync(cancellationToken).ConfigureAwait(false);\n                break;\n        }\n\n        await FlushAsync();\n    }\n\n    public override void Rollback()\n    {\n        Debug.Assert(DbTransaction != null);\n\n        switch (DbTransaction)\n        {\n            case IDbTransaction dbTransaction:\n                dbTransaction.Rollback();\n                break;\n            case IDbContextTransaction dbContextTransaction:\n                dbContextTransaction.Rollback();\n                break;\n        }\n    }\n\n    public override async Task RollbackAsync(CancellationToken cancellationToken = default)\n    {\n        Debug.Assert(DbTransaction != null);\n\n        switch (DbTransaction)\n        {\n            case DbTransaction dbTransaction:\n                await dbTransaction.RollbackAsync(cancellationToken).ConfigureAwait(false);\n                break;\n            case IDbContextTransaction dbContextTransaction:\n                await dbContextTransaction.RollbackAsync(cancellationToken).ConfigureAwait(false);\n                break;\n        }\n    }\n}\n\npublic static class CapTransactionExtensions\n{\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"dbConnection\">The <see cref=\"IDbConnection\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    public static ICapTransaction BeginTransaction(this IDbConnection dbConnection,\n        ICapPublisher publisher, bool autoCommit = false)\n    {\n        return BeginTransaction(dbConnection, IsolationLevel.Unspecified, publisher, autoCommit);\n    }\n\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"dbConnection\">The <see cref=\"IDbConnection\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <param name=\"isolationLevel\"><see cref=\"IsolationLevel\"/></param>\n    public static ICapTransaction BeginTransaction(this IDbConnection dbConnection,\n        IsolationLevel isolationLevel, ICapPublisher publisher, bool autoCommit = false)\n    {\n        if (dbConnection.State == ConnectionState.Closed) dbConnection.Open();\n        var dbTransaction = dbConnection.BeginTransaction(isolationLevel);\n\n        publisher.Transaction = ActivatorUtilities.CreateInstance<PostgreSqlCapTransaction>(publisher.ServiceProvider);\n        publisher.Transaction.DbTransaction = dbTransaction;\n        publisher.Transaction.AutoCommit = autoCommit;\n\n        return publisher.Transaction;\n    }\n\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"dbConnection\">The <see cref=\"IDbConnection\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <param name=\"cancellationToken\"></param>\n    public static ValueTask<ICapTransaction> BeginTransactionAsync(this IDbConnection dbConnection,\n        ICapPublisher publisher, bool autoCommit = false, CancellationToken cancellationToken = default)\n    {\n        return BeginTransactionAsync(dbConnection, IsolationLevel.Unspecified, publisher, autoCommit, cancellationToken);\n    }\n\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"dbConnection\">The <see cref=\"IDbConnection\" />.</param>\n    /// <param name=\"isolationLevel\"><see cref=\"IsolationLevel\"/></param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <param name=\"cancellationToken\"></param>\n    public static ValueTask<ICapTransaction> BeginTransactionAsync(this IDbConnection dbConnection,\n        IsolationLevel isolationLevel, ICapPublisher publisher, bool autoCommit = false, CancellationToken cancellationToken = default)\n    {\n        if (dbConnection.State == ConnectionState.Closed) ((DbConnection)dbConnection).OpenAsync(cancellationToken).GetAwaiter().GetResult();\n        var dbTransaction = ((DbConnection)dbConnection).BeginTransactionAsync(isolationLevel, cancellationToken).AsTask().GetAwaiter().GetResult();\n \n        publisher.Transaction = ActivatorUtilities.CreateInstance<PostgreSqlCapTransaction>(publisher.ServiceProvider);\n        publisher.Transaction.DbTransaction = dbTransaction;\n        publisher.Transaction.AutoCommit = autoCommit;\n\n        return ValueTask.FromResult(publisher.Transaction);\n    }\n\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"database\">The <see cref=\"DatabaseFacade\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <returns>The <see cref=\"IDbContextTransaction\" /> of EF DbContext transaction object.</returns>\n    public static IDbContextTransaction BeginTransaction(this DatabaseFacade database,\n        ICapPublisher publisher, bool autoCommit = false)\n    {\n        return BeginTransaction(database, IsolationLevel.Unspecified, publisher, autoCommit);\n    }\n\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"database\">The <see cref=\"DatabaseFacade\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"isolationLevel\">The <see cref=\"IsolationLevel\" /> to use</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <returns>The <see cref=\"IDbContextTransaction\" /> of EF DbContext transaction object.</returns>\n    public static IDbContextTransaction BeginTransaction(this DatabaseFacade database,\n        IsolationLevel isolationLevel, ICapPublisher publisher, bool autoCommit = false)\n    {\n        var trans = database.BeginTransaction(isolationLevel);\n        publisher.Transaction = ActivatorUtilities.CreateInstance<PostgreSqlCapTransaction>(publisher.ServiceProvider);\n        publisher.Transaction.DbTransaction = trans;\n        publisher.Transaction.AutoCommit = autoCommit;\n        return new CapEFDbTransaction(publisher.Transaction);\n    }\n\n    /// <summary>\n    /// Start the CAP transaction async\n    /// </summary>\n    /// <param name=\"database\">The <see cref=\"DatabaseFacade\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <param name=\"cancellationToken\"></param>\n    /// <returns>The <see cref=\"IDbContextTransaction\" /> of EF DbContext transaction object.</returns>\n    public static Task<IDbContextTransaction> BeginTransactionAsync(this DatabaseFacade database,\n        ICapPublisher publisher, bool autoCommit = false, CancellationToken cancellationToken = default)\n    {\n        return BeginTransactionAsync(database, IsolationLevel.Unspecified, publisher, autoCommit, cancellationToken);\n    }\n\n    /// <summary>\n    /// Start the CAP transaction async\n    /// </summary>\n    /// <param name=\"database\">The <see cref=\"DatabaseFacade\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"isolationLevel\">The <see cref=\"IsolationLevel\" /> to use</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <param name=\"cancellationToken\"></param>\n    /// <returns>The <see cref=\"IDbContextTransaction\" /> of EF DbContext transaction object.</returns>\n    public static Task<IDbContextTransaction> BeginTransactionAsync(this DatabaseFacade database,\n        IsolationLevel isolationLevel, ICapPublisher publisher, bool autoCommit = false, CancellationToken cancellationToken = default)\n    {\n        var trans = database.BeginTransactionAsync(isolationLevel, cancellationToken).GetAwaiter().GetResult();\n        publisher.Transaction = ActivatorUtilities.CreateInstance<PostgreSqlCapTransaction>(publisher.ServiceProvider);\n        publisher.Transaction.DbTransaction = trans;\n        publisher.Transaction.AutoCommit = autoCommit;\n        return Task.FromResult<IDbContextTransaction>(new CapEFDbTransaction(publisher.Transaction));\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.PostgreSql/IDataStorage.PostgreSql.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Data.Common;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Monitoring;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Serialization;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.Extensions.Options;\nusing Npgsql;\n\nnamespace DotNetCore.CAP.PostgreSql;\n\npublic class PostgreSqlDataStorage : IDataStorage\n{\n    private readonly IOptions<CapOptions> _capOptions;\n    private readonly IStorageInitializer _initializer;\n    private readonly string _lockName;\n    private readonly IOptions<PostgreSqlOptions> _options;\n    private readonly string _pubName;\n    private readonly string _recName;\n    private readonly ISerializer _serializer;\n    private readonly ISnowflakeId _snowflakeId;\n\n    public PostgreSqlDataStorage(\n        IOptions<PostgreSqlOptions> options,\n        IOptions<CapOptions> capOptions,\n        IStorageInitializer initializer,\n        ISerializer serializer,\n        ISnowflakeId snowflakeId)\n    {\n        _capOptions = capOptions;\n        _initializer = initializer;\n        _options = options;\n        _serializer = serializer;\n        _snowflakeId = snowflakeId;\n        _pubName = initializer.GetPublishedTableName();\n        _recName = initializer.GetReceivedTableName();\n        _lockName = initializer.GetLockTableName();\n    }\n\n    public async Task<bool> AcquireLockAsync(string key, TimeSpan ttl, string instance,\n        CancellationToken token = default)\n    {\n        var sql =\n            $\"UPDATE {_lockName} SET \\\"Instance\\\"=@Instance,\\\"LastLockTime\\\"=@LastLockTime WHERE \\\"Key\\\"=@Key AND \\\"LastLockTime\\\" < @TTL;\";\n        var connection = _options.Value.CreateConnection();\n        await using var _ = connection.ConfigureAwait(false);\n        object[] sqlParams =\n        {\n            new NpgsqlParameter(\"@Instance\", instance),\n            new NpgsqlParameter(\"@LastLockTime\", DateTime.Now),\n            new NpgsqlParameter(\"@Key\", key),\n            new NpgsqlParameter(\"@TTL\", DateTime.Now.Subtract(ttl))\n        };\n        var opResult = await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n        return opResult > 0;\n    }\n\n    public async Task ReleaseLockAsync(string key, string instance, CancellationToken token = default)\n    {\n        var sql =\n            $\"UPDATE {_lockName} SET \\\"Instance\\\"='',\\\"LastLockTime\\\"=@LastLockTime WHERE \\\"Key\\\"=@Key AND \\\"Instance\\\"=@Instance;\";\n        var connection = _options.Value.CreateConnection();\n        await using var _ = connection.ConfigureAwait(false);\n        object[] sqlParams =\n        {\n            new NpgsqlParameter(\"@Instance\", instance),\n            new NpgsqlParameter(\"@LastLockTime\", DateTime.MinValue),\n            new NpgsqlParameter(\"@Key\", key)\n        };\n        await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n    }\n\n    public async Task RenewLockAsync(string key, TimeSpan ttl, string instance, CancellationToken token = default)\n    {\n        var sql =\n            $\"UPDATE {_lockName} SET \\\"LastLockTime\\\"=\\\"LastLockTime\\\"+interval '{ttl.TotalSeconds}' second WHERE \\\"Key\\\"=@Key AND \\\"Instance\\\"=@Instance;\";\n        var connection = _options.Value.CreateConnection();\n        await using var _ = connection.ConfigureAwait(false);\n        object[] sqlParams =\n        {\n            new NpgsqlParameter(\"@Instance\", instance),\n            new NpgsqlParameter(\"@Key\", key)\n        };\n        await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n    }\n\n    public async Task ChangePublishStateToDelayedAsync(string[] ids)\n    {\n        var sql =\n            $\"UPDATE {_pubName} SET \\\"StatusName\\\"='{StatusName.Delayed}' WHERE \\\"Id\\\" IN ({string.Join(',', ids)});\";\n        var connection = _options.Value.CreateConnection();\n        await using var _ = connection.ConfigureAwait(false);\n        await connection.ExecuteNonQueryAsync(sql).ConfigureAwait(false);\n    }\n\n    public async Task ChangePublishStateAsync(MediumMessage message, StatusName state, object? transaction = null)\n    {\n        await ChangeMessageStateAsync(_pubName, message, state, transaction).ConfigureAwait(false);\n    }\n\n    public async Task ChangeReceiveStateAsync(MediumMessage message, StatusName state)\n    {\n        await ChangeMessageStateAsync(_recName, message, state).ConfigureAwait(false);\n    }\n\n    public async Task<MediumMessage> StoreMessageAsync(string name, Message content, object? transaction = null)\n    {\n        var sql =\n            $\"INSERT INTO {_pubName} (\\\"Id\\\",\\\"Version\\\",\\\"Name\\\",\\\"Content\\\",\\\"Retries\\\",\\\"Added\\\",\\\"ExpiresAt\\\",\\\"StatusName\\\")\" +\n            $\"VALUES(@Id,'{_options.Value.Version}',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);\";\n\n        var message = new MediumMessage\n        {\n            DbId = content.GetId(),\n            Origin = content,\n            Content = _serializer.Serialize(content),\n            Added = DateTime.Now,\n            ExpiresAt = null,\n            Retries = 0\n        };\n\n        object[] sqlParams =\n        {\n            new NpgsqlParameter(\"@Id\", long.Parse(message.DbId)),\n            new NpgsqlParameter(\"@Name\", name),\n            new NpgsqlParameter(\"@Content\", message.Content),\n            new NpgsqlParameter(\"@Retries\", message.Retries),\n            new NpgsqlParameter(\"@Added\", message.Added),\n            new NpgsqlParameter(\"@ExpiresAt\", message.ExpiresAt.HasValue ? message.ExpiresAt.Value : DBNull.Value),\n            new NpgsqlParameter(\"@StatusName\", nameof(StatusName.Scheduled))\n        };\n\n        if (transaction == null)\n        {\n            var connection = _options.Value.CreateConnection();\n            await using var _ = connection.ConfigureAwait(false);\n            await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n        }\n        else\n        {\n            var dbTrans = transaction as DbTransaction;\n            if (dbTrans == null && transaction is IDbContextTransaction dbContextTrans)\n                dbTrans = dbContextTrans.GetDbTransaction();\n\n            var conn = dbTrans?.Connection!;\n            await conn.ExecuteNonQueryAsync(sql, dbTrans, sqlParams).ConfigureAwait(false);\n        }\n\n        return message;\n    }\n\n    public async Task StoreReceivedExceptionMessageAsync(string name, string group, string content)\n    {\n        object[] sqlParams =\n        {\n            new NpgsqlParameter(\"@Id\", _snowflakeId.NextId()),\n            new NpgsqlParameter(\"@Name\", name),\n            new NpgsqlParameter(\"@Group\", group),\n            new NpgsqlParameter(\"@Content\", content),\n            new NpgsqlParameter(\"@Retries\", _capOptions.Value.FailedRetryCount),\n            new NpgsqlParameter(\"@Added\", DateTime.Now),\n            new NpgsqlParameter(\"@ExpiresAt\", DateTime.Now.AddSeconds(_capOptions.Value.FailedMessageExpiredAfter)),\n            new NpgsqlParameter(\"@StatusName\", nameof(StatusName.Failed))\n        };\n\n        await StoreReceivedMessage(sqlParams).ConfigureAwait(false);\n    }\n\n    public async Task<MediumMessage> StoreReceivedMessageAsync(string name, string group, Message message)\n    {\n        var mdMessage = new MediumMessage\n        {\n            DbId = _snowflakeId.NextId().ToString(),\n            Origin = message,\n            Added = DateTime.Now,\n            ExpiresAt = null,\n            Retries = 0\n        };\n\n        object[] sqlParams =\n        {\n            new NpgsqlParameter(\"@Id\", long.Parse(mdMessage.DbId)),\n            new NpgsqlParameter(\"@Name\", name),\n            new NpgsqlParameter(\"@Group\", group),\n            new NpgsqlParameter(\"@Content\", _serializer.Serialize(mdMessage.Origin)),\n            new NpgsqlParameter(\"@Retries\", mdMessage.Retries),\n            new NpgsqlParameter(\"@Added\", mdMessage.Added),\n            new NpgsqlParameter(\"@ExpiresAt\", mdMessage.ExpiresAt.HasValue ? mdMessage.ExpiresAt.Value : DBNull.Value),\n            new NpgsqlParameter(\"@StatusName\", nameof(StatusName.Scheduled))\n        };\n\n        await StoreReceivedMessage(sqlParams).ConfigureAwait(false);\n\n        return mdMessage;\n    }\n\n    public async Task<int> DeleteExpiresAsync(string table, DateTime timeout, int batchCount = 1000,\n        CancellationToken token = default)\n    {\n        var connection = _options.Value.CreateConnection();\n        await using var _ = connection.ConfigureAwait(false);\n\n        return await connection.ExecuteNonQueryAsync(\n            $@\"DELETE FROM {table}\n               WHERE \"\"Id\"\" IN (\n                   SELECT \"\"Id\"\"\n                   FROM {table}\n                   WHERE \"\"ExpiresAt\"\" < @timeout\n                   AND \"\"StatusName\"\" IN ('{StatusName.Succeeded}','{StatusName.Failed}')\n                   LIMIT @batchCount\n               )\",\n             null,\n             new NpgsqlParameter(\"@timeout\", timeout),\n             new NpgsqlParameter(\"@batchCount\", batchCount)).ConfigureAwait(false);\n    }\n\n    public async Task<IEnumerable<MediumMessage>> GetPublishedMessagesOfNeedRetry(TimeSpan lookbackSeconds)\n    {\n        return await GetMessagesOfNeedRetryAsync(_pubName, lookbackSeconds).ConfigureAwait(false);\n    }\n\n    public async Task<IEnumerable<MediumMessage>> GetReceivedMessagesOfNeedRetry(TimeSpan lookbackSeconds)\n    {\n        return await GetMessagesOfNeedRetryAsync(_recName, lookbackSeconds).ConfigureAwait(false);\n    }\n\n    public async Task<int> DeleteReceivedMessageAsync(long id)\n    {\n        var sql = $@\"DELETE FROM {_recName} WHERE \"\"Id\"\"={id}\";\n\n        var connection = _options.Value.CreateConnection();\n        await using var _ = connection.ConfigureAwait(false);\n        var result = await connection.ExecuteNonQueryAsync(sql);\n        return result;\n    }\n\n    public async Task<int> DeletePublishedMessageAsync(long id)\n    {\n        var sql = $@\"DELETE FROM {_pubName} WHERE \"\"Id\"\"={id}\";\n\n        var connection = _options.Value.CreateConnection();\n        await using var _ = connection.ConfigureAwait(false);\n        var result = await connection.ExecuteNonQueryAsync(sql);\n        return result;\n    }\n\n    public async Task ScheduleMessagesOfDelayedAsync(Func<object, IEnumerable<MediumMessage>, Task> scheduleTask,\n        CancellationToken token = default)\n    {\n        var sql =\n            $\"SELECT \\\"Id\\\",\\\"Content\\\",\\\"Retries\\\",\\\"Added\\\",\\\"ExpiresAt\\\" FROM {_pubName} WHERE \\\"Version\\\"=@Version \" +\n            $\"AND ((\\\"ExpiresAt\\\"< @TwoMinutesLater AND \\\"StatusName\\\" = '{StatusName.Delayed}') OR (\\\"ExpiresAt\\\"< @OneMinutesAgo AND \\\"StatusName\\\" = '{StatusName.Queued}')) FOR UPDATE SKIP LOCKED LIMIT @BatchSize;\";\n\n        var sqlParams = new object[]\n        {\n            new NpgsqlParameter(\"@Version\", _capOptions.Value.Version),\n            new NpgsqlParameter(\"@TwoMinutesLater\", DateTime.Now.AddMinutes(2)),\n            new NpgsqlParameter(\"@OneMinutesAgo\", QueuedMessageFetchTime()),\n            new NpgsqlParameter(\"@BatchSize\", _capOptions.Value.SchedulerBatchSize)\n        };\n\n        await using var connection = _options.Value.CreateConnection();\n        await connection.OpenAsync(token);\n        await using var transaction = await connection.BeginTransactionAsync(token);\n        var messageList = await connection.ExecuteReaderAsync(sql, async reader =>\n        {\n            var messages = new List<MediumMessage>();\n            while (await reader.ReadAsync(token).ConfigureAwait(false))\n            {\n                messages.Add(new MediumMessage\n                {\n                    DbId = reader.GetInt64(0).ToString(),\n                    Origin = _serializer.Deserialize(reader.GetString(1))!,\n                    Retries = reader.GetInt32(2),\n                    Added = reader.GetDateTime(3),\n                    ExpiresAt = reader.GetDateTime(4)\n                });\n            }\n\n            return messages;\n        }, transaction, sqlParams).ConfigureAwait(false);\n\n        await scheduleTask(transaction, messageList);\n\n        await transaction.CommitAsync(token);\n    }\n\n    public IMonitoringApi GetMonitoringApi()\n    {\n        return new PostgreSqlMonitoringApi(_options, _initializer, _serializer);\n    }\n\n    protected virtual DateTime QueuedMessageFetchTime()\n    {\n        return DateTime.Now.AddMinutes(-1);\n    }\n\n    private async Task ChangeMessageStateAsync(string tableName, MediumMessage message, StatusName state,\n        object? transaction = null)\n    {\n        var sql =\n            $\"UPDATE {tableName} SET \\\"Content\\\"=@Content,\\\"Retries\\\"=@Retries,\\\"ExpiresAt\\\"=@ExpiresAt,\\\"StatusName\\\"=@StatusName WHERE \\\"Id\\\"=@Id\";\n\n        object[] sqlParams =\n        {\n            new NpgsqlParameter(\"@Id\", long.Parse(message.DbId)),\n            new NpgsqlParameter(\"@Content\", _serializer.Serialize(message.Origin)),\n            new NpgsqlParameter(\"@Retries\", message.Retries),\n            new NpgsqlParameter(\"@ExpiresAt\", message.ExpiresAt),\n            new NpgsqlParameter(\"@StatusName\", state.ToString(\"G\"))\n        };\n\n        if (transaction is DbTransaction dbTransaction)\n        {\n            var connection = (NpgsqlConnection)dbTransaction.Connection!;\n            await connection.ExecuteNonQueryAsync(sql, dbTransaction, sqlParams).ConfigureAwait(false);\n        }\n        else\n        {\n            await using var connection = _options.Value.CreateConnection();\n            await using var _ = connection.ConfigureAwait(false);\n            await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n        }\n    }\n\n    private async Task StoreReceivedMessage(object[] sqlParams)\n    {\n        var sql =\n            $\"INSERT INTO {_recName}(\\\"Id\\\",\\\"Version\\\",\\\"Name\\\",\\\"Group\\\",\\\"Content\\\",\\\"Retries\\\",\\\"Added\\\",\\\"ExpiresAt\\\",\\\"StatusName\\\")\" +\n            $\"VALUES(@Id,'{_capOptions.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName) RETURNING \\\"Id\\\";\";\n\n        var connection = _options.Value.CreateConnection();\n        await using var _ = connection.ConfigureAwait(false);\n        await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n    }\n\n    private async Task<IEnumerable<MediumMessage>> GetMessagesOfNeedRetryAsync(string tableName, TimeSpan lookbackSeconds)\n    {\n        var fourMinAgo = DateTime.Now.Subtract(lookbackSeconds);\n        var sql =\n            $\"SELECT \\\"Id\\\",\\\"Content\\\",\\\"Retries\\\",\\\"Added\\\" FROM {tableName} WHERE \\\"Retries\\\"<@Retries \" +\n            $\"AND \\\"Version\\\"=@Version AND \\\"Added\\\"<@Added AND \\\"StatusName\\\" IN ('{StatusName.Failed}','{StatusName.Scheduled}') LIMIT 200;\";\n\n        object[] sqlParams =\n        {\n            new NpgsqlParameter(\"@Retries\", _capOptions.Value.FailedRetryCount),\n            new NpgsqlParameter(\"@Version\", _capOptions.Value.Version),\n            new NpgsqlParameter(\"@Added\", fourMinAgo)\n        };\n\n        var connection = _options.Value.CreateConnection();\n        await using var _ = connection.ConfigureAwait(false);\n        var result = await connection.ExecuteReaderAsync(sql, async reader =>\n        {\n            var messages = new List<MediumMessage>();\n            while (await reader.ReadAsync().ConfigureAwait(false))\n            {\n                messages.Add(new MediumMessage\n                {\n                    DbId = reader.GetInt64(0).ToString(),\n                    Origin = _serializer.Deserialize(reader.GetString(1))!,\n                    Retries = reader.GetInt32(2),\n                    Added = reader.GetDateTime(3)\n                });\n            }\n\n            return messages;\n        }, sqlParams: sqlParams).ConfigureAwait(false);\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP.PostgreSql/IDbConnection.Extensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.ComponentModel;\nusing System.Data;\nusing System.Data.Common;\nusing System.Threading.Tasks;\n\nnamespace DotNetCore.CAP.PostgreSql;\n\ninternal static class DbConnectionExtensions\n{\n    public static async Task<int> ExecuteNonQueryAsync(this DbConnection connection, string sql,\n        DbTransaction? transaction = null, params object[] sqlParams)\n    {\n        if (connection.State == ConnectionState.Closed) await connection.OpenAsync().ConfigureAwait(false);\n\n        var command = connection.CreateCommand();\n        await using var _ = command.ConfigureAwait(false);\n        command.CommandType = CommandType.Text;\n        command.CommandText = sql;\n        foreach (var param in sqlParams)\n        {\n            command.Parameters.Add(param);\n        }\n\n        if (transaction != null) command.Transaction = transaction;\n\n        return await command.ExecuteNonQueryAsync().ConfigureAwait(false);\n    }\n\n    public static async Task<T> ExecuteReaderAsync<T>(this DbConnection connection, string sql,\n        Func<DbDataReader, Task<T>>? readerFunc, DbTransaction? transaction = null, params object[] sqlParams)\n    {\n        if (connection.State == ConnectionState.Closed) await connection.OpenAsync().ConfigureAwait(false);\n\n        var command = connection.CreateCommand();\n        await using var _ = command.ConfigureAwait(false);\n        command.CommandType = CommandType.Text;\n        command.CommandText = sql;\n        foreach (var param in sqlParams)\n        {\n            command.Parameters.Add(param);\n        }\n\n        if (transaction != null) command.Transaction = transaction;\n\n        await using var reader = await command.ExecuteReaderAsync().ConfigureAwait(false);\n\n        T result = default!;\n        if (readerFunc != null) result = await readerFunc(reader).ConfigureAwait(false);\n\n        return result;\n    }\n\n    public static async Task<T> ExecuteScalarAsync<T>(this DbConnection connection, string sql,\n        params object[] sqlParams)\n    {\n        if (connection.State == ConnectionState.Closed) await connection.OpenAsync().ConfigureAwait(false);\n\n        var command = connection.CreateCommand();\n        await using var _ = command.ConfigureAwait(false);\n        command.CommandType = CommandType.Text;\n        command.CommandText = sql;\n        foreach (var param in sqlParams)\n        {\n            command.Parameters.Add(param);\n        }\n\n        var objValue = await command.ExecuteScalarAsync().ConfigureAwait(false);\n\n        T result = default!;\n        if (objValue != null)\n        {\n            var returnType = typeof(T);\n            var converter = TypeDescriptor.GetConverter(returnType);\n            if (converter.CanConvertFrom(objValue.GetType()))\n                result = (T)converter.ConvertFrom(objValue)!;\n            else\n                result = (T)Convert.ChangeType(objValue, returnType);\n        }\n\n        return result;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.PostgreSql/IDbContextTransaction.CAP.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Data.Common;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.EntityFrameworkCore.Storage;\n\ninternal class CapEFDbTransaction : IDbContextTransaction, IInfrastructure<DbTransaction>\n{\n    private readonly ICapTransaction _transaction;\n\n    public CapEFDbTransaction(ICapTransaction transaction)\n    {\n        _transaction = transaction;\n        var dbContextTransaction = (IDbContextTransaction)_transaction.DbTransaction!;\n        TransactionId = dbContextTransaction.TransactionId;\n    }\n\n    public void Dispose()\n    {\n        _transaction.Dispose();\n    }\n\n    public void Commit()\n    {\n        _transaction.Commit();\n    }\n\n    public void Rollback()\n    {\n        _transaction.Rollback();\n    }\n\n    public Task CommitAsync(CancellationToken cancellationToken = default)\n    {\n        return _transaction.CommitAsync(cancellationToken);\n    }\n\n    public Task RollbackAsync(CancellationToken cancellationToken = default)\n    {\n        return _transaction.RollbackAsync(cancellationToken);\n    }\n\n    public Guid TransactionId { get; }\n\n    public ValueTask DisposeAsync()\n    {\n        return new ValueTask(Task.Run(() => _transaction.Dispose()));\n    }\n\n    public DbTransaction Instance\n    {\n        get\n        {\n            var dbContextTransaction = (IDbContextTransaction)_transaction.DbTransaction!;\n            return dbContextTransaction.GetDbTransaction();\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.PostgreSql/IMonitoringApi.PostgreSql.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Monitoring;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Serialization;\nusing Microsoft.Extensions.Options;\nusing Npgsql;\n\nnamespace DotNetCore.CAP.PostgreSql;\n\npublic class PostgreSqlMonitoringApi : IMonitoringApi\n{\n    private readonly PostgreSqlOptions _options;\n    private readonly string _pubName;\n    private readonly string _recName;\n    private readonly ISerializer _serializer;\n\n    public PostgreSqlMonitoringApi(IOptions<PostgreSqlOptions> options, IStorageInitializer initializer,\n        ISerializer serializer)\n    {\n        _options = options.Value ?? throw new ArgumentNullException(nameof(options));\n        _pubName = initializer.GetPublishedTableName();\n        _recName = initializer.GetReceivedTableName();\n        _serializer = serializer;\n    }\n\n    public async Task<MediumMessage?> GetPublishedMessageAsync(long id)\n    {\n        return await GetMessageAsync(_pubName, id).ConfigureAwait(false);\n    }\n\n    public async Task<MediumMessage?> GetReceivedMessageAsync(long id)\n    {\n        return await GetMessageAsync(_recName, id).ConfigureAwait(false);\n    }\n\n    public async Task<StatisticsDto> GetStatisticsAsync()\n    {\n        var sql = $@\"\nSELECT\n(\n    SELECT COUNT(\"\"Id\"\") FROM {_pubName} WHERE \"\"StatusName\"\" = N'Succeeded'\n) AS \"\"PublishedSucceeded\"\",\n(\n    SELECT COUNT(\"\"Id\"\") FROM {_recName} WHERE \"\"StatusName\"\" = N'Succeeded'\n) AS \"\"ReceivedSucceeded\"\",\n(\n    SELECT COUNT(\"\"Id\"\") FROM {_pubName} WHERE \"\"StatusName\"\" = N'Failed'\n) AS \"\"PublishedFailed\"\",\n(\n    SELECT COUNT(\"\"Id\"\") FROM {_recName} WHERE \"\"StatusName\"\" = N'Failed'\n) AS \"\"ReceivedFailed\"\",\n(\n    SELECT COUNT(\"\"Id\"\") FROM {_pubName} WHERE \"\"StatusName\"\" = N'Delayed'\n) AS \"\"PublishedDelayed\"\";\";\n\n        var connection = _options.CreateConnection();\n        await using var _ = connection.ConfigureAwait(false);\n        var statistics = await connection.ExecuteReaderAsync(sql, async reader =>\n        {\n            var statisticsDto = new StatisticsDto();\n\n            while (await reader.ReadAsync().ConfigureAwait(false))\n            {\n                statisticsDto.PublishedSucceeded = reader.GetInt32(0);\n                statisticsDto.ReceivedSucceeded = reader.GetInt32(1);\n                statisticsDto.PublishedFailed = reader.GetInt32(2);\n                statisticsDto.ReceivedFailed = reader.GetInt32(3);\n                statisticsDto.PublishedDelayed = reader.GetInt32(4);\n            }\n\n            return statisticsDto;\n        }).ConfigureAwait(false);\n\n        return statistics;\n    }\n\n    public async Task<PagedQueryResult<MessageDto>> GetMessagesAsync(MessageQueryDto queryDto)\n    {\n        var tableName = queryDto.MessageType == MessageType.Publish ? _pubName : _recName;\n        var where = string.Empty;\n\n        if (!string.IsNullOrEmpty(queryDto.StatusName)) where += \" AND Lower(\\\"StatusName\\\") = Lower(@StatusName)\";\n\n        if (!string.IsNullOrEmpty(queryDto.Name)) where += \" AND Lower(\\\"Name\\\") = Lower(@Name)\";\n\n        if (!string.IsNullOrEmpty(queryDto.Group)) where += \" AND Lower(\\\"Group\\\") = Lower(@Group)\";\n\n        if (!string.IsNullOrEmpty(queryDto.Content)) where += \" AND \\\"Content\\\" ILike @Content\";\n\n        var sqlQuery =\n            $\"SELECT * FROM {tableName} WHERE 1=1 {where} ORDER BY \\\"Added\\\" DESC OFFSET @Offset LIMIT @Limit\";\n\n        var connection = _options.CreateConnection();\n        await using var _ = connection.ConfigureAwait(false);\n\n        var count = await connection.ExecuteScalarAsync<int>($\"SELECT COUNT(1) FROM {tableName} WHERE 1=1 {where}\",\n            new NpgsqlParameter(\"@StatusName\", queryDto.StatusName ?? string.Empty),\n            new NpgsqlParameter(\"@Group\", queryDto.Group ?? string.Empty),\n            new NpgsqlParameter(\"@Name\", queryDto.Name ?? string.Empty),\n            new NpgsqlParameter(\"@Content\", $\"%{queryDto.Content}%\")).ConfigureAwait(false);\n\n        object[] sqlParams =\n        {\n            new NpgsqlParameter(\"@StatusName\", queryDto.StatusName ?? string.Empty),\n            new NpgsqlParameter(\"@Group\", queryDto.Group ?? string.Empty),\n            new NpgsqlParameter(\"@Name\", queryDto.Name ?? string.Empty),\n            new NpgsqlParameter(\"@Content\", $\"%{queryDto.Content}%\"),\n            new NpgsqlParameter(\"@Offset\", queryDto.CurrentPage * queryDto.PageSize),\n            new NpgsqlParameter(\"@Limit\", queryDto.PageSize)\n        };\n\n        var items = await connection.ExecuteReaderAsync(sqlQuery, async reader =>\n        {\n            var messages = new List<MessageDto>();\n\n            while (await reader.ReadAsync().ConfigureAwait(false))\n            {\n                var index = 0;\n                messages.Add(new MessageDto\n                {\n                    Id = reader.GetInt64(index++).ToString(),\n                    Version = reader.GetString(index++),\n                    Name = reader.GetString(index++),\n                    Group = queryDto.MessageType == MessageType.Subscribe ? reader.GetString(index++) : default,\n                    Content = reader.GetString(index++),\n                    Retries = reader.GetInt32(index++),\n                    Added = reader.GetDateTime(index++),\n                    ExpiresAt = reader.IsDBNull(index++) ? null : reader.GetDateTime(index - 1),\n                    StatusName = reader.GetString(index)\n                });\n            }\n\n            return messages;\n        }, sqlParams: sqlParams).ConfigureAwait(false);\n\n        return new PagedQueryResult<MessageDto>\n            { Items = items, PageIndex = queryDto.CurrentPage, PageSize = queryDto.PageSize, Totals = count };\n    }\n\n    public ValueTask<int> PublishedFailedCount()\n    {\n        return GetNumberOfMessage(_pubName, nameof(StatusName.Failed));\n    }\n\n    public ValueTask<int> PublishedSucceededCount()\n    {\n        return GetNumberOfMessage(_pubName, nameof(StatusName.Succeeded));\n    }\n\n    public ValueTask<int> ReceivedFailedCount()\n    {\n        return GetNumberOfMessage(_recName, nameof(StatusName.Failed));\n    }\n\n    public ValueTask<int> ReceivedSucceededCount()\n    {\n        return GetNumberOfMessage(_recName, nameof(StatusName.Succeeded));\n    }\n\n    public async Task<IDictionary<DateTime, int>> HourlySucceededJobs(MessageType type)\n    {\n        var tableName = type == MessageType.Publish ? _pubName : _recName;\n        return await GetHourlyTimelineStats(tableName, nameof(StatusName.Succeeded)).ConfigureAwait(false);\n    }\n\n    public async Task<IDictionary<DateTime, int>> HourlyFailedJobs(MessageType type)\n    {\n        var tableName = type == MessageType.Publish ? _pubName : _recName;\n        return await GetHourlyTimelineStats(tableName, nameof(StatusName.Failed)).ConfigureAwait(false);\n    }\n\n    private async ValueTask<int> GetNumberOfMessage(string tableName, string statusName)\n    {\n        var sqlQuery =\n            $\"SELECT COUNT(\\\"Id\\\") FROM {tableName} WHERE Lower(\\\"StatusName\\\") = Lower(@State)\";\n\n        var connection = _options.CreateConnection();\n        await using var _ = connection.ConfigureAwait(false);\n        return await connection.ExecuteScalarAsync<int>(sqlQuery, new NpgsqlParameter(\"@State\", statusName))\n            .ConfigureAwait(false);\n    }\n\n    private Task<Dictionary<DateTime, int>> GetHourlyTimelineStats(string tableName, string statusName)\n    {\n        var endDate = DateTime.Now;\n        var dates = new List<DateTime>();\n        for (var i = 0; i < 24; i++)\n        {\n            dates.Add(endDate);\n            endDate = endDate.AddHours(-1);\n        }\n\n        var keyMaps = dates.ToDictionary(x => x.ToString(\"yyyy-MM-dd-HH\"), x => x);\n\n        return GetTimelineStats(tableName, statusName, keyMaps);\n    }\n\n    private async Task<Dictionary<DateTime, int>> GetTimelineStats(\n        string tableName,\n        string statusName,\n        IDictionary<string, DateTime> keyMaps)\n    {\n        var sqlQuery =\n            $@\"\nWITH Aggr AS (\n    SELECT to_char(\"\"Added\"\",'yyyy-MM-dd-HH') AS \"\"Key\"\",\n    COUNT(\"\"Id\"\") AS \"\"Count\"\"\n    FROM {tableName}\n        WHERE \"\"StatusName\"\" = @StatusName\n    GROUP BY to_char(\"\"Added\"\", 'yyyy-MM-dd-HH')\n)\nSELECT \"\"Key\"\",\"\"Count\"\" from Aggr WHERE \"\"Key\"\" >= @MinKey AND \"\"Key\"\" <= @MaxKey;\";\n\n        object[] sqlParams =\n        {\n            new NpgsqlParameter(\"@StatusName\", statusName),\n            new NpgsqlParameter(\"@MinKey\", keyMaps.Keys.Min()),\n            new NpgsqlParameter(\"@MaxKey\", keyMaps.Keys.Max())\n        };\n\n        Dictionary<string, int> valuesMap;\n        var connection = _options.CreateConnection();\n        await using (connection.ConfigureAwait(false))\n        {\n            valuesMap = await connection.ExecuteReaderAsync(sqlQuery, async reader =>\n            {\n                var dictionary = new Dictionary<string, int>();\n\n                while (await reader.ReadAsync().ConfigureAwait(false))\n                {\n                    dictionary.Add(reader.GetString(0), reader.GetInt32(1));\n                }\n\n                return dictionary;\n            }, sqlParams: sqlParams).ConfigureAwait(false);\n        }\n\n        foreach (var key in keyMaps.Keys)\n        {\n            valuesMap.TryAdd(key, 0);\n        }\n\n        var result = new Dictionary<DateTime, int>();\n        for (var i = 0; i < keyMaps.Count; i++)\n        {\n            var value = valuesMap[keyMaps.ElementAt(i).Key];\n            result.Add(keyMaps.ElementAt(i).Value, value);\n        }\n\n        return result;\n    }\n\n    private async Task<MediumMessage?> GetMessageAsync(string tableName, long id)\n    {\n        var sql =\n            $@\"SELECT \"\"Id\"\" AS \"\"DbId\"\", \"\"Content\"\", \"\"Added\"\", \"\"ExpiresAt\"\", \"\"Retries\"\" FROM {tableName} WHERE \"\"Id\"\"={id} FOR UPDATE SKIP LOCKED\";\n\n        var connection = _options.CreateConnection();\n        await using var _ = connection.ConfigureAwait(false);\n        var mediumMessage = await connection.ExecuteReaderAsync(sql, async reader =>\n        {\n            MediumMessage? message = null;\n\n            while (await reader.ReadAsync().ConfigureAwait(false))\n            {\n                message = new MediumMessage\n                {\n                    DbId = reader.GetInt64(0).ToString(),\n                    Origin = _serializer.Deserialize(reader.GetString(1))!,\n                    Content = reader.GetString(1),\n                    Added = reader.GetDateTime(2),\n                    ExpiresAt = reader.GetDateTime(3),\n                    Retries = reader.GetInt32(4)\n                };\n            }\n\n            return message;\n        }).ConfigureAwait(false);\n\n        return mediumMessage;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.PostgreSql/IStorageInitializer.PostgreSql.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Persistence;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Npgsql;\n\nnamespace DotNetCore.CAP.PostgreSql;\n\npublic class PostgreSqlStorageInitializer : IStorageInitializer\n{\n    private readonly IOptions<CapOptions> _capOptions;\n    private readonly ILogger _logger;\n    private readonly IOptions<PostgreSqlOptions> _options;\n\n    public PostgreSqlStorageInitializer(\n        ILogger<PostgreSqlStorageInitializer> logger,\n        IOptions<PostgreSqlOptions> options, IOptions<CapOptions> capOptions)\n    {\n        _capOptions = capOptions;\n        _options = options;\n        _logger = logger;\n    }\n\n    public virtual string GetPublishedTableName()\n    {\n        return $\"\\\"{_options.Value.Schema}\\\".\\\"published\\\"\";\n    }\n\n    public virtual string GetReceivedTableName()\n    {\n        return $\"\\\"{_options.Value.Schema}\\\".\\\"received\\\"\";\n    }\n\n    public virtual string GetLockTableName()\n    {\n        return $\"\\\"{_options.Value.Schema}\\\".\\\"lock\\\"\";\n    }\n\n    public async Task InitializeAsync(CancellationToken cancellationToken)\n    {\n        if (cancellationToken.IsCancellationRequested) return;\n\n        var sql = CreateDbTablesScript(_options.Value.Schema);\n        var connection = _options.Value.CreateConnection();\n        await using var _ = connection.ConfigureAwait(false);\n        object[] sqlParams =\n        {\n            new NpgsqlParameter(\"@PubKey\", $\"publish_retry_{_capOptions.Value.Version}\"),\n            new NpgsqlParameter(\"@RecKey\", $\"received_retry_{_capOptions.Value.Version}\"),\n            new NpgsqlParameter(\"@LastLockTime\", DateTime.MinValue)\n        };\n        await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n\n        _logger.LogDebug(\"Ensuring all create database tables script are applied.\");\n    }\n\n    protected virtual string CreateDbTablesScript(string schema)\n    {\n        var batchSql = $@\"\nCREATE SCHEMA IF NOT EXISTS \"\"{schema}\"\";\n\nCREATE TABLE IF NOT EXISTS {GetReceivedTableName()}(\n\t\"\"Id\"\" BIGINT PRIMARY KEY NOT NULL,\n    \"\"Version\"\" VARCHAR(20) NOT NULL,\n\t\"\"Name\"\" VARCHAR(200) NOT NULL,\n\t\"\"Group\"\" VARCHAR(200) NULL,\n\t\"\"Content\"\" TEXT NULL,\n\t\"\"Retries\"\" INT NOT NULL,\n\t\"\"Added\"\" TIMESTAMP NOT NULL,\n    \"\"ExpiresAt\"\" TIMESTAMP NULL,\n\t\"\"StatusName\"\" VARCHAR(50) NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS \"\"idx_received_ExpiresAt_StatusName\"\" ON {GetReceivedTableName()} (\"\"ExpiresAt\"\",\"\"StatusName\"\");\nCREATE INDEX IF NOT EXISTS \"\"idx_received_Version_ExpiresAt_StatusName\"\" ON {GetReceivedTableName()} (\"\"Version\"\",\"\"ExpiresAt\"\",\"\"StatusName\"\");\n\nCREATE TABLE IF NOT EXISTS {GetPublishedTableName()}(\n\t\"\"Id\"\" BIGINT PRIMARY KEY NOT NULL,\n    \"\"Version\"\" VARCHAR(20) NOT NULL,\n\t\"\"Name\"\" VARCHAR(200) NOT NULL,\n\t\"\"Content\"\" TEXT NULL,\n\t\"\"Retries\"\" INT NOT NULL,\n\t\"\"Added\"\" TIMESTAMP NOT NULL,\n    \"\"ExpiresAt\"\" TIMESTAMP NULL,\n\t\"\"StatusName\"\" VARCHAR(50) NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS \"\"idx_published_ExpiresAt_StatusName\"\" ON {GetPublishedTableName()}(\"\"ExpiresAt\"\",\"\"StatusName\"\");\nCREATE INDEX IF NOT EXISTS \"\"idx_published_Version_ExpiresAt_StatusName\"\" ON {GetPublishedTableName()} (\"\"Version\"\",\"\"ExpiresAt\"\",\"\"StatusName\"\");\";\n\n        if (_capOptions.Value.UseStorageLock)\n            batchSql += $@\"\nCREATE TABLE IF NOT EXISTS {GetLockTableName()}(\n\t\"\"Key\"\" VARCHAR(128) PRIMARY KEY NOT NULL,\n    \"\"Instance\"\" VARCHAR(256),\n\t\"\"LastLockTime\"\" TIMESTAMP NOT NULL\n);\n\nINSERT INTO {GetLockTableName()} (\"\"Key\"\",\"\"Instance\"\",\"\"LastLockTime\"\") VALUES(@PubKey,'',@LastLockTime) ON CONFLICT DO NOTHING;\nINSERT INTO {GetLockTableName()} (\"\"Key\"\",\"\"Instance\"\",\"\"LastLockTime\"\") VALUES(@RecKey,'',@LastLockTime) ON CONFLICT DO NOTHING;\";\n\n        return batchSql;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Pulsar/CAP.Options.Extensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.Extensions.DependencyInjection;\n\npublic static class CapOptionsExtensions\n{\n    /// <summary>\n    /// Configuration to use pulsar in CAP.\n    /// </summary>\n    /// <param name=\"options\">CAP configuration options</param>\n    /// <param name=\"serverUrl\">Pulsar bootstrap server urls.</param>\n    public static CapOptions UsePulsar(this CapOptions options, string serverUrl)\n    {\n        return options.UsePulsar(opt => { opt.ServiceUrl = serverUrl; });\n    }\n\n    /// <summary>\n    /// Configuration to use pulsar in CAP.\n    /// </summary>\n    /// <param name=\"options\">CAP configuration options</param>\n    /// <param name=\"configure\">Provides programmatic configuration for the pulsar .</param>\n    /// <returns></returns>\n    public static CapOptions UsePulsar(this CapOptions options, Action<PulsarOptions> configure)\n    {\n        if (configure == null) throw new ArgumentNullException(nameof(configure));\n\n        options.RegisterExtension(new PulsarCapOptionsExtension(configure));\n\n        return options;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Pulsar/CAP.PulsarCapOptionsExtension.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP.Pulsar;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.DependencyInjection;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\ninternal sealed class PulsarCapOptionsExtension : ICapOptionsExtension\n{\n    private readonly Action<PulsarOptions> _configure;\n\n    public PulsarCapOptionsExtension(Action<PulsarOptions> configure)\n    {\n        _configure = configure;\n    }\n\n    public void AddServices(IServiceCollection services)\n    {\n        services.AddSingleton(new CapMessageQueueMakerService(\"Apache Pulsar\"));\n\n        services.Configure(_configure);\n\n        services.AddSingleton<ITransport, PulsarTransport>();\n        services.AddSingleton<IConsumerClientFactory, PulsarConsumerClientFactory>();\n        services.AddSingleton<IConnectionFactory, ConnectionFactory>();\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Pulsar/CAP.PulsarOptions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\n// ReSharper disable once CheckNamespace\n\nusing System.Security.Authentication;\nusing System.Security.Cryptography.X509Certificates;\nusing DotNetCore.CAP.Pulsar;\nusing Pulsar.Client.Api;\n\nnamespace DotNetCore.CAP\n{\n    /// <summary>\n    /// Provides programmatic configuration for the CAP pulsar project.\n    /// </summary>\n    public class PulsarOptions\n    {\n        public string ServiceUrl { get; set; } = default!;\n\n        public bool EnableClientLog { get; set; } = false;\n\n        public TlsOptions? TlsOptions { get; set; }\n    }\n}\n\nnamespace DotNetCore.CAP.Pulsar\n{\n    public class TlsOptions\n    {\n        private static readonly PulsarClientConfiguration Default =\n            PulsarClientConfiguration.Default;\n\n        public bool UseTls { get; set; } = Default.UseTls;\n        public bool TlsHostnameVerificationEnable { get; set; } = Default.TlsHostnameVerificationEnable;\n        public bool TlsAllowInsecureConnection { get; set; } = Default.TlsAllowInsecureConnection;\n        public X509Certificate2 TlsTrustCertificate { get; set; } = Default.TlsTrustCertificate;\n        public Authentication Authentication { get; set; } = Default.Authentication;\n        public SslProtocols TlsProtocols { get; set; } = Default.TlsProtocols;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Pulsar/DotNetCore.CAP.Pulsar.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<TargetFramework>net8.0</TargetFramework>\n\t\t<Nullable>enable</Nullable>\n\t\t<PackageTags>$(PackageTags);Pulsar</PackageTags>\n\t\t<NoWarn>CS0067</NoWarn>\n\t</PropertyGroup>\n\n\t<ItemGroup>\n\t\t<ProjectReference Include=\"..\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n\t\t<PackageReference Include=\"Pulsar.Client\" Version=\"3.13.0\" />\n\t</ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/DotNetCore.CAP.Pulsar/IConnectionFactory.Default.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Concurrent;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Newtonsoft.Json;\nusing Pulsar.Client.Api;\n\nnamespace DotNetCore.CAP.Pulsar;\n\npublic class ConnectionFactory : IConnectionFactory, IAsyncDisposable\n{\n    private readonly ILogger<ConnectionFactory> _logger;\n    private readonly PulsarOptions _options;\n    private readonly ConcurrentDictionary<string, Task<IProducer<byte[]>>> _topicProducers;\n    private PulsarClient? _client;\n\n    public ConnectionFactory(ILogger<ConnectionFactory> logger, IOptions<PulsarOptions> options)\n    {\n        _logger = logger;\n        _options = options.Value;\n        _topicProducers = new ConcurrentDictionary<string, Task<IProducer<byte[]>>>();\n\n        logger.LogDebug(\"CAP Pulsar configuration: {0}\", JsonConvert.SerializeObject(_options, Formatting.Indented));\n    }\n\n    public async ValueTask DisposeAsync()\n    {\n        foreach (var value in _topicProducers.Values)\n        {\n            _ = (await value).DisposeAsync();\n        }\n    }\n\n    public string ServersAddress => _options.ServiceUrl;\n\n    public async Task<IProducer<byte[]>> CreateProducerAsync(string topic)\n    {\n        _client ??= RentClient();\n\n        async Task<IProducer<byte[]>> ValueFactory(string top)\n        {\n            return await _client.NewProducer()\n                .Topic(top)\n                .CreateAsync();\n        }\n\n        //connection may lost\n        return await _topicProducers.GetOrAdd(topic, ValueFactory);\n    }\n\n    public PulsarClient RentClient()\n    {\n        lock (this)\n        {\n            if (_client == null)\n            {\n                var builder = new PulsarClientBuilder().ServiceUrl(_options.ServiceUrl);\n                if (_options.TlsOptions != null)\n                {\n                    builder.EnableTls(_options.TlsOptions.UseTls);\n                    builder.EnableTlsHostnameVerification(_options.TlsOptions.TlsHostnameVerificationEnable);\n                    builder.AllowTlsInsecureConnection(_options.TlsOptions.TlsAllowInsecureConnection);\n                    builder.TlsTrustCertificate(_options.TlsOptions.TlsTrustCertificate);\n                    builder.Authentication(_options.TlsOptions.Authentication);\n                    builder.TlsProtocols(_options.TlsOptions.TlsProtocols);\n                }\n\n                _client = builder.BuildAsync().Result;\n            }\n\n            return _client;\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Pulsar/IConnectionFactory.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Threading.Tasks;\nusing Pulsar.Client.Api;\n\nnamespace DotNetCore.CAP.Pulsar;\n\npublic interface IConnectionFactory\n{\n    string ServersAddress { get; }\n\n    Task<IProducer<byte[]>> CreateProducerAsync(string topic);\n\n    PulsarClient RentClient();\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Pulsar/ITransport.Pulsar.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Logging;\n\nnamespace DotNetCore.CAP.Pulsar;\n\ninternal class PulsarTransport : ITransport\n{\n    private readonly IConnectionFactory _connectionFactory;\n    private readonly ILogger _logger;\n\n    public PulsarTransport(ILogger<PulsarTransport> logger, IConnectionFactory connectionFactory)\n    {\n        _logger = logger;\n        _connectionFactory = connectionFactory;\n    }\n\n    public BrokerAddress BrokerAddress => new(\"Pulsar\", _connectionFactory.ServersAddress);\n\n    public async Task<OperateResult> SendAsync(TransportMessage message)\n    {\n        var producer = await _connectionFactory.CreateProducerAsync(message.GetName());\n\n        try\n        {\n            var headerDic = new Dictionary<string, string?>(message.Headers);\n            headerDic.TryGetValue(PulsarHeaders.PulsarKey, out var key);\n            var pulsarMessage = producer.NewMessage(message.Body.ToArray()!, key, headerDic);\n            var messageId = await producer.SendAsync(pulsarMessage);\n            \n            if (messageId != null)\n            {\n                _logger.LogDebug($\"pulsar topic message [{message.GetName()}] has been published.\");\n\n                return OperateResult.Success;\n            }\n\n            throw new PublisherSentFailedException(\"pulsar message persisted failed!\");\n        }\n        catch (Exception ex)\n        {\n            var wrapperEx = new PublisherSentFailedException(ex.Message, ex);\n\n            return OperateResult.Failed(wrapperEx);\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Pulsar/PulsarConsumerClient.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Options;\nusing Pulsar.Client.Api;\nusing Pulsar.Client.Common;\n\nnamespace DotNetCore.CAP.Pulsar;\n\ninternal sealed class PulsarConsumerClient : IConsumerClient\n{\n    private readonly PulsarClient _client;\n    private readonly string _groupId;\n    private readonly byte _groupConcurrent;\n    private readonly SemaphoreSlim _semaphore;\n    private readonly PulsarOptions _pulsarOptions;\n    private IConsumer<byte[]>? _consumerClient;\n\n    public PulsarConsumerClient(IOptions<PulsarOptions> options, PulsarClient client, string groupName, byte groupConcurrent)\n    {\n        _client = client;\n        _groupId = groupName;\n        _groupConcurrent = groupConcurrent;\n        _semaphore = new SemaphoreSlim(groupConcurrent);\n        _pulsarOptions = options.Value;\n    }\n\n    public Func<TransportMessage, object?, Task>? OnMessageCallback { get; set; }\n\n    public Action<LogMessageEventArgs>? OnLogCallback { get; set; }\n\n    public BrokerAddress BrokerAddress => new(\"pulsar\", _pulsarOptions.ServiceUrl);\n\n    public async Task SubscribeAsync(IEnumerable<string> topics)\n    {\n        if (topics == null) throw new ArgumentNullException(nameof(topics));\n\n        var serviceName = Assembly.GetEntryAssembly()?.GetName().Name!.ToLower();\n\n        _consumerClient = await _client.NewConsumer()\n            .Topics(topics)\n            .SubscriptionName(_groupId)\n            .ConsumerName(serviceName)\n            .SubscriptionType(SubscriptionType.Shared)\n            .SubscribeAsync();\n    }\n\n    public async Task ListeningAsync(TimeSpan timeout, CancellationToken cancellationToken)\n    {\n        while (!cancellationToken.IsCancellationRequested)\n        {\n            try\n            {\n                var consumerResult = await _consumerClient!.ReceiveAsync(cancellationToken);\n\n                if (_groupConcurrent > 0)\n                {\n                    _semaphore.Wait(cancellationToken);\n                    _ = Task.Run(ConsumeAsync, cancellationToken).ConfigureAwait(false);\n                }\n                else\n                {\n                    await ConsumeAsync();\n                }\n\n                Task ConsumeAsync()\n                {\n                    var headers = new Dictionary<string, string?>(consumerResult.Properties.Count);\n                    foreach (var header in consumerResult.Properties)\n                    {\n                        headers.Add(header.Key, header.Value);\n                    }\n\n                    headers[Headers.Group] = _groupId;\n\n                    var message = new TransportMessage(headers, consumerResult.Data);\n\n                    return OnMessageCallback!(message, consumerResult.MessageId);\n                }\n            }\n            catch (Exception e)\n            {\n                OnLogCallback!(new LogMessageEventArgs\n                {\n                    LogType = MqLogType.ConsumeError,\n                    Reason = e.Message\n                });\n            }\n        }\n    }\n\n    public async Task CommitAsync(object? sender)\n    {\n        await _consumerClient!.AcknowledgeAsync((MessageId)sender!);\n        _semaphore.Release();\n    }\n\n    public async Task RejectAsync(object? sender)\n    {\n        if (sender is MessageId id) \n           await _consumerClient!.NegativeAcknowledge(id);\n        _semaphore.Release();\n    }\n\n    public ValueTask DisposeAsync()\n    {\n        return _consumerClient?.DisposeAsync() ?? ValueTask.CompletedTask;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Pulsar/PulsarConsumerClientFactory.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Pulsar.Client.Api;\n\nnamespace DotNetCore.CAP.Pulsar;\n\ninternal sealed class PulsarConsumerClientFactory : IConsumerClientFactory\n{\n    private readonly IConnectionFactory _connection;\n    private readonly IOptions<PulsarOptions> _pulsarOptions;\n\n    public PulsarConsumerClientFactory(IConnectionFactory connection, ILoggerFactory loggerFactory,\n        IOptions<PulsarOptions> pulsarOptions)\n    {\n        _connection = connection;\n        _pulsarOptions = pulsarOptions;\n\n        if (_pulsarOptions.Value.EnableClientLog) PulsarClient.Logger = loggerFactory.CreateLogger<PulsarClient>();\n    }\n\n    public Task<IConsumerClient> CreateAsync(string groupName, byte groupConcurrent)\n    {\n        try\n        {\n            var client = _connection.RentClient();\n            var consumerClient = new PulsarConsumerClient(_pulsarOptions, client, groupName, groupConcurrent);\n            return Task.FromResult<IConsumerClient>(consumerClient);\n        }\n        catch (Exception e)\n        {\n            throw new BrokerConnectionException(e);\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.Pulsar/PulsarHeaders.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nnamespace DotNetCore.CAP.Pulsar;\n\npublic static class PulsarHeaders\n{\n    public const string PulsarKey = \"cap-pulsar-key\";\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RabbitMQ/CAP.Options.Extensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.Extensions.DependencyInjection;\n\npublic static class CapOptionsExtensions\n{\n    // ReSharper disable once InconsistentNaming\n    public static CapOptions UseRabbitMQ(this CapOptions options, string hostName)\n    {\n        return options.UseRabbitMQ(opt => { opt.HostName = hostName; });\n    }\n\n    // ReSharper disable once InconsistentNaming\n    public static CapOptions UseRabbitMQ(this CapOptions options, Action<RabbitMQOptions> configure)\n    {\n        if (configure == null) throw new ArgumentNullException(nameof(configure));\n\n        options.RegisterExtension(new RabbitMqCapOptionsExtension(configure));\n\n        return options;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RabbitMQ/CAP.RabbiMQOptions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing RabbitMQ.Client;\nusing RabbitMQ.Client.Events;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\n// ReSharper disable once InconsistentNaming\npublic class RabbitMQOptions\n{\n    /// <summary>\n    /// Default password (value: \"guest\").\n    /// </summary>\n    /// <remarks>PLEASE KEEP THIS MATCHING THE DOC ABOVE.</remarks>\n    public const string DefaultPass = \"guest\";\n\n    /// <summary>\n    /// Default user name (value: \"guest\").\n    /// </summary>\n    /// <remarks>PLEASE KEEP THIS MATCHING THE DOC ABOVE.</remarks>\n    public const string DefaultUser = \"guest\";\n\n    /// <summary>\n    /// Default virtual host (value: \"/\").\n    /// </summary>\n    /// <remarks> PLEASE KEEP THIS MATCHING THE DOC ABOVE.</remarks>\n    public const string DefaultVHost = \"/\";\n\n    /// <summary>\n    /// Default exchange name (value: \"cap.default.router\").\n    /// </summary>\n    public const string DefaultExchangeName = \"cap.default.router\";\n\n    /// <summary> The topic exchange type. </summary>\n    public const string ExchangeType = \"topic\";\n\n    /// <summary>\n    /// The host to connect to.\n    /// If you want to connect to the cluster, you can assign like “192.168.1.111,192.168.1.112”\n    /// </summary>\n    public string HostName { get; set; } = \"localhost\";\n\n    /// <summary>\n    /// Password to use when authenticating to the server.\n    /// </summary>\n    public string Password { get; set; } = DefaultPass;\n\n    /// <summary>\n    /// Username to use when authenticating to the server.\n    /// </summary>\n    public string UserName { get; set; } = DefaultUser;\n\n    /// <summary>\n    /// Virtual host to access during this connection.\n    /// </summary>\n    public string VirtualHost { get; set; } = DefaultVHost;\n\n    /// <summary>\n    /// Topic exchange name when declare a topic exchange.\n    /// </summary>\n    public string ExchangeName { get; set; } = DefaultExchangeName;\n\n    /// <summary>\n    /// Enabling Publisher Confirms on a Channel\n    /// </summary>\n    public bool PublishConfirms { get; set; }\n\n    /// <summary>\n    /// The port to connect on.\n    /// </summary>\n    public int Port { get; set; } = -1;\n\n    /// <summary>\n    /// Optional queue arguments, also known as \"x-arguments\" because of their field name in the AMQP 0-9-1 protocol,\n    /// is a map (dictionary) of arbitrary key/value pairs that can be provided by clients when a queue is declared.\n    /// </summary>\n    public QueueArgumentsOptions QueueArguments { get; set; } = new();\n\n\n    /// <summary>\n    /// Optional queue arguments, also known as \"x-arguments\" because of their field name in the AMQP 0-9-1 protocol,\n    /// is a map (dictionary) of arbitrary key/value pairs that can be provided by clients when a queue is declared.\n    /// </summary>\n    public QueueRabbitOptions QueueOptions { get; set; } = new();\n\n    /// <summary>\n    /// If you need to get additional native delivery args, you can use this function to write into <see cref=\"CapHeader\" />.\n    /// </summary>\n    public Func<BasicDeliverEventArgs, IServiceProvider, List<KeyValuePair<string, string>>>? CustomHeadersBuilder\n    {\n        get;\n        set;\n    }\n\n    /// <summary>\n    /// RabbitMQ native connection factory options\n    /// </summary>\n    public Action<ConnectionFactory>? ConnectionFactoryOptions { get; set; }\n\n    /// <summary>\n    /// Specify quality of service.\n    /// <br /><br />\n    /// These settings request a specific quality of service.The QoS can be specified for the current channel or for all\n    /// channels on the connection.<br />\n    /// The particular properties and semantics of a qos method always depend on the content class semantics.<br />\n    /// Though the qos method could in principle apply to both peers, it is currently meaningful only for the server.<br />\n    /// <br />\n    /// <see href=\"https://www.rabbitmq.com/consumer-prefetch.html\">\n    /// More info at:\n    /// https://www.rabbitmq.com/consumer-prefetch.html\n    /// </see>\n    /// </summary>\n    public BasicQos? BasicQosOptions { get; set; } = null;\n\n    public class QueueArgumentsOptions\n    {\n        /// <summary>\n        /// Gets or sets queue mode by supplying the 'x-queue-mode' declaration argument with a string specifying the desired mode.\n        /// </summary>\n        public string QueueMode { get; set; } = null!;\n\n        /// <summary>\n        /// Gets or sets queue message automatic deletion time (in milliseconds) \"x-message-ttl\", Default 864000000 ms (10 days).\n        /// </summary>\n        // ReSharper disable once InconsistentNaming\n        public int MessageTTL { get; set; } = 864000000;\n\n        /// <summary>\n        /// Gets or sets queue type by supplying the 'x-queue-type' declaration argument with a string specifying the desired type.\n        /// </summary>\n        public string QueueType { get; set; } = null!;\n    }\n\n    public class BasicQos\n    {\n        /// <summary>\n        /// New instance of BasicQos sets the use of basic qos setup on the basic channel.\n        /// </summary>\n        /// <param name=\"prefetchCount\">Sets the PrefetchCount.</param>\n        /// <param name=\"global\">Sets Global flag (default false).</param>\n        public BasicQos(ushort prefetchCount, bool global = false)\n        {\n            PrefetchCount = prefetchCount;\n            Global = global;\n        }\n\n        /// <summary>\n        /// Gets the PrefetchCount, a value of 0 is treated as infinite, allowing any number of unacknowledged message being pushed\n        /// to consumer.\n        /// The default value is 0.\n        /// </summary>\n        public ushort PrefetchCount { get; }\n\n        /// <summary>\n        /// Gets the global flag across all consumers in RabbitMq.\n        /// false (default) - applied separately to each new consumer on the channel\n        /// true - shared across all consumers on the channel\n        /// </summary>\n        public bool Global { get; }\n    }\n\n    public class QueueRabbitOptions\n    {\n        public bool Durable { get; set; } = true;\n        public bool Exclusive { get; set; } = false;\n        public bool AutoDelete { get; set; } = false;\n    }\n}\n\n"
  },
  {
    "path": "src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP.RabbitMQ;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.DependencyInjection;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\ninternal sealed class RabbitMqCapOptionsExtension : ICapOptionsExtension\n{\n    private readonly Action<RabbitMQOptions> _configure;\n\n    public RabbitMqCapOptionsExtension(Action<RabbitMQOptions> configure)\n    {\n        _configure = configure;\n    }\n\n    public void AddServices(IServiceCollection services)\n    {\n        services.AddSingleton(new CapMessageQueueMakerService(\"RabbitMQ\"));\n\n        services.Configure(_configure);\n        services.AddSingleton<ITransport, RabbitMqTransport>();\n        services.AddSingleton<IConsumerClientFactory, RabbitMqConsumerClientFactory>();\n        services.AddSingleton<IConnectionChannelPool, ConnectionChannelPool>();\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RabbitMQ/DotNetCore.CAP.RabbitMQ.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  \n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\t<Nullable>enable</Nullable>\n    <PackageTags>$(PackageTags);RabbitMQ</PackageTags>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"RabbitMQ.Client\" Version=\"7.2.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "src/DotNetCore.CAP.RabbitMQ/IConnectionChannelPool.Default.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Concurrent;\nusing System.Diagnostics;\nusing System.Reflection;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing RabbitMQ.Client;\n\nnamespace DotNetCore.CAP.RabbitMQ;\n\npublic class ConnectionChannelPool : IConnectionChannelPool, IDisposable\n{\n    private const int DefaultPoolSize = 15;\n    private static readonly object SLock = new();\n\n    private readonly Func<Task<IConnection>> _connectionActivator;\n    private readonly bool _isPublishConfirms;\n    private readonly ILogger<ConnectionChannelPool> _logger;\n    private readonly ConcurrentQueue<IChannel> _pool;\n    private IConnection? _connection;\n\n    private int _count;\n    private int _maxSize;\n\n    public ConnectionChannelPool(\n        ILogger<ConnectionChannelPool> logger,\n        IOptions<CapOptions> capOptionsAccessor,\n        IOptions<RabbitMQOptions> optionsAccessor)\n    {\n        _logger = logger;\n        _maxSize = DefaultPoolSize;\n        _pool = new ConcurrentQueue<IChannel>();\n\n        var capOptions = capOptionsAccessor.Value;\n        var options = optionsAccessor.Value;\n\n        _connectionActivator = CreateConnection(options);\n        _isPublishConfirms = options.PublishConfirms;\n\n        HostAddress = $\"{options.HostName}:{options.Port}\";\n        Exchange = \"v1\" == capOptions.Version ? options.ExchangeName : $\"{options.ExchangeName}.{capOptions.Version}\";\n\n        _logger.LogDebug(\n            $\"RabbitMQ configuration:'HostName:{options.HostName}, Port:{options.Port}, UserName:{options.UserName}, VirtualHost:{options.VirtualHost}, ExchangeName:{options.ExchangeName}'\");\n    }\n\n    Task<IChannel> IConnectionChannelPool.Rent()\n    {\n        lock (SLock)\n        {\n            while (_count > _maxSize)\n            {\n                Thread.SpinWait(1);\n            }\n\n            return Rent();\n        }\n    }\n\n    bool IConnectionChannelPool.Return(IChannel connection)\n    {\n        return Return(connection);\n    }\n\n    public string HostAddress { get; }\n\n    public string Exchange { get; }\n\n    public IConnection GetConnection()\n    {\n        lock (SLock)\n        {\n            if (_connection != null && _connection.IsOpen) return _connection;\n\n            _connection?.Dispose();\n            _connection = _connectionActivator().GetAwaiter().GetResult();\n            return _connection;\n        }\n    }\n\n    public void Dispose()\n    {\n        _maxSize = 0;\n\n        while (_pool.TryDequeue(out var channel))\n        {\n            channel.Dispose();\n        }\n\n        _connection?.Dispose();\n    }\n\n    private static Func<Task<IConnection>> CreateConnection(RabbitMQOptions options)\n    {\n        var factory = new ConnectionFactory\n        {\n            UserName = options.UserName,\n            Port = options.Port,\n            Password = options.Password,\n            VirtualHost = options.VirtualHost,\n            ClientProvidedName = Assembly.GetEntryAssembly()?.GetName().Name!.ToLower()\n        };\n\n        if (options.HostName.Contains(\",\"))\n        {\n            options.ConnectionFactoryOptions?.Invoke(factory);\n            var endpoints = AmqpTcpEndpoint.ParseMultiple(options.HostName);\n            foreach (var endpoint in endpoints)\n            {\n                endpoint.Ssl = factory.Ssl;\n            }\n            return () => factory.CreateConnectionAsync(endpoints);\n        }\n\n        factory.HostName = options.HostName;\n        options.ConnectionFactoryOptions?.Invoke(factory);\n        return () => factory.CreateConnectionAsync();\n    }\n\n    public virtual async Task<IChannel> Rent()\n    {\n        if (_pool.TryDequeue(out var model))\n        {\n            Interlocked.Decrement(ref _count);\n\n            Debug.Assert(_count >= 0);\n\n            return model;\n        }\n\n        try\n        {\n            model = await GetConnection().CreateChannelAsync(new CreateChannelOptions(_isPublishConfirms, false));\n            await model.ExchangeDeclareAsync(Exchange, RabbitMQOptions.ExchangeType, true);\n        }\n        catch (Exception e)\n        {\n            _logger.LogError(e, \"RabbitMQ channel model create failed!\");\n            Console.WriteLine(e);\n            throw;\n        }\n\n        return model;\n    }\n\n    public virtual bool Return(IChannel channel)\n    {\n        if (Interlocked.Increment(ref _count) <= _maxSize && channel.IsOpen)\n        {\n            _pool.Enqueue(channel);\n\n            return true;\n        }\n\n        channel.Dispose();\n\n        Interlocked.Decrement(ref _count);\n\n        Debug.Assert(_maxSize == 0 || _pool.Count <= _maxSize);\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP.RabbitMQ/IConnectionChannelPool.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Threading.Tasks;\nusing RabbitMQ.Client;\n\nnamespace DotNetCore.CAP.RabbitMQ;\n\npublic interface IConnectionChannelPool\n{\n    string HostAddress { get; }\n\n    string Exchange { get; }\n\n    IConnection GetConnection();\n\n    Task<IChannel> Rent();\n\n    bool Return(IChannel context);\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RabbitMQ/ITransport.RabbitMQ.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Logging;\nusing RabbitMQ.Client;\nusing RabbitMQ.Client.Exceptions;\n\nnamespace DotNetCore.CAP.RabbitMQ;\n\ninternal sealed class RabbitMqTransport : ITransport\n{\n    private readonly IConnectionChannelPool _connectionChannelPool;\n    private readonly string _exchange;\n    private readonly ILogger _logger;\n\n    public RabbitMqTransport(ILogger<RabbitMqTransport> logger, IConnectionChannelPool connectionChannelPool)\n    {\n        _logger = logger;\n        _connectionChannelPool = connectionChannelPool;\n        _exchange = _connectionChannelPool.Exchange;\n    }\n\n    public BrokerAddress BrokerAddress => new(\"RabbitMQ\", _connectionChannelPool.HostAddress);\n\n    public async Task<OperateResult> SendAsync(TransportMessage message)\n    {\n        IChannel? channel = null;\n        try\n        {\n            channel = await _connectionChannelPool.Rent();\n\n            var props = new BasicProperties\n            {\n                MessageId = message.GetId(),\n                DeliveryMode = DeliveryModes.Persistent,\n                Headers = message.Headers.ToDictionary(x => x.Key, object? (x) => x.Value)\n            };\n\n            await channel.BasicPublishAsync(_exchange, message.GetName(), false, props, message.Body);\n\n            _logger.LogInformation(\"CAP message '{0}' published, internal id '{1}'\", message.GetName(), message.GetId());\n\n            return OperateResult.Success;\n        }\n        catch (Exception ex)\n        {\n            if (ex is AlreadyClosedException && channel?.IsOpen == true)\n            {\n                // There are cases when channel's property IsOpen returns true, but the connection is actually closed, e.g. https://github.com/rabbitmq/rabbitmq-dotnet-client/issues/1871\n                // This is a workaround to abort the channel in this case to avoid returning a faulty channel back to the pool.\n\n                _logger.LogWarning(\"Channel state inconsistency detected: channel is reported as open, but its underlying connection is closed. Forcing channel closure.\");\n\n                await channel.DisposeAsync();\n            }\n\n            var wrapperEx = new PublisherSentFailedException(ex.Message, ex);\n            var errors = new OperateError\n            {\n                Code = ex.HResult.ToString(),\n                Description = ex.Message\n            };\n\n            return OperateResult.Failed(wrapperEx, errors);\n        }\n        finally\n        {\n            if (channel != null) _connectionChannelPool.Return(channel);\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RabbitMQ/RabbitMQBasicConsumer.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\nusing RabbitMQ.Client;\nusing RabbitMQ.Client.Events;\n\nnamespace DotNetCore.CAP.RabbitMQ;\n\npublic class RabbitMqBasicConsumer : AsyncDefaultBasicConsumer\n{\n    private readonly SemaphoreSlim _semaphore;\n    private readonly string _groupName;\n    private readonly bool _usingTaskRun;\n    private readonly Func<TransportMessage, object?, Task> _msgCallback;\n    private readonly Action<LogMessageEventArgs> _logCallback;\n    private readonly Func<BasicDeliverEventArgs, IServiceProvider, List<KeyValuePair<string, string>>>? _customHeadersBuilder;\n    private readonly IServiceProvider _serviceProvider;\n\n    public RabbitMqBasicConsumer(IChannel channel, \n        byte concurrent,\n        string groupName,\n        Func<TransportMessage, object?, Task> msgCallback,\n        Action<LogMessageEventArgs> logCallback,\n        Func<BasicDeliverEventArgs, IServiceProvider, List<KeyValuePair<string, string>>>? customHeadersBuilder,\n        IServiceProvider serviceProvider\n        ) : base(channel)\n    {\n        _semaphore = new SemaphoreSlim(concurrent);\n        _groupName = groupName;\n        _usingTaskRun = concurrent > 0;\n        _msgCallback = msgCallback;\n        _logCallback = logCallback;\n        _customHeadersBuilder = customHeadersBuilder;\n        _serviceProvider = serviceProvider;\n    }\n\n    public override async Task HandleBasicDeliverAsync(string consumerTag, ulong deliveryTag, bool redelivered, string exchange,\n        string routingKey, IReadOnlyBasicProperties properties, ReadOnlyMemory<byte> body,\n        CancellationToken cancellationToken = default)\n    {\n        if (_usingTaskRun)\n        {\n            await _semaphore.WaitAsync(cancellationToken);\n            // Copy of the body safe to use outside the RabbitMQ thread context\n            ReadOnlyMemory<byte> safeBody = body.ToArray();\n            _ = Task.Run(() => Consume(consumerTag, deliveryTag, redelivered, exchange, routingKey, properties, safeBody), cancellationToken).ConfigureAwait(false);\n        }\n        else\n        {\n            await Consume(consumerTag, deliveryTag, redelivered, exchange, routingKey, properties, body).ConfigureAwait(false);\n        }\n    }\n\n    private Task Consume(string consumerTag, ulong deliveryTag, bool redelivered, string exchange,\n        string routingKey, IReadOnlyBasicProperties properties, ReadOnlyMemory<byte> body)\n    {\n        var headers = new Dictionary<string, string?>();\n\n        if (properties.Headers != null)\n            foreach (var header in properties.Headers)\n            {\n                if (header.Value is byte[] val)\n                    headers.Add(header.Key, Encoding.UTF8.GetString(val));\n                else\n                    headers.Add(header.Key, header.Value?.ToString());\n            }\n\n        headers[Messages.Headers.Group] = _groupName;\n\n        if (_customHeadersBuilder != null)\n        {\n            var e = new BasicDeliverEventArgs(consumerTag, deliveryTag, redelivered, exchange, routingKey,\n                properties, body);\n            var customHeaders = _customHeadersBuilder(e, _serviceProvider);\n            foreach (var customHeader in customHeaders)\n            {\n                headers[customHeader.Key] = customHeader.Value;\n            }\n        }\n\n        var message = new TransportMessage(headers, body);\n\n        return _msgCallback(message, deliveryTag);\n    }\n\n    public async Task BasicAck(ulong deliveryTag)\n    {\n        if (Channel.IsOpen)\n           await Channel.BasicAckAsync(deliveryTag, false);\n\n        _semaphore.Release();\n    }\n\n    public async Task BasicReject(ulong deliveryTag)\n    {\n        if (Channel.IsOpen)\n           await Channel.BasicRejectAsync(deliveryTag, true);\n\n        _semaphore.Release();\n    }\n\n\n    protected override async Task OnCancelAsync(string[] consumerTags, CancellationToken cancellationToken = default)\n    {\n        await base.OnCancelAsync(consumerTags, cancellationToken);\n\n        var args = new LogMessageEventArgs\n        {\n            LogType = MqLogType.ConsumerCancelled,\n            Reason = string.Join(\",\", consumerTags)\n        };\n\n        _logCallback(args);\n    }\n\n    public override async Task HandleBasicCancelOkAsync(string consumerTag, CancellationToken cancellationToken = default)\n    {\n        await base.HandleBasicCancelOkAsync(consumerTag, cancellationToken);\n\n        var args = new LogMessageEventArgs\n        {\n            LogType = MqLogType.ConsumerUnregistered,\n            Reason = consumerTag\n        };\n\n        _logCallback(args);\n    }\n\n    public override async Task HandleBasicConsumeOkAsync(string consumerTag, CancellationToken cancellationToken = default)\n    {\n        await base.HandleBasicConsumeOkAsync(consumerTag, cancellationToken);\n\n        var args = new LogMessageEventArgs\n        {\n            LogType = MqLogType.ConsumerRegistered,\n            Reason = consumerTag\n        };\n\n        _logCallback(args);\n    }\n\n    public override async Task HandleChannelShutdownAsync(object channel, ShutdownEventArgs reason)\n    {\n        await base.HandleChannelShutdownAsync(channel, reason);\n\n        var args = new LogMessageEventArgs\n        {\n            LogType = MqLogType.ConsumerShutdown,\n            Reason = reason.ReplyText\n        };\n\n        _logCallback(args);\n    }\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Options;\nusing RabbitMQ.Client;\nusing RabbitMQ.Client.Events;\n\nnamespace DotNetCore.CAP.RabbitMQ;\n\ninternal sealed class RabbitMqConsumerClient : IConsumerClient\n{\n    private readonly SemaphoreSlim _semaphore = new(1, 1);\n    private readonly IConnectionChannelPool _connectionChannelPool;\n    private readonly IServiceProvider _serviceProvider;\n    private readonly string _exchangeName;\n    private readonly string _queueName;\n    private readonly byte _groupConcurrent;\n    private readonly RabbitMQOptions _rabbitMqOptions;\n    private RabbitMqBasicConsumer? _consumer = null;\n    private IChannel? _channel;\n\n    public RabbitMqConsumerClient(string groupName, byte groupConcurrent,\n        IConnectionChannelPool connectionChannelPool,\n        IOptions<RabbitMQOptions> options,\n        IServiceProvider serviceProvider)\n    {\n        _queueName = groupName;\n        _groupConcurrent = groupConcurrent;\n        _connectionChannelPool = connectionChannelPool;\n        _serviceProvider = serviceProvider;\n        _rabbitMqOptions = options.Value;\n        _exchangeName = connectionChannelPool.Exchange;\n    }\n\n    public Func<TransportMessage, object?, Task>? OnMessageCallback { get; set; }\n\n    public Action<LogMessageEventArgs>? OnLogCallback { get; set; }\n\n    public BrokerAddress BrokerAddress => new(\"rabbitmq\", $\"{_rabbitMqOptions.HostName}:{_rabbitMqOptions.Port}\");\n\n    public async Task SubscribeAsync(IEnumerable<string> topics)\n    {\n        if (topics == null) throw new ArgumentNullException(nameof(topics));\n\n        await ConnectAsync();\n\n        foreach (var topic in topics)\n        {\n            await _channel!.QueueBindAsync(_queueName, _exchangeName, topic);\n        }\n    }\n\n    public async Task ListeningAsync(TimeSpan timeout, CancellationToken cancellationToken)\n    {\n        await ConnectAsync();\n\n        if (_rabbitMqOptions.BasicQosOptions != null)\n        {\n            await _channel!.BasicQosAsync(0, _rabbitMqOptions.BasicQosOptions.PrefetchCount, _rabbitMqOptions.BasicQosOptions.Global, cancellationToken);\n        }\n        else\n        {\n            ushort prefetch = _groupConcurrent > 0 ? _groupConcurrent : (ushort)1;\n            await _channel!.BasicQosAsync(prefetchSize: 0, prefetchCount: prefetch, global: false, cancellationToken);\n        }\n\n        _consumer = new RabbitMqBasicConsumer(_channel!, _groupConcurrent, _queueName, OnMessageCallback!, OnLogCallback!,_rabbitMqOptions.CustomHeadersBuilder, _serviceProvider);\n\n        try\n        {\n            await _channel!.BasicConsumeAsync(_queueName, false, _consumer, cancellationToken);\n        }\n        catch (TimeoutException ex)\n        {\n            await _consumer.HandleChannelShutdownAsync(null!, new ShutdownEventArgs(ShutdownInitiator.Application, 0, ex.Message + \"-->\" + nameof(_channel.BasicConsumeAsync)));\n        }\n\n        while (true)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            cancellationToken.WaitHandle.WaitOne(timeout);\n        }\n        // ReSharper disable once FunctionNeverReturns\n    }\n\n    public async Task CommitAsync(object? sender)\n    {\n        await _consumer!.BasicAck((ulong)sender!);\n    }\n\n    public async Task RejectAsync(object? sender)\n    {\n        await _consumer!.BasicReject((ulong)sender!);\n    }\n\n    public ValueTask DisposeAsync()\n    {\n        _channel?.Dispose();\n        return ValueTask.CompletedTask;\n        //The connection should not be closed here, because the connection is still in use elsewhere. \n        //_connection?.Dispose();\n    }\n\n    public async Task ConnectAsync()\n    {\n        var connection = _connectionChannelPool.GetConnection();\n\n        await _semaphore.WaitAsync();\n\n        if (_channel == null || _channel.IsClosed)\n        {\n            _channel = await connection.CreateChannelAsync();\n\n            await _channel.ExchangeDeclareAsync(_exchangeName, RabbitMQOptions.ExchangeType, true);\n\n            var arguments = new Dictionary<string, object?>\n            {\n                { \"x-message-ttl\", _rabbitMqOptions.QueueArguments.MessageTTL }\n            };\n\n            if (!string.IsNullOrEmpty(_rabbitMqOptions.QueueArguments.QueueMode))\n                arguments.Add(\"x-queue-mode\", _rabbitMqOptions.QueueArguments.QueueMode);\n\n            if (!string.IsNullOrEmpty(_rabbitMqOptions.QueueArguments.QueueType))\n                arguments.Add(\"x-queue-type\", _rabbitMqOptions.QueueArguments.QueueType);\n\n            try\n            {\n                await _channel.QueueDeclareAsync(_queueName, _rabbitMqOptions.QueueOptions.Durable, _rabbitMqOptions.QueueOptions.Exclusive, _rabbitMqOptions.QueueOptions.AutoDelete, arguments);\n            }\n            catch (TimeoutException ex)\n            {\n                var args = new LogMessageEventArgs\n                {\n                    LogType = MqLogType.ConsumerShutdown,\n                    Reason = ex.Message + \"-->\" + nameof(_channel.QueueDeclareAsync)\n                };\n\n                OnLogCallback!(args);\n            }\n        }\n\n        _semaphore.Release();\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClientFactory.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.RabbitMQ;\n\ninternal sealed class RabbitMqConsumerClientFactory : IConsumerClientFactory\n{\n    private readonly IConnectionChannelPool _connectionChannelPool;\n    private readonly IOptions<RabbitMQOptions> _rabbitMqOptions;\n    private readonly IServiceProvider _serviceProvider;\n\n    public RabbitMqConsumerClientFactory(IOptions<RabbitMQOptions> rabbitMqOptions, IConnectionChannelPool channelPool,\n        IServiceProvider serviceProvider)\n    {\n        _rabbitMqOptions = rabbitMqOptions;\n        _connectionChannelPool = channelPool;\n        _serviceProvider = serviceProvider;\n    }\n\n    public async Task<IConsumerClient> CreateAsync(string groupId, byte concurrent)\n    {\n        try\n        {\n            var client = new RabbitMqConsumerClient(groupId, concurrent, _connectionChannelPool,\n                _rabbitMqOptions, _serviceProvider);\n            \n            await client.ConnectAsync();\n            \n            return client;\n        }\n        catch (Exception e)\n        {\n            throw new BrokerConnectionException(e);\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RedisStreams/CapOptions.Redis.Extensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP;\nusing StackExchange.Redis;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.Extensions.DependencyInjection;\n\npublic static class CapRedisOptionsExtensions\n{\n    public static CapOptions UseRedis(this CapOptions options)\n    {\n        return options.UseRedis(_ => { });\n    }\n\n    /// <summary>\n    /// Use redis streams as the message transport.\n    /// </summary>\n    /// <param name=\"options\">The <see cref=\"CapOptions\" />.</param>\n    /// <param name=\"connection\">\n    /// The StackExchange.Redis <see cref=\"ConfigurationOptions\" /> comma-delimited configuration\n    /// string.\n    /// </param>\n    public static CapOptions UseRedis(this CapOptions options, string connection)\n    {\n        return options.UseRedis(opt => opt.Configuration = ConfigurationOptions.Parse(connection));\n    }\n\n    /// <summary>\n    /// Use redis streams as the message transport.\n    /// </summary>\n    /// <param name=\"options\">The <see cref=\"CapOptions\" />.</param>\n    /// <param name=\"configure\">The CAP redis client options.</param>\n    /// <exception cref=\"ArgumentNullException\"><paramref name=\"configure\" /> is <c>null</c>.</exception>\n    public static CapOptions UseRedis(this CapOptions options, Action<CapRedisOptions> configure)\n    {\n        ArgumentNullException.ThrowIfNull(configure);\n\n        options.RegisterExtension(new RedisOptionsExtension(configure));\n\n        return options;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RedisStreams/CapOptions.Redis.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing StackExchange.Redis;\nusing System;\nusing System.Threading.Tasks;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\npublic class CapRedisOptions\n{\n    /// <summary>\n    /// Gets or sets the native options of StackExchange.Redis\n    /// </summary>\n    public ConfigurationOptions? Configuration { get; set; }\n\n    internal string Endpoint => Configuration?.ToString() ?? string.Empty;\n\n    /// <summary>\n    /// Gets or sets the count of entries consumed from stream\n    /// </summary>\n    public uint StreamEntriesCount { get; set; }\n\n    /// <summary>\n    /// Gets or sets the number of connections that can be used with redis server\n    /// </summary>\n    public uint ConnectionPoolSize { get; set; }\n\n    /// <summary>\n    /// Callback function that will be invoked when an error occurred during message consumption.\n    /// </summary>\n    public Func<ConsumeErrorContext, Task>? OnConsumeError { get; set; }   \n    public record ConsumeErrorContext(Exception Exception, StreamEntry? Entry);\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RedisStreams/DotNetCore.CAP.RedisStreams.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<TargetFramework>net8.0</TargetFramework>\n\t\t<Nullable>enable</Nullable>\n\t\t<PackageTags>$(PackageTags);RedisStreams</PackageTags>\n\t\t<LangVersion>preview</LangVersion>\n\t</PropertyGroup>\n\n\t<PropertyGroup>\n\t\t<DocumentationFile>bin\\$(Configuration)\\netstandard2.1\\DotNetCore.CAP.RedisStreams.xml</DocumentationFile>\n\t\t<NoWarn>1701;1702;1705;CS1591</NoWarn>\n\t</PropertyGroup>\n\n\t<ItemGroup>\n\t\t<PackageReference Include=\"StackExchange.Redis\" Version=\"2.9.32\" />\n\t</ItemGroup>\n\n\t<ItemGroup>\n\t\t<ProjectReference Include=\"..\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n\t\t<InternalsVisibleTo Include=\"DotNetCore.CAP.RedisStreams.Test\" />\n\t</ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/DotNetCore.CAP.RedisStreams/ICapOptionsExtension.Redis.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Linq;\nusing System.Net;\nusing DotNetCore.CAP.RedisStreams;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Options;\nusing StackExchange.Redis;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\ninternal class RedisOptionsExtension(Action<CapRedisOptions> configure) : ICapOptionsExtension\n{\n    private readonly Action<CapRedisOptions> _configure = configure ?? throw new ArgumentNullException(nameof(configure));\n\n    public void AddServices(IServiceCollection services)\n    {\n        services.AddSingleton(new CapMessageQueueMakerService(\"RedisStreams\"));\n        services.AddSingleton<IRedisStreamManager, RedisStreamManager>();\n        services.AddSingleton<IConsumerClientFactory, RedisConsumerClientFactory>();\n        services.AddSingleton<ITransport, RedisTransport>();\n        services.AddSingleton<IRedisConnectionPool, RedisConnectionPool>();\n        services.TryAddEnumerable(ServiceDescriptor\n            .Singleton<IPostConfigureOptions<CapRedisOptions>, CapRedisOptionsPostConfigure>());\n        services.AddOptions<CapRedisOptions>().Configure(_configure);\n    }\n}\n\ninternal class CapRedisOptionsPostConfigure : IPostConfigureOptions<CapRedisOptions>\n{\n    public void PostConfigure(string? name, CapRedisOptions options)\n    {\n        options.Configuration ??= new ConfigurationOptions();\n\n        if (options.StreamEntriesCount == default)\n            options.StreamEntriesCount = 10;\n\n        if (options.ConnectionPoolSize == default)\n            options.ConnectionPoolSize = 10;\n\n        if (!options.Configuration.EndPoints.Any())\n        {\n            options.Configuration.EndPoints.Add(IPAddress.Loopback, 0);\n            options.Configuration.SetDefaultPorts();\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RedisStreams/IConnectionPool.Default.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Concurrent;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing StackExchange.Redis;\n\nnamespace DotNetCore.CAP.RedisStreams;\n\ninternal class RedisConnectionPool : IRedisConnectionPool, IDisposable\n{\n    private readonly ConcurrentBag<AsyncLazyRedisConnection> _connections = [];\n\n    private readonly ILoggerFactory _loggerFactory;\n    private readonly SemaphoreSlim _poolLock = new(1);\n    private readonly CapRedisOptions _redisOptions;\n    private bool _isDisposed;\n    private bool _poolAlreadyConfigured;\n\n    public RedisConnectionPool(IOptions<CapRedisOptions> options, ILoggerFactory loggerFactory)\n    {\n        _redisOptions = options.Value;\n        _loggerFactory = loggerFactory;\n        Init().GetAwaiter().GetResult();\n    }\n\n    private AsyncLazyRedisConnection? QuietConnection\n    {\n        get\n        {\n            return _poolAlreadyConfigured ? _connections.OrderBy(static c => c.CreatedConnection?.ConnectionCapacity ?? int.MaxValue)\n                .First() : null;\n        }\n    }\n\n    public void Dispose()\n    {\n        Dispose(true);\n        GC.SuppressFinalize(this);\n    }\n\n    public async Task<IConnectionMultiplexer> ConnectAsync()\n    {\n        if (QuietConnection == null)\n        {\n            _poolAlreadyConfigured =\n                _connections.Count(static c => c.IsValueCreated) == _redisOptions.ConnectionPoolSize;\n            if (QuietConnection != null) return QuietConnection.CreatedConnection!.Connection;\n        }\n\n        foreach (var lazy in _connections)\n        {\n            if (!lazy.IsValueCreated) return (await lazy).Connection;\n\n            if (lazy.CreatedConnection!.ConnectionCapacity == default) return lazy.CreatedConnection.Connection;\n        }\n\n        return (await _connections.OrderBy(static c => c.CreatedConnection!.ConnectionCapacity).First()).Connection;\n    }\n\n    private async Task Init()\n    {\n        try\n        {\n            await _poolLock.WaitAsync();\n\n            if (!_connections.IsEmpty) return;\n\n            for (var i = 0; i < _redisOptions.ConnectionPoolSize; i++)\n            {\n                var connection = new AsyncLazyRedisConnection(_redisOptions,\n                    _loggerFactory.CreateLogger<AsyncLazyRedisConnection>());\n\n                _connections.Add(connection);\n            }\n        }\n        finally\n        {\n            _poolLock.Release();\n        }\n    }\n\n    private void Dispose(bool disposing)\n    {\n        if (_isDisposed) return;\n\n        if (disposing)\n            foreach (var connection in _connections)\n            {\n                if (!connection.IsValueCreated) continue;\n\n                connection.CreatedConnection!.Dispose();\n            }\n\n        _isDisposed = true;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RedisStreams/IConnectionPool.LazyConnection.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Runtime.CompilerServices;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing StackExchange.Redis;\n\nnamespace DotNetCore.CAP.RedisStreams;\n\npublic class AsyncLazyRedisConnection(\n    CapRedisOptions redisOptions,\n    ILogger<AsyncLazyRedisConnection> logger)\n    : Lazy<Task<RedisConnection>>(() => ConnectAsync(redisOptions, logger))\n{\n    public RedisConnection? CreatedConnection\n        => IsValueCreated ? Value.GetAwaiter().GetResult() : null;\n\n    public TaskAwaiter<RedisConnection> GetAwaiter()\n    {\n        return Value.GetAwaiter();\n    }\n\n    private static async Task<RedisConnection> ConnectAsync(CapRedisOptions redisOptions,\n        ILogger<AsyncLazyRedisConnection> logger)\n    {\n        var attempt = 1;\n\n        var redisLogger = new RedisLogger(logger);\n\n        ConnectionMultiplexer? connection = null;\n\n        while (attempt <= 5)\n        {\n            connection = await ConnectionMultiplexer.ConnectAsync(redisOptions.Configuration!, redisLogger)\n                .ConfigureAwait(false);\n\n            connection.LogEvents(logger);\n\n            if (!connection.IsConnected)\n            {\n                logger.LogWarning(\"Can't establish redis connection,trying to establish connection [attempt {attempt}].\", attempt);\n\n                await Task.Delay(TimeSpan.FromSeconds(2))\n                    .ConfigureAwait(false);\n\n                ++attempt;\n            }\n            else\n            {\n                attempt = 6;\n            }\n        }\n\n        if (connection == null) throw new Exception($\"Can't establish redis connection,after [{attempt}] attempts.\");\n\n        return new RedisConnection(connection);\n    }\n}\n\npublic class RedisConnection(IConnectionMultiplexer connection) : IDisposable\n{\n    private bool _isDisposed;\n    public IConnectionMultiplexer Connection { get; } = connection ?? throw new ArgumentNullException(nameof(connection));\n    public long ConnectionCapacity => Connection.GetCounters().TotalOutstanding;\n\n    public void Dispose()\n    {\n        Dispose(true);\n        GC.SuppressFinalize(this);\n    }\n\n    private void Dispose(bool disposing)\n    {\n        if (_isDisposed) return;\n\n        if (disposing) Connection.Dispose();\n\n        _isDisposed = true;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RedisStreams/IConnectionPool.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Threading.Tasks;\nusing StackExchange.Redis;\n\nnamespace DotNetCore.CAP.RedisStreams;\n\ninternal interface IRedisConnectionPool\n{\n    Task<IConnectionMultiplexer> ConnectAsync();\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RedisStreams/IConsumerClient.Redis.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing StackExchange.Redis;\n\nnamespace DotNetCore.CAP.RedisStreams;\n\ninternal class RedisConsumerClient(\n    string _groupId,\n    byte _groupConcurrent,\n    IRedisStreamManager _redis,\n    IOptions<CapRedisOptions> _options,\n    ILogger<RedisConsumerClient> _logger) : IConsumerClient\n{\n    private readonly SemaphoreSlim _semaphore = new(_groupConcurrent);\n    private string[] _topics = default!;\n\n    public Func<TransportMessage, object?, Task>? OnMessageCallback { get; set; }\n\n    public Action<LogMessageEventArgs>? OnLogCallback { get; set; }\n\n    public BrokerAddress BrokerAddress => new(\"redis\", _options.Value.Endpoint);\n\n    public async Task SubscribeAsync(IEnumerable<string> topics)\n    {\n        ArgumentNullException.ThrowIfNull(topics);\n\n        foreach (var topic in topics)\n        {\n            await _redis.CreateStreamWithConsumerGroupAsync(topic, _groupId);\n        }\n\n        _topics = topics.ToArray();\n    }\n\n    public Task ListeningAsync(TimeSpan timeout, CancellationToken cancellationToken)\n    {\n        _ = ListeningForMessagesAsync(timeout, cancellationToken);\n\n        while (true)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            cancellationToken.WaitHandle.WaitOne(timeout);\n        }\n        // ReSharper disable once FunctionNeverReturns\n    }\n\n    public async Task CommitAsync(object? sender)\n    {\n        var (stream, group, id) = ((string stream, string group, string id))sender!;\n\n        await _redis.Ack(stream, group, id);\n\n        _semaphore.Release();\n    }\n\n    public Task RejectAsync(object? sender)\n    {\n        _semaphore.Release();\n        return Task.CompletedTask;\n    }\n\n    public ValueTask DisposeAsync()\n    {\n        return ValueTask.CompletedTask;\n    }\n\n    private async Task ListeningForMessagesAsync(TimeSpan timeout, CancellationToken cancellationToken)\n    {\n        //first time, we want to read our pending messages, in case we crashed and are recovering.\n        var pendingMsgs = _redis.PollStreamsPendingMessagesAsync(_topics, _groupId, timeout, cancellationToken);\n\n        await ConsumeMessages(pendingMsgs, StreamPosition.Beginning).ConfigureAwait(false);\n\n        //Once we consumed our history, we can start getting new messages.\n        var newMsgs = _redis.PollStreamsLatestMessagesAsync(_topics, _groupId, timeout, cancellationToken);\n\n        _ = ConsumeMessages(newMsgs, StreamPosition.NewMessages);\n    }\n\n    private async Task ConsumeMessages(IAsyncEnumerable<IEnumerable<RedisStream>> streamsSet, RedisValue position)\n    {\n        await foreach (var set in streamsSet)\n        {\n            foreach (var stream in set)\n            {\n                foreach (var entry in stream.Entries)\n                {\n                    if (entry.IsNull) return;\n\n                    if (_groupConcurrent > 0)\n                    {\n                        _semaphore.Wait();\n                        _ = Task.Run(() => ConsumeAsync(position, stream, entry)).ConfigureAwait(false);\n                    }\n                    else\n                    {\n                        await ConsumeAsync(position, stream, entry);\n                    }\n                }\n            }\n        }\n\n        async Task ConsumeAsync(RedisValue position, RedisStream stream, StreamEntry entry)\n        {\n            try\n            {\n                var message = RedisMessage.Create(entry, _groupId);\n                await OnMessageCallback!(message, (stream.Key.ToString(), _groupId, entry.Id.ToString()));\n            }\n            catch (Exception ex)\n            {\n                _logger.LogError(ex, message: \"Redis entry {entryId} on stream {streamKey} at position {position} of group {groupId} is not valid for Cap, see inner exception for more details.\", entry.Id, stream.Key, position, _groupId);\n\n                var logArgs = new LogMessageEventArgs\n                {\n                    LogType = MqLogType.RedisConsumeError,\n                    Reason = ex.ToString()\n                };\n\n                try\n                {\n                    var onError = _options.Value.OnConsumeError?.Invoke(new CapRedisOptions.ConsumeErrorContext(ex, entry));\n\n                    await (onError ?? Task.CompletedTask).ConfigureAwait(false);\n                }\n                catch (Exception onError)\n                {\n                    _logger.LogError(onError, \"Unhandled exception occurred in {action} action, Exception has been caught.\", nameof(CapRedisOptions.OnConsumeError));\n                }\n                finally\n                {\n                    OnLogCallback!(logArgs);\n                }\n            }\n            finally\n            {\n                var positionName = position == StreamPosition.Beginning\n                    ? nameof(StreamPosition.Beginning)\n                    : nameof(StreamPosition.NewMessages);\n                _logger.LogDebug(\"Redis stream entry [{entryId}] [position : {positionName}] was delivered.\", entry.Id, positionName);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RedisStreams/IConsumerClientFactory.Redis.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.RedisStreams;\n\ninternal class RedisConsumerClientFactory(IOptions<CapRedisOptions> _redisOptions, IRedisStreamManager _redis, ILogger<RedisConsumerClient> _logger) : IConsumerClientFactory\n{\n    public Task<IConsumerClient> CreateAsync(string groupName, byte groupConcurrent)\n    {\n        var client = new RedisConsumerClient(groupName, groupConcurrent, _redis, _redisOptions, _logger);\n        return Task.FromResult<IConsumerClient>(client);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RedisStreams/IRedis.Events.Logger.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.IO;\nusing System.Text;\nusing Microsoft.Extensions.Logging;\n\nnamespace DotNetCore.CAP.RedisStreams;\n\ninternal class RedisLogger : TextWriter\n{\n    private readonly ILogger logger;\n\n    public RedisLogger(ILogger logger)\n    {\n        this.logger = logger;\n    }\n\n    public override Encoding Encoding => Encoding.UTF8;\n\n\n    public override void WriteLine(string? value)\n    {\n        logger.LogInformation(value);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RedisStreams/IRedis.Events.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing Microsoft.Extensions.Logging;\nusing StackExchange.Redis;\n\nnamespace DotNetCore.CAP.RedisStreams;\n\ninternal class RedisEvents\n{\n    private readonly IConnectionMultiplexer _connection;\n    private readonly ILogger _logger;\n\n    public RedisEvents(IConnectionMultiplexer connection, ILogger logger)\n    {\n        _logger = logger;\n        _connection = connection;\n        _connection.ErrorMessage += Connection_ErrorMessage;\n        _connection.ConnectionRestored += Connection_ConnectionRestored;\n        _connection.ConnectionFailed += Connection_ConnectionFailed;\n    }\n\n    private void Connection_ConnectionFailed(object? sender, ConnectionFailedEventArgs e)\n    {\n        _logger.LogError(e.Exception, \"Connection failed!, {message}, for endpoint:{endPoint}, failure type:{failureType}, connection type:{connectionType}\", e.Exception?.Message, e.EndPoint, e.FailureType, e.ConnectionType);\n    }\n\n    private void Connection_ConnectionRestored(object? sender, ConnectionFailedEventArgs e)\n    {\n        _logger.LogWarning(\"Connection restored back!, {message}, for endpoint:{endPoint}, failure type:{failureType}, connection type:{connectionType}\", e.Exception?.Message, e.EndPoint, e.FailureType, e.ConnectionType);\n    }\n\n    private void Connection_ErrorMessage(object? sender, RedisErrorEventArgs e)\n    {\n        if (e.Message.GetRedisErrorType() == RedisErrorTypes.Unknown)\n        {\n            _logger.LogError(\"Server replied with error, {message}, for endpoint:{endPoint}\", e.Message, e.EndPoint);\n        }\n    }\n}\n\ninternal static class RedisConnectionExtensions\n{\n    public static void LogEvents(this IConnectionMultiplexer connection, ILogger logger)\n    {\n        ArgumentNullException.ThrowIfNull(connection);\n\n        ArgumentNullException.ThrowIfNull(logger);\n\n        _ = new RedisEvents(connection, logger);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RedisStreams/IRedisStream.Manager.Default.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing StackExchange.Redis;\n\nnamespace DotNetCore.CAP.RedisStreams;\n\ninternal class RedisStreamManager(\n    IRedisConnectionPool _connectionsPool,\n    IOptions<CapRedisOptions> options,\n    ILogger<RedisStreamManager> _logger) : IRedisStreamManager\n{\n    private readonly CapRedisOptions _options = options.Value;\n    private IConnectionMultiplexer? _redis;\n\n    public async Task CreateStreamWithConsumerGroupAsync(string stream, string consumerGroup)\n    {\n        await ConnectAsync()\n            .ConfigureAwait(false);\n\n        //The object returned from GetDatabase is a cheap pass - thru object, and does not need to be stored\n        var database = _redis!.GetDatabase();\n\n        await database.TryGetOrCreateStreamConsumerGroupAsync(stream, consumerGroup)\n            .ConfigureAwait(false);\n    }\n\n    public async Task PublishAsync(string stream, NameValueEntry[] message)\n    {\n        await ConnectAsync()\n            .ConfigureAwait(false);\n\n        //The object returned from GetDatabase is a cheap pass - thru object, and does not need to be stored\n        await _redis!.GetDatabase().StreamAddAsync(stream, message)\n            .ConfigureAwait(false);\n    }\n\n    public async IAsyncEnumerable<IEnumerable<RedisStream>> PollStreamsLatestMessagesAsync(string[] streams,\n        string consumerGroup, TimeSpan pollDelay, [EnumeratorCancellation] CancellationToken token)\n    {\n        var positions = streams.Select(stream => new StreamPosition(stream, StreamPosition.NewMessages));\n\n        while (true)\n        {\n            var result = await TryReadConsumerGroupAsync(consumerGroup, positions.ToArray(), token)\n                .ConfigureAwait(false);\n\n            yield return result;\n\n            token.WaitHandle.WaitOne(pollDelay);\n        }\n    }\n\n    public async IAsyncEnumerable<IEnumerable<RedisStream>> PollStreamsPendingMessagesAsync(string[] streams,\n        string consumerGroup, TimeSpan pollDelay, [EnumeratorCancellation] CancellationToken token)\n    {\n        var positions = streams.Select(stream => new StreamPosition(stream, StreamPosition.Beginning));\n\n        while (true)\n        {\n            token.ThrowIfCancellationRequested();\n\n            var result = await TryReadConsumerGroupAsync(consumerGroup, positions.ToArray(), token)\n                .ConfigureAwait(false);\n\n            yield return result;\n\n            //Once we consumed our history of pending messages, we can break the loop.\n            if (result.All(s => s.Entries.Length < _options.StreamEntriesCount)) break;\n\n            token.WaitHandle.WaitOne(pollDelay);\n        }\n    }\n\n    public async Task Ack(string stream, string consumerGroup, string messageId)\n    {\n        await ConnectAsync()\n            .ConfigureAwait(false);\n\n        await _redis!.GetDatabase().StreamAcknowledgeAsync(stream, consumerGroup, messageId)\n            .ConfigureAwait(false);\n    }\n\n    private async Task<IEnumerable<RedisStream>> TryReadConsumerGroupAsync(string consumerGroup,\n        StreamPosition[] positions, CancellationToken token)\n    {\n        try\n        {\n            token.ThrowIfCancellationRequested();\n\n            List<StreamPosition> createdPositions = [];\n\n            await ConnectAsync()\n                .ConfigureAwait(false);\n\n            var database = _redis!.GetDatabase();\n\n            await foreach (var position in database\n                               .TryGetOrCreateConsumerGroupPositionsAsync(positions, consumerGroup, _logger)\n                               .ConfigureAwait(false).WithCancellation(token))\n            {\n                createdPositions.Add(position);\n            }\n\n            if (createdPositions.Count == 0) return [];\n\n            //calculate keys HashSlots to start reading per HashSlot\n            var groupedPositions = createdPositions.GroupBy(s => _redis.GetHashSlot(s.Key))\n                .Select(group => database.StreamReadGroupAsync([.. group], consumerGroup, consumerGroup, (int)_options.StreamEntriesCount));\n\n            var readSet = await Task.WhenAll(groupedPositions)\n                .ConfigureAwait(false);\n\n            return readSet.SelectMany(set => set);\n        }\n        catch (OperationCanceledException)\n        {\n            // ignore\n        }\n        catch (Exception ex)\n        {\n            _logger.LogError(ex, \"Redis error when trying read consumer group {consumerGroup}\", consumerGroup);\n        }\n\n        return [];\n    }\n\n    private async Task ConnectAsync()\n    {\n        _redis = await _connectionsPool.ConnectAsync()\n            .ConfigureAwait(false);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RedisStreams/IRedisStream.Manager.Extensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing StackExchange.Redis;\n\nnamespace DotNetCore.CAP.RedisStreams;\n\ninternal static class RedisStreamManagerExtensions\n{\n    public static async IAsyncEnumerable<StreamPosition> TryGetOrCreateConsumerGroupPositionsAsync(\n        this IDatabase database, StreamPosition[] positions, string consumerGroup, ILogger logger)\n    {\n        foreach (var position in positions)\n        {\n            var created = false;\n            try\n            {\n                await database.TryGetOrCreateStreamConsumerGroupAsync(position.Key, consumerGroup)\n                    .ConfigureAwait(false);\n\n                created = true;\n            }\n            catch (Exception ex)\n            {\n                if (ex.GetRedisErrorType() == RedisErrorTypes.Unknown)\n                {\n                    logger?.LogError(ex, \"Redis error while creating consumer group [{consumerGroup}] of stream [{position}]\", consumerGroup, position.Key);\n                }\n            }\n\n            if (created) yield return position;\n        }\n    }\n\n    public static async Task TryGetOrCreateStreamConsumerGroupAsync(this IDatabase database, RedisKey stream,\n        RedisValue consumerGroup)\n    {\n        var streamExist = await database.KeyExistsAsync(stream)\n            .ConfigureAwait(false);\n        if (streamExist)\n        {\n            await database.TryGetOrCreateStreamGroupAsync(stream, consumerGroup)\n                .ConfigureAwait(false);\n            return;\n        }\n\n        try\n        {\n            await database.StreamCreateConsumerGroupAsync(stream, consumerGroup, StreamPosition.NewMessages)\n                .ConfigureAwait(false);\n        }\n        catch (Exception ex)\n        {\n            if (ex.GetRedisErrorType() != RedisErrorTypes.GroupAlreadyExists) throw;\n        }\n    }\n\n    private static async Task TryGetOrCreateStreamGroupAsync(this IDatabase database, RedisKey stream,\n        RedisValue consumerGroup)\n    {\n        try\n        {\n            var groupInfo = await database.StreamGroupInfoAsync(stream);\n            \n            if (groupInfo.Any(g => g.Name == consumerGroup)) return;\n\n            await database.StreamCreateConsumerGroupAsync(stream, consumerGroup, StreamPosition.NewMessages)\n                .ConfigureAwait(false);\n        }\n        catch (Exception ex)\n        {\n            if (ex.GetRedisErrorType() is var type && type == RedisErrorTypes.NoGroupInfoExists)\n            {\n                await database.TryGetOrCreateStreamConsumerGroupAsync(stream, consumerGroup)\n                    .ConfigureAwait(false);\n                return;\n            }\n\n            throw;\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RedisStreams/IRedisStream.Manager.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing StackExchange.Redis;\n\nnamespace DotNetCore.CAP.RedisStreams;\n\ninternal interface IRedisStreamManager\n{\n    Task CreateStreamWithConsumerGroupAsync(string stream, string consumerGroup);\n    Task PublishAsync(string stream, NameValueEntry[] message);\n\n    IAsyncEnumerable<IEnumerable<RedisStream>> PollStreamsLatestMessagesAsync(string[] streams, string consumerGroup,\n        TimeSpan pollDelay, CancellationToken token);\n\n    IAsyncEnumerable<IEnumerable<RedisStream>> PollStreamsPendingMessagesAsync(string[] streams, string consumerGroup,\n        TimeSpan pollDelay, CancellationToken token);\n\n    Task Ack(string stream, string consumerGroup, string messageId);\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RedisStreams/ITransport.Redis.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.RedisStreams;\n\ninternal class RedisTransport(\n    IRedisStreamManager _redis,\n    IOptions<CapRedisOptions> options,\n    ILogger<RedisTransport> _logger) : ITransport\n{\n    private readonly CapRedisOptions _options = options.Value;\n\n    public BrokerAddress BrokerAddress => new(\"redis\", _options.Endpoint);\n\n    public async Task<OperateResult> SendAsync(TransportMessage message)\n    {\n        try\n        {\n            await _redis.PublishAsync(message.GetName(), message.AsStreamEntries())\n                .ConfigureAwait(false);\n\n            _logger.LogDebug(\"Redis message [{message}] has been published.\",message.GetName());\n\n            return OperateResult.Success;\n        }\n        catch (Exception ex)\n        {\n            var wrapperEx = new PublisherSentFailedException(ex.Message, ex);\n\n            return OperateResult.Failed(wrapperEx);\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RedisStreams/RedisErrorExtensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\n\nnamespace DotNetCore.CAP.RedisStreams;\n\ninternal static class RedisErrorExtensions\n{\n    public static RedisErrorTypes GetRedisErrorType(this string redisError)\n    {\n        if (string.Equals(\"BUSYGROUP Consumer Group name already exists\", redisError, StringComparison.InvariantCultureIgnoreCase))\n        {\n            return RedisErrorTypes.GroupAlreadyExists;\n        }\n\n        if (string.Equals(\"ERR no such key\", redisError, StringComparison.InvariantCultureIgnoreCase))\n        {\n            return RedisErrorTypes.NoGroupInfoExists;\n        }\n\n        return RedisErrorTypes.Unknown;\n    }\n\n    public static RedisErrorTypes GetRedisErrorType(this Exception exception)\n    {\n        return exception.Message.GetRedisErrorType();\n    }\n}\n\ninternal enum RedisErrorTypes : byte\n{\n    Unknown = 0,\n    GroupAlreadyExists = 1,\n    NoGroupInfoExists = 2\n}"
  },
  {
    "path": "src/DotNetCore.CAP.RedisStreams/TransportMessage.Redis.Exceptions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing StackExchange.Redis;\n\nnamespace DotNetCore.CAP.RedisStreams;\n\ninternal class RedisConsumeMissingHeadersException(StreamEntry entry) : Exception(message: $\"Redis entry [{entry.Id}] is missing Cap headers.\");\n\ninternal class RedisConsumeMissingBodyException(StreamEntry entry) : Exception(message: $\"Redis entry [{entry.Id}] is missing Cap body.\");\n\ninternal class RedisConsumeInvalidHeadersException(StreamEntry entry, Exception ex)\n    : Exception(message: $\"Redis entry [{entry.Id}] has not headers that are formatted properly as Cap headers.\", ex);\n\ninternal class RedisConsumeInvalidBodyException(StreamEntry entry, Exception ex) : Exception(message: $\"Redis entry [{entry.Id}] has not body that is formatted properly as Cap body.\", ex);"
  },
  {
    "path": "src/DotNetCore.CAP.RedisStreams/TransportMessage.Redis.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text.Json;\nusing DotNetCore.CAP.Messages;\nusing StackExchange.Redis;\n\nnamespace DotNetCore.CAP.RedisStreams;\n\ninternal static class RedisMessage\n{\n    private const string Headers = \"headers\";\n    private const string Body = \"body\";\n    private readonly static JsonSerializerOptions JSON_OPTIONS = new(JsonSerializerDefaults.Web);\n\n    public static NameValueEntry[] AsStreamEntries(this TransportMessage message)\n    {\n        return\n        [\n            new NameValueEntry(Headers, ToJson(message.Headers)),\n            new NameValueEntry(Body, ToJson(message.Body.ToArray()))\n        ];\n    }\n\n    public static TransportMessage Create(StreamEntry streamEntry, string? groupId = null)\n    {\n        IDictionary<string, string?> headers;\n        byte[]? body;\n\n        var streamDict = streamEntry.Values.ToDictionary(c => c.Name, c => c.Value);\n\n        if (!streamDict.TryGetValue(Headers, out var headersRaw) || headersRaw.IsNullOrEmpty)\n        {\n            throw new RedisConsumeMissingHeadersException(streamEntry);\n        }\n\n        if (!streamDict.TryGetValue(Body, out var bodyRaw))\n        {\n            throw new RedisConsumeMissingBodyException(streamEntry);\n        }\n\n        try\n        {\n            headers = JsonSerializer.Deserialize<IDictionary<string, string?>>(json: headersRaw!, JSON_OPTIONS)!;\n        }\n        catch (Exception ex)\n        {\n            throw new RedisConsumeInvalidHeadersException(streamEntry, ex);\n        }\n\n        if (!bodyRaw.IsNullOrEmpty)\n        {\n            try\n            {\n                body = JsonSerializer.Deserialize<byte[]>(json: bodyRaw!, JSON_OPTIONS);\n            }\n            catch (Exception ex)\n            {\n                throw new RedisConsumeInvalidBodyException(streamEntry, ex);\n            }\n        }\n        else body = null;\n\n        if (!string.IsNullOrEmpty(groupId))\n        {\n            headers[Messages.Headers.Group] = groupId;\n        }\n\n        return new TransportMessage(headers, body);\n    }\n\n    private static RedisValue ToJson(object? obj)\n    {\n        if (obj == null) return RedisValue.Null;\n        return JsonSerializer.Serialize(obj, JSON_OPTIONS);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.SqlServer/CAP.EFOptions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\npublic class EFOptions\n{\n    public const string DefaultSchema = \"cap\";\n\n    /// <summary>\n    /// Gets or sets the schema to use when creating database objects.\n    /// Default is <see cref=\"DefaultSchema\" />.\n    /// </summary>\n    public string Schema { get; set; } = DefaultSchema;\n\n    /// <summary>\n    /// EF DbContext\n    /// </summary>\n    internal Type? DbContextType { get; set; }\n\n    internal bool IsSqlServer2008 { get; set; }\n\n    /// <summary>\n    /// Data version\n    /// </summary>\n    internal string Version { get; set; } = default!;\n\n    public EFOptions UseSqlServer2008()\n    {\n        IsSqlServer2008 = true;\n        return this;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.SqlServer/CAP.Options.Extensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP;\nusing Microsoft.EntityFrameworkCore;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.Extensions.DependencyInjection;\n\npublic static class CapOptionsExtensions\n{\n    public static CapOptions UseSqlServer(this CapOptions options, string connectionString)\n    {\n        return options.UseSqlServer(opt => { opt.ConnectionString = connectionString; });\n    }\n\n    public static CapOptions UseSqlServer(this CapOptions options, Action<SqlServerOptions> configure)\n    {\n        if (configure == null) throw new ArgumentNullException(nameof(configure));\n\n        configure += x => x.Version = options.Version;\n\n        options.RegisterExtension(new SqlServerCapOptionsExtension(configure));\n\n        return options;\n    }\n\n    public static CapOptions UseEntityFramework<TContext>(this CapOptions options)\n        where TContext : DbContext\n    {\n        return options.UseEntityFramework<TContext>(opt => { });\n    }\n\n    public static CapOptions UseEntityFramework<TContext>(this CapOptions options, Action<EFOptions> configure)\n        where TContext : DbContext\n    {\n        if (configure == null) throw new ArgumentNullException(nameof(configure));\n\n        options.RegisterExtension(new SqlServerCapOptionsExtension(x =>\n        {\n            configure(x);\n            x.Version = options.Version;\n            x.DbContextType = typeof(TContext);\n        }));\n\n        return options;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.SqlServer/CAP.SqlServerCapOptionsExtension.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.SqlServer;\nusing DotNetCore.CAP.SqlServer.Diagnostics;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Options;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\ninternal class SqlServerCapOptionsExtension : ICapOptionsExtension\n{\n    private readonly Action<SqlServerOptions> _configure;\n\n    public SqlServerCapOptionsExtension(Action<SqlServerOptions> configure)\n    {\n        _configure = configure;\n    }\n\n    public void AddServices(IServiceCollection services)\n    {\n        services.AddSingleton(new CapStorageMarkerService(\"SqlServer\"));\n\n        services.AddSingleton<DiagnosticProcessorObserver>();\n        services.AddSingleton<IDataStorage, SqlServerDataStorage>();\n        services.AddSingleton<IStorageInitializer, SqlServerStorageInitializer>();\n        services.TryAddEnumerable(ServiceDescriptor.Singleton<IProcessingServer, DiagnosticRegister>());\n\n        services.Configure(_configure);\n        services.AddSingleton<IConfigureOptions<SqlServerOptions>, ConfigureSqlServerOptions>();\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.SqlServer/CAP.SqlServerOptions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing DotNetCore.CAP.Internal;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\npublic class SqlServerOptions : EFOptions\n{\n    /// <summary>\n    /// Gets or sets the database's connection string that will be used to store database entities.\n    /// </summary>\n    public string ConnectionString { get; set; } = default!;\n}\n\ninternal class ConfigureSqlServerOptions : IConfigureOptions<SqlServerOptions>\n{\n    private readonly IServiceScopeFactory _serviceScopeFactory;\n\n    public ConfigureSqlServerOptions(IServiceScopeFactory serviceScopeFactory)\n    {\n        _serviceScopeFactory = serviceScopeFactory;\n    }\n\n    public void Configure(SqlServerOptions options)\n    {\n        if (options.DbContextType == null) return;\n\n        if (Helper.IsUsingType<ICapPublisher>(options.DbContextType))\n            throw new InvalidOperationException(\n                \"We detected that you are using ICapPublisher in DbContext, please change the configuration to use the storage extension directly to avoid circular references! eg:  x.UseSqlServer()\");\n\n        using var scope = _serviceScopeFactory.CreateScope();\n        var provider = scope.ServiceProvider;\n        using var dbContext = (DbContext)provider.GetRequiredService(options.DbContextType);\n        var connectionString = dbContext.Database.GetConnectionString();\n        if (string.IsNullOrEmpty(connectionString)) throw new ArgumentNullException(connectionString);\n        options.ConnectionString = connectionString;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticObserver.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Reflection;\nusing DotNetCore.CAP.Internal;\nusing Microsoft.Data.SqlClient;\n\nnamespace DotNetCore.CAP.SqlServer.Diagnostics;\n\ninternal class DiagnosticObserver : IObserver<KeyValuePair<string, object?>>\n{\n    public const string SqlAfterCommitTransactionMicrosoft = \"Microsoft.Data.SqlClient.WriteTransactionCommitAfter\";\n    public const string SqlErrorCommitTransactionMicrosoft = \"Microsoft.Data.SqlClient.WriteTransactionCommitError\";\n    public const string SqlAfterRollbackTransactionMicrosoft = \"Microsoft.Data.SqlClient.WriteTransactionRollbackAfter\";\n    public const string SqlBeforeCloseConnectionMicrosoft = \"Microsoft.Data.SqlClient.WriteConnectionCloseBefore\";\n\n    private readonly ConcurrentDictionary<Guid, SqlServerCapTransaction> _transBuffer;\n\n    public DiagnosticObserver(ConcurrentDictionary<Guid, SqlServerCapTransaction> bufferTrans)\n    {\n        _transBuffer = bufferTrans;\n    }\n\n    public void OnCompleted()\n    {\n    }\n\n    public void OnError(Exception error)\n    {\n    }\n\n    public void OnNext(KeyValuePair<string, object?> evt)\n    {\n        switch (evt.Key)\n        {\n            case SqlAfterCommitTransactionMicrosoft:\n                {\n                    if (!TryGetSqlConnection(evt, out var sqlConnection)) return;\n                    var transactionKey = sqlConnection.ClientConnectionId;\n\n                    if (_transBuffer.TryRemove(transactionKey, out var transaction))\n                    {\n                        if (GetProperty(evt.Value, \"Operation\") as string == \"Rollback\")\n                        {\n                            transaction.Dispose();\n                            return;\n                        }\n\n                        transaction.DbTransaction = new NoopTransaction();\n                        transaction.Commit();\n                        transaction.Dispose();\n                    }\n\n                    break;\n                }\n            case SqlErrorCommitTransactionMicrosoft or SqlAfterRollbackTransactionMicrosoft\n                or SqlBeforeCloseConnectionMicrosoft:\n                {\n                    if (!_transBuffer.IsEmpty)\n                    {\n                        if (!TryGetSqlConnection(evt, out var sqlConnection)) return;\n                        var transactionKey = sqlConnection.ClientConnectionId;\n\n                        if (_transBuffer.TryRemove(transactionKey, out var transaction))\n                        {\n                            transaction.Dispose();\n                        }\n                    }\n\n                    break;\n                }\n        }\n    }\n\n    private static bool TryGetSqlConnection(KeyValuePair<string, object?> evt,\n        [NotNullWhen(true)] out SqlConnection? sqlConnection)\n    {\n        sqlConnection = GetProperty(evt.Value, \"Connection\") as SqlConnection;\n        return sqlConnection != null;\n    }\n\n    private static object? GetProperty(object? @this, string propertyName)\n    {\n        return @this?.GetType().GetTypeInfo().GetDeclaredProperty(propertyName)?.GetValue(@this);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticProcessorObserver.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Concurrent;\nusing System.Diagnostics;\n\nnamespace DotNetCore.CAP.SqlServer.Diagnostics;\n\npublic class DiagnosticProcessorObserver : IObserver<DiagnosticListener>\n{\n    public const string DiagnosticListenerName = \"SqlClientDiagnosticListener\";\n\n    public DiagnosticProcessorObserver()\n    {\n        TransBuffer = new ConcurrentDictionary<Guid, SqlServerCapTransaction>();\n    }\n\n    public ConcurrentDictionary<Guid, SqlServerCapTransaction> TransBuffer { get; }\n\n    public void OnCompleted()\n    {\n    }\n\n    public void OnError(Exception error)\n    {\n    }\n\n    public void OnNext(DiagnosticListener listener)\n    {\n        if (listener.Name == DiagnosticListenerName)\n            listener.Subscribe(new DiagnosticObserver(TransBuffer));\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.SqlServer/Diagnostics/IProcessingServer.DiagnosticRegister.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Diagnostics;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\n\nnamespace DotNetCore.CAP.SqlServer.Diagnostics;\n\npublic class DiagnosticRegister : IProcessingServer\n{\n    private readonly DiagnosticProcessorObserver _diagnosticProcessorObserver;\n\n    public DiagnosticRegister(DiagnosticProcessorObserver diagnosticProcessorObserver)\n    {\n        _diagnosticProcessorObserver = diagnosticProcessorObserver;\n    }\n\n    public void Dispose()\n    {\n        GC.SuppressFinalize(this);\n    }\n\n    public ValueTask StartAsync(CancellationToken stoppingToken)\n    {\n        DiagnosticListener.AllListeners.Subscribe(_diagnosticProcessorObserver);\n\n        return ValueTask.CompletedTask;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.SqlServer/DotNetCore.CAP.SqlServer.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>\n    <Nullable>enable</Nullable>\n    <PackageTags>$(PackageTags);SQL Server</PackageTags>\n  </PropertyGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net8.0'\">\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.Relational\" Version=\"8.0.22\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net9.0'\">\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.Relational\" Version=\"9.0.11\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net10.0'\">\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.Relational\" Version=\"10.0.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Data.SqlClient\" Version=\"6.1.3\" />\n    <ProjectReference Include=\"..\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Data;\nusing System.Data.Common;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.SqlServer.Diagnostics;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Data.SqlClient;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.Extensions.DependencyInjection;\n\n// ReSharper disable once CheckNamespace\nnamespace DotNetCore.CAP;\n\npublic class SqlServerCapTransaction : CapTransactionBase\n{\n    private readonly DiagnosticProcessorObserver _diagnosticProcessor;\n\n    public SqlServerCapTransaction(\n        IDispatcher dispatcher,\n        DiagnosticProcessorObserver diagnosticProcessor) : base(dispatcher)\n    {\n        _diagnosticProcessor = diagnosticProcessor;\n    }\n\n    protected override void AddToSent(MediumMessage msg)\n    {\n        base.AddToSent(msg);\n\n        var dbTransaction = DbTransaction as IDbTransaction;\n        if (dbTransaction == null)\n        {\n            if (DbTransaction is IDbContextTransaction dbContextTransaction)\n                dbTransaction = dbContextTransaction.GetDbTransaction();\n\n            if (dbTransaction == null) throw new ArgumentNullException(nameof(DbTransaction));\n        }\n\n        var transactionKey = ((SqlConnection)dbTransaction.Connection!).ClientConnectionId;\n\n        _diagnosticProcessor.TransBuffer.TryAdd(transactionKey, this);\n    }\n\n    public override void Commit()\n    {\n        switch (DbTransaction)\n        {\n            case NoopTransaction _:\n                Flush();\n                break;\n            case IDbTransaction dbTransaction:\n                dbTransaction.Commit();\n                break;\n            case IDbContextTransaction dbContextTransaction:\n                dbContextTransaction.Commit();\n                break;\n        }\n    }\n\n    public override async Task CommitAsync(CancellationToken cancellationToken = default)\n    {\n        switch (DbTransaction)\n        {\n            case NoopTransaction _:\n                await FlushAsync().ConfigureAwait(false);\n                break;\n            case DbTransaction dbTransaction:\n                await dbTransaction.CommitAsync(cancellationToken).ConfigureAwait(false);\n                break;\n            case IDbContextTransaction dbContextTransaction:\n                await dbContextTransaction.CommitAsync(cancellationToken).ConfigureAwait(false);\n                break;\n        }\n    }\n\n    public override void Rollback()\n    {\n        switch (DbTransaction)\n        {\n            case IDbTransaction dbTransaction:\n                dbTransaction.Rollback();\n                break;\n            case IDbContextTransaction dbContextTransaction:\n                dbContextTransaction.Rollback();\n                break;\n        }\n    }\n\n    public override async Task RollbackAsync(CancellationToken cancellationToken = default)\n    {\n        switch (DbTransaction)\n        {\n            case DbTransaction dbTransaction:\n                await dbTransaction.RollbackAsync(cancellationToken).ConfigureAwait(false);\n                break;\n            case IDbContextTransaction dbContextTransaction:\n                await dbContextTransaction.RollbackAsync(cancellationToken).ConfigureAwait(false);\n                break;\n        }\n    }\n}\n\npublic static class CapTransactionExtensions\n{\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"database\">The <see cref=\"DatabaseFacade\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <returns>The <see cref=\"IDbContextTransaction\" /> of EF DbContext transaction object.</returns>\n    public static IDbContextTransaction BeginTransaction(this DatabaseFacade database,\n        ICapPublisher publisher, bool autoCommit = false)\n    {\n        return BeginTransaction(database, IsolationLevel.Unspecified, publisher, autoCommit);\n    }\n\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"database\">The <see cref=\"DatabaseFacade\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"isolationLevel\">The <see cref=\"IsolationLevel\" /> to use</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <returns>The <see cref=\"IDbContextTransaction\" /> of EF DbContext transaction object.</returns>\n    public static IDbContextTransaction BeginTransaction(this DatabaseFacade database,\n        IsolationLevel isolationLevel, ICapPublisher publisher, bool autoCommit = false)\n    {\n        var dbTransaction = database.BeginTransaction(isolationLevel);\n        publisher.Transaction = ActivatorUtilities.CreateInstance<SqlServerCapTransaction>(publisher.ServiceProvider);\n        publisher.Transaction.DbTransaction = dbTransaction;\n        publisher.Transaction.AutoCommit = autoCommit;\n        return new CapEFDbTransaction(publisher.Transaction);\n    }\n\n    /// <summary>\n    /// Start the CAP transaction async\n    /// </summary>\n    /// <param name=\"database\">The <see cref=\"DatabaseFacade\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <param name=\"cancellationToken\"></param>\n    /// <returns>The <see cref=\"IDbContextTransaction\" /> of EF DbContext transaction object.</returns>\n    public static Task<IDbContextTransaction> BeginTransactionAsync(this DatabaseFacade database,\n        ICapPublisher publisher, bool autoCommit = false, CancellationToken cancellationToken = default)\n    {\n        return BeginTransactionAsync(database, IsolationLevel.Unspecified, publisher, autoCommit, cancellationToken);\n    }\n\n    /// <summary>\n    /// Start the CAP transaction async\n    /// </summary>\n    /// <param name=\"database\">The <see cref=\"DatabaseFacade\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"isolationLevel\">The <see cref=\"IsolationLevel\" /> to use</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <param name=\"cancellationToken\"></param>\n    /// <returns>The <see cref=\"IDbContextTransaction\" /> of EF DbContext transaction object.</returns>\n    public static Task<IDbContextTransaction> BeginTransactionAsync(this DatabaseFacade database,\n        IsolationLevel isolationLevel, ICapPublisher publisher, bool autoCommit = false, CancellationToken cancellationToken = default)\n    {\n        var dbTransaction = database.BeginTransactionAsync(isolationLevel, cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult();\n        publisher.Transaction = ActivatorUtilities.CreateInstance<SqlServerCapTransaction>(publisher.ServiceProvider);\n        publisher.Transaction.DbTransaction = dbTransaction;\n        publisher.Transaction.AutoCommit = autoCommit;\n        return Task.FromResult<IDbContextTransaction>(new CapEFDbTransaction(publisher.Transaction));\n    }\n\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"dbConnection\">The <see cref=\"IDbConnection\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <returns>The <see cref=\"ICapTransaction\" /> object.</returns>\n    public static IDbTransaction BeginTransaction(this IDbConnection dbConnection,\n        ICapPublisher publisher, bool autoCommit = false)\n    {\n        return BeginTransaction(dbConnection, IsolationLevel.Unspecified, publisher, autoCommit);\n    }\n\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"dbConnection\">The <see cref=\"IDbConnection\" />.</param>\n    /// <param name=\"isolationLevel\">The <see cref=\"IsolationLevel\" /> to use</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <returns>The <see cref=\"ICapTransaction\" /> object.</returns>\n    public static IDbTransaction BeginTransaction(this IDbConnection dbConnection,\n        IsolationLevel isolationLevel, ICapPublisher publisher, bool autoCommit = false)\n    {\n        if (dbConnection.State == ConnectionState.Closed) dbConnection.Open();\n\n        var dbTransaction = dbConnection.BeginTransaction(isolationLevel);\n        publisher.Transaction = ActivatorUtilities.CreateInstance<SqlServerCapTransaction>(publisher.ServiceProvider);\n        publisher.Transaction.DbTransaction = dbTransaction;\n        publisher.Transaction.AutoCommit = autoCommit;\n        return dbTransaction;\n    }\n\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"dbConnection\">The <see cref=\"IDbConnection\" />.</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <param name=\"cancellationToken\"></param>\n    /// <returns>The <see cref=\"ICapTransaction\" /> object.</returns>\n    public static Task<IDbTransaction> BeginTransactionAsync(this IDbConnection dbConnection,\n        ICapPublisher publisher, bool autoCommit = false, CancellationToken cancellationToken = default)\n    {\n        return BeginTransactionAsync(dbConnection, IsolationLevel.Unspecified, publisher, autoCommit, cancellationToken);\n    }\n\n    /// <summary>\n    /// Start the CAP transaction\n    /// </summary>\n    /// <param name=\"dbConnection\">The <see cref=\"IDbConnection\" />.</param>\n    /// <param name=\"isolationLevel\">The <see cref=\"IsolationLevel\" /> to use</param>\n    /// <param name=\"publisher\">The <see cref=\"ICapPublisher\" />.</param>\n    /// <param name=\"autoCommit\">Whether the transaction is automatically committed when the message is published</param>\n    /// <param name=\"cancellationToken\"></param>\n    /// <returns>The <see cref=\"ICapTransaction\" /> object.</returns>\n    public static Task<IDbTransaction> BeginTransactionAsync(this IDbConnection dbConnection,\n        IsolationLevel isolationLevel, ICapPublisher publisher, bool autoCommit = false, CancellationToken cancellationToken = default)\n    {\n        if (dbConnection.State == ConnectionState.Closed) ((DbConnection)dbConnection).OpenAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult();\n\n        var dbTransaction = ((DbConnection)dbConnection).BeginTransactionAsync(isolationLevel, cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult();\n        publisher.Transaction = ActivatorUtilities.CreateInstance<SqlServerCapTransaction>(publisher.ServiceProvider);\n        publisher.Transaction.DbTransaction = dbTransaction;\n        publisher.Transaction.AutoCommit = autoCommit;\n        return Task.FromResult<IDbTransaction>(dbTransaction);\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Data;\nusing System.Data.Common;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Monitoring;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Serialization;\nusing Microsoft.Data.SqlClient;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.SqlServer;\n\npublic class SqlServerDataStorage : IDataStorage\n{\n    private readonly IOptions<CapOptions> _capOptions;\n    private readonly IStorageInitializer _initializer;\n    private readonly string _lockName;\n    private readonly IOptions<SqlServerOptions> _options;\n    private readonly string _pubName;\n    private readonly string _recName;\n    private readonly ISerializer _serializer;\n    private readonly ISnowflakeId _snowflakeId;\n\n    public SqlServerDataStorage(\n        IOptions<CapOptions> capOptions,\n        IOptions<SqlServerOptions> options,\n        IStorageInitializer initializer,\n        ISerializer serializer,\n        ISnowflakeId snowflakeId)\n    {\n        _options = options;\n        _initializer = initializer;\n        _capOptions = capOptions;\n        _serializer = serializer;\n        _snowflakeId = snowflakeId;\n        _pubName = initializer.GetPublishedTableName();\n        _recName = initializer.GetReceivedTableName();\n        _lockName = initializer.GetLockTableName();\n    }\n\n    public async Task<bool> AcquireLockAsync(string key, TimeSpan ttl, string instance,\n        CancellationToken token = default)\n    {\n        var sql =\n            $\"UPDATE {_lockName} SET [Instance]=@Instance,[LastLockTime]=@LastLockTime WHERE [Key]=@Key AND [LastLockTime] < @TTL;\";\n        var connection = new SqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        object[] sqlParams =\n        {\n            new SqlParameter(\"@Instance\", instance),\n            new SqlParameter(\"@LastLockTime\", DateTime.Now),\n            new SqlParameter(\"@Key\", key),\n            new SqlParameter(\"@TTL\", DateTime.Now.Subtract(ttl))\n        };\n        var opResult = await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n        return opResult > 0;\n    }\n\n    public async Task ReleaseLockAsync(string key, string instance, CancellationToken cancellationToken = default)\n    {\n        var sql =\n            $\"UPDATE {_lockName} SET [Instance]='',[LastLockTime]=@LastLockTime WHERE [Key]=@Key AND [Instance]=@Instance;\";\n        var connection = new SqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        object[] sqlParams =\n        {\n            new SqlParameter(\"@Instance\", instance),\n            new SqlParameter(\"@LastLockTime\", DateTime.MinValue) { SqlDbType = SqlDbType.DateTime2 },\n            new SqlParameter(\"@Key\", key)\n        };\n        await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n    }\n\n    public async Task RenewLockAsync(string key, TimeSpan ttl, string instance, CancellationToken token = default)\n    {\n        var sql =\n            $\"UPDATE {_lockName} SET [LastLockTime]=DATEADD(s,{ttl.TotalSeconds},[LastLockTime]) WHERE [Key]=@Key AND [Instance]=@Instance;\";\n        var connection = new SqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        object[] sqlParams =\n        {\n            new SqlParameter(\"@Key\", key),\n            new SqlParameter(\"@Instance\", instance)\n        };\n        await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n    }\n\n    public async Task ChangePublishStateToDelayedAsync(string[] ids)\n    {\n        var sql = $\"UPDATE {_pubName} SET [StatusName]='{StatusName.Delayed}' WHERE [Id] IN ({string.Join(',', ids)});\";\n        var connection = new SqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        await connection.ExecuteNonQueryAsync(sql).ConfigureAwait(false);\n    }\n\n    public async Task ChangePublishStateAsync(MediumMessage message, StatusName state, object? transaction = null)\n    {\n        await ChangeMessageStateAsync(_pubName, message, state, transaction).ConfigureAwait(false);\n    }\n\n    public async Task ChangeReceiveStateAsync(MediumMessage message, StatusName state)\n    {\n        await ChangeMessageStateAsync(_recName, message, state).ConfigureAwait(false);\n    }\n\n    public async Task<MediumMessage> StoreMessageAsync(string name, Message content, object? transaction = null)\n    {\n        var sql =\n            $\"INSERT INTO {_pubName} ([Id],[Version],[Name],[Content],[Retries],[Added],[ExpiresAt],[StatusName])\" +\n            $\"VALUES(@Id,'{_options.Value.Version}',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);\";\n\n        var message = new MediumMessage\n        {\n            DbId = content.GetId(),\n            Origin = content,\n            Content = _serializer.Serialize(content),\n            Added = DateTime.Now,\n            ExpiresAt = null,\n            Retries = 0\n        };\n\n        object[] sqlParams =\n        {\n            new SqlParameter(\"@Id\", message.DbId),\n            new SqlParameter(\"@Name\", name),\n            new SqlParameter(\"@Content\", message.Content),\n            new SqlParameter(\"@Retries\", message.Retries),\n            new SqlParameter(\"@Added\", message.Added),\n            new SqlParameter(\"@ExpiresAt\", message.ExpiresAt.HasValue ? message.ExpiresAt.Value : DBNull.Value),\n            new SqlParameter(\"@StatusName\", nameof(StatusName.Scheduled))\n        };\n\n        if (transaction == null)\n        {\n            var connection = new SqlConnection(_options.Value.ConnectionString);\n            await using var _ = connection.ConfigureAwait(false);\n            await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n        }\n        else\n        {\n            var dbTrans = transaction as DbTransaction;\n            if (dbTrans == null && transaction is IDbContextTransaction dbContextTrans)\n                dbTrans = dbContextTrans.GetDbTransaction();\n\n            var conn = dbTrans?.Connection;\n            await conn!.ExecuteNonQueryAsync(sql, dbTrans, sqlParams).ConfigureAwait(false);\n        }\n\n        return message;\n    }\n\n    public async Task StoreReceivedExceptionMessageAsync(string name, string group, string content)\n    {\n        object[] sqlParams =\n        {\n            new SqlParameter(\"@Id\", _snowflakeId.NextId().ToString()),\n            new SqlParameter(\"@Name\", name),\n            new SqlParameter(\"@Group\", group),\n            new SqlParameter(\"@Content\", content),\n            new SqlParameter(\"@Retries\", _capOptions.Value.FailedRetryCount),\n            new SqlParameter(\"@Added\", DateTime.Now),\n            new SqlParameter(\"@ExpiresAt\", DateTime.Now.AddSeconds(_capOptions.Value.FailedMessageExpiredAfter)),\n            new SqlParameter(\"@StatusName\", nameof(StatusName.Failed))\n        };\n\n        await StoreReceivedMessage(sqlParams).ConfigureAwait(false);\n    }\n\n    public async Task<MediumMessage> StoreReceivedMessageAsync(string name, string group, Message message)\n    {\n        var mdMessage = new MediumMessage\n        {\n            DbId = _snowflakeId.NextId().ToString(),\n            Origin = message,\n            Added = DateTime.Now,\n            ExpiresAt = null,\n            Retries = 0\n        };\n\n        object[] sqlParams =\n        {\n            new SqlParameter(\"@Id\", mdMessage.DbId),\n            new SqlParameter(\"@Name\", name),\n            new SqlParameter(\"@Group\", group),\n            new SqlParameter(\"@Content\", _serializer.Serialize(mdMessage.Origin)),\n            new SqlParameter(\"@Retries\", mdMessage.Retries),\n            new SqlParameter(\"@Added\", mdMessage.Added),\n            new SqlParameter(\"@ExpiresAt\", mdMessage.ExpiresAt.HasValue ? mdMessage.ExpiresAt.Value : DBNull.Value),\n            new SqlParameter(\"@StatusName\", nameof(StatusName.Scheduled))\n        };\n\n        await StoreReceivedMessage(sqlParams).ConfigureAwait(false);\n\n        return mdMessage;\n    }\n\n    public async Task<int> DeleteExpiresAsync(string table, DateTime timeout, int batchCount = 1000,\n        CancellationToken token = default)\n    {\n        var connection = new SqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n\n        return await connection.ExecuteNonQueryAsync(\n            $@\"DELETE FROM {table}\n               WHERE Id IN (\n                   SELECT TOP (@batchCount) Id\n                   FROM {table} WITH (READPAST)\n                   WHERE ExpiresAt < @timeout\n                   AND StatusName IN('{StatusName.Succeeded}','{StatusName.Failed}')\n               );\",\n            null,\n            new SqlParameter(\"@timeout\", timeout),\n            new SqlParameter(\"@batchCount\", batchCount)).ConfigureAwait(false);\n    }\n\n    public Task<IEnumerable<MediumMessage>> GetPublishedMessagesOfNeedRetry(TimeSpan lookbackSeconds)\n    {\n        return GetMessagesOfNeedRetryAsync(_pubName, lookbackSeconds);\n    }\n\n    public Task<IEnumerable<MediumMessage>> GetReceivedMessagesOfNeedRetry(TimeSpan lookbackSeconds)\n    {\n        return GetMessagesOfNeedRetryAsync(_recName, lookbackSeconds);\n    }\n\n    public async Task<int> DeleteReceivedMessageAsync(long id)\n    {\n        var sql = $\"DELETE FROM {_recName} WHERE Id={id}\";\n\n        var connection = new SqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        var affectedRowCount = await connection.ExecuteNonQueryAsync(sql).ConfigureAwait(false);\n        return affectedRowCount;\n    }\n\n    public async Task<int> DeletePublishedMessageAsync(long id)\n    {\n        var sql = $\"DELETE FROM {_pubName} WHERE Id={id}\";\n\n        var connection = new SqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        var affectedRowCount = await connection.ExecuteNonQueryAsync(sql).ConfigureAwait(false);\n        return affectedRowCount;\n    }\n\n    public async Task ScheduleMessagesOfDelayedAsync(Func<object, IEnumerable<MediumMessage>, Task> scheduleTask,\n        CancellationToken token = default)\n    {\n        var sql = $@\"\n            SELECT TOP (@BatchSize) Id, Content, Retries, Added, ExpiresAt FROM {_pubName} WITH (UPDLOCK, READPAST)\n                WHERE Version = @Version AND StatusName = '{StatusName.Delayed}' AND ExpiresAt < @TwoMinutesLater\n            UNION ALL\n            SELECT TOP (@BatchSize) Id, Content, Retries, Added, ExpiresAt FROM {_pubName} WITH (UPDLOCK, READPAST)\n                WHERE Version = @Version AND StatusName = '{StatusName.Queued}' AND ExpiresAt < @OneMinutesAgo;\";\n\n        object[] sqlParams =\n        {\n            new SqlParameter(\"@Version\", _capOptions.Value.Version),\n            new SqlParameter(\"@TwoMinutesLater\", DateTime.Now.AddMinutes(2)),\n            new SqlParameter(\"@OneMinutesAgo\", DateTime.Now.AddMinutes(-1)),\n            new SqlParameter(\"@BatchSize\", _capOptions.Value.SchedulerBatchSize)\n        };\n\n        await using var connection = new SqlConnection(_options.Value.ConnectionString);\n        await connection.OpenAsync(token);\n        await using var transaction = await connection.BeginTransactionAsync(token);\n        var messageList = await connection.ExecuteReaderAsync(sql, async reader =>\n        {\n            var messages = new List<MediumMessage>();\n            while (await reader.ReadAsync(token).ConfigureAwait(false))\n            {\n                messages.Add(new MediumMessage\n                {\n                    DbId = reader.GetInt64(0).ToString(),\n                    Origin = _serializer.Deserialize(reader.GetString(1))!,\n                    Retries = reader.GetInt32(2),\n                    Added = reader.GetDateTime(3),\n                    ExpiresAt = reader.GetDateTime(4)\n                });\n            }\n\n            return messages;\n        }, transaction, sqlParams).ConfigureAwait(false);\n\n        await scheduleTask(transaction, messageList);\n\n        await transaction.CommitAsync(token);\n    }\n\n    public IMonitoringApi GetMonitoringApi()\n    {\n        return new SqlServerMonitoringApi(_options, _initializer, _serializer);\n    }\n\n    private async Task ChangeMessageStateAsync(string tableName, MediumMessage message, StatusName state,\n        object? transaction = null)\n    {\n        var sql =\n            $\"UPDATE {tableName} SET Content=@Content, Retries=@Retries,ExpiresAt=@ExpiresAt,StatusName=@StatusName WHERE Id=@Id\";\n\n        object[] sqlParams =\n        {\n            new SqlParameter(\"@Id\", message.DbId),\n            new SqlParameter(\"@Content\", _serializer.Serialize(message.Origin)),\n            new SqlParameter(\"@Retries\", message.Retries),\n            new SqlParameter(\"@ExpiresAt\", message.ExpiresAt),\n            new SqlParameter(\"@StatusName\", state.ToString(\"G\"))\n        };\n\n        if (transaction is DbTransaction dbTransaction)\n        {\n            var connection = (SqlConnection)dbTransaction.Connection!;\n            await connection.ExecuteNonQueryAsync(sql, dbTransaction, sqlParams).ConfigureAwait(false);\n        }\n        else\n        {\n            var connection = new SqlConnection(_options.Value.ConnectionString);\n            await using var _ = connection.ConfigureAwait(false);\n            await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n        }\n    }\n\n    private async Task StoreReceivedMessage(object[] sqlParams)\n    {\n        var sql =\n            $\"INSERT INTO {_recName}([Id],[Version],[Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName])\" +\n            $\"VALUES(@Id,'{_capOptions.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);\";\n\n        var connection = new SqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n    }\n\n    private async Task<IEnumerable<MediumMessage>> GetMessagesOfNeedRetryAsync(string tableName, TimeSpan lookbackSeconds)\n    {\n        var fourMinAgo = DateTime.Now.Subtract(lookbackSeconds);\n\n        var sql =\n            $\"SELECT TOP (200) Id, Content, Retries, Added FROM {tableName} WITH (READPAST) \" +\n            $\"WHERE Retries < @Retries AND Version = @Version AND Added < @Added AND StatusName IN ('{StatusName.Failed}', '{StatusName.Scheduled}');\";\n\n        object[] sqlParams =\n        {\n            new SqlParameter(\"@Retries\", _capOptions.Value.FailedRetryCount),\n            new SqlParameter(\"@Version\", _capOptions.Value.Version),\n            new SqlParameter(\"@Added\", fourMinAgo)\n        };\n\n        var connection = new SqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        var result = await connection.ExecuteReaderAsync(sql, async reader =>\n        {\n            var messages = new List<MediumMessage>();\n            while (await reader.ReadAsync().ConfigureAwait(false))\n            {\n                messages.Add(new MediumMessage\n                {\n                    DbId = reader.GetInt64(0).ToString(),\n                    Origin = _serializer.Deserialize(reader.GetString(1))!,\n                    Retries = reader.GetInt32(2),\n                    Added = reader.GetDateTime(3)\n                });\n            }\n\n            return messages;\n        }, sqlParams: sqlParams).ConfigureAwait(false);\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "src/DotNetCore.CAP.SqlServer/IDbConnection.Extensions.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.ComponentModel;\nusing System.Data;\nusing System.Data.Common;\nusing System.Threading.Tasks;\n\nnamespace DotNetCore.CAP.SqlServer;\n\ninternal static class DbConnectionExtensions\n{\n    public static async Task<int> ExecuteNonQueryAsync(this DbConnection connection, string sql,\n        DbTransaction? transaction = null, params object[] sqlParams)\n    {\n        if (connection.State == ConnectionState.Closed) await connection.OpenAsync().ConfigureAwait(false);\n\n        var command = connection.CreateCommand();\n        await using var _ = command.ConfigureAwait(false);\n        command.CommandType = CommandType.Text;\n        command.CommandText = sql;\n        foreach (var param in sqlParams)\n        {\n            command.Parameters.Add(param);\n        }\n\n        if (transaction != null) command.Transaction = transaction;\n\n        return await command.ExecuteNonQueryAsync().ConfigureAwait(false);\n    }\n\n    public static async Task<T> ExecuteReaderAsync<T>(this DbConnection connection, string sql,\n        Func<DbDataReader, Task<T>>? readerFunc, DbTransaction? transaction = null, params object[] sqlParams)\n    {\n        if (connection.State == ConnectionState.Closed) await connection.OpenAsync().ConfigureAwait(false);\n\n        var command = connection.CreateCommand();\n        await using var _ = command.ConfigureAwait(false);\n        command.CommandType = CommandType.Text;\n        command.CommandText = sql;\n        foreach (var param in sqlParams)\n        {\n            command.Parameters.Add(param);\n        }\n\n        if (transaction != null) command.Transaction = transaction;\n\n        await using var reader = await command.ExecuteReaderAsync().ConfigureAwait(false);\n\n        T result = default!;\n        if (readerFunc != null) result = await readerFunc(reader).ConfigureAwait(false);\n\n        return result;\n    }\n\n    public static async Task<T> ExecuteScalarAsync<T>(this DbConnection connection, string sql,\n        params object[] sqlParams)\n    {\n        if (connection.State == ConnectionState.Closed) await connection.OpenAsync().ConfigureAwait(false);\n\n        var command = connection.CreateCommand();\n        await using var _ = command.ConfigureAwait(false);\n        command.CommandType = CommandType.Text;\n        command.CommandText = sql;\n        foreach (var param in sqlParams)\n        {\n            command.Parameters.Add(param);\n        }\n\n        var objValue = await command.ExecuteScalarAsync().ConfigureAwait(false);\n\n        T result = default!;\n        if (objValue != null)\n        {\n            var returnType = typeof(T);\n            var converter = TypeDescriptor.GetConverter(returnType);\n            if (converter.CanConvertFrom(objValue.GetType()))\n                result = (T)converter.ConvertFrom(objValue)!;\n            else\n                result = (T)Convert.ChangeType(objValue, returnType);\n        }\n\n        return result;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.SqlServer/IDbContextTransaction.CAP.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Data.Common;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.EntityFrameworkCore.Storage;\n\ninternal class CapEFDbTransaction : IDbContextTransaction, IInfrastructure<DbTransaction>\n{\n    private readonly ICapTransaction _transaction;\n\n    public CapEFDbTransaction(ICapTransaction transaction)\n    {\n        _transaction = transaction;\n        var dbContextTransaction = (IDbContextTransaction)_transaction.DbTransaction!;\n        TransactionId = dbContextTransaction.TransactionId;\n    }\n\n    public Guid TransactionId { get; }\n\n    public void Dispose()\n    {\n        _transaction.Dispose();\n    }\n\n    public void Commit()\n    {\n        _transaction.Commit();\n    }\n\n    public void Rollback()\n    {\n        _transaction.Rollback();\n    }\n\n    public async Task CommitAsync(CancellationToken cancellationToken = default)\n    {\n        await _transaction.CommitAsync(cancellationToken).ConfigureAwait(false);\n    }\n\n    public async Task RollbackAsync(CancellationToken cancellationToken = default)\n    {\n        await _transaction.RollbackAsync(cancellationToken).ConfigureAwait(false);\n    }\n\n    public ValueTask DisposeAsync()\n    {\n        return new ValueTask(Task.Run(() => _transaction.Dispose()));\n    }\n\n    public DbTransaction Instance\n    {\n        get\n        {\n            var dbContextTransaction = (IDbContextTransaction)_transaction.DbTransaction!;\n            return dbContextTransaction.GetDbTransaction();\n        }\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.SqlServer/IMonitoringApi.SqlServer.cs",
    "content": "﻿// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Monitoring;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Serialization;\nusing Microsoft.Data.SqlClient;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.SqlServer;\n\ninternal class SqlServerMonitoringApi : IMonitoringApi\n{\n    private readonly SqlServerOptions _options;\n    private readonly string _pubName;\n    private readonly string _recName;\n    private readonly ISerializer _serializer;\n\n    public SqlServerMonitoringApi(IOptions<SqlServerOptions> options, IStorageInitializer initializer,\n        ISerializer serializer)\n    {\n        _options = options.Value ?? throw new ArgumentNullException(nameof(options));\n        _pubName = initializer.GetPublishedTableName();\n        _recName = initializer.GetReceivedTableName();\n        _serializer = serializer;\n    }\n\n    public async Task<StatisticsDto> GetStatisticsAsync()\n    {\n        var sql = $@\"\nSELECT\n(\n    SELECT COUNT(Id) FROM {_pubName} WHERE StatusName = N'Succeeded'\n) AS PublishedSucceeded,\n(\n    SELECT COUNT(Id) FROM {_recName} WHERE StatusName = N'Succeeded'\n) AS ReceivedSucceeded,\n(\n    SELECT COUNT(Id) FROM {_pubName} WHERE StatusName = N'Failed'\n) AS PublishedFailed,\n(\n    SELECT COUNT(Id) FROM {_recName} WHERE StatusName = N'Failed'\n) AS ReceivedFailed,\n(\n    SELECT COUNT(Id) FROM {_pubName} WHERE StatusName = N'Delayed'\n) AS PublishedDelayed;\";\n\n        var connection = new SqlConnection(_options.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        var statistics = await connection.ExecuteReaderAsync(sql, reader =>\n        {\n            var statisticsDto = new StatisticsDto();\n\n            while (reader.Read())\n            {\n                statisticsDto.PublishedSucceeded = reader.GetInt32(0);\n                statisticsDto.ReceivedSucceeded = reader.GetInt32(1);\n                statisticsDto.PublishedFailed = reader.GetInt32(2);\n                statisticsDto.ReceivedFailed = reader.GetInt32(3);\n                statisticsDto.PublishedDelayed = reader.GetInt32(4);\n            }\n\n            return Task.FromResult(statisticsDto);\n        }).ConfigureAwait(false);\n\n        return statistics;\n    }\n\n    public async Task<IDictionary<DateTime, int>> HourlyFailedJobs(MessageType type)\n    {\n        var tableName = type == MessageType.Publish ? _pubName : _recName;\n        return await GetHourlyTimelineStats(tableName, nameof(StatusName.Failed)).ConfigureAwait(false);\n    }\n\n    public async Task<IDictionary<DateTime, int>> HourlySucceededJobs(MessageType type)\n    {\n        var tableName = type == MessageType.Publish ? _pubName : _recName;\n        return await GetHourlyTimelineStats(tableName, nameof(StatusName.Succeeded)).ConfigureAwait(false);\n    }\n\n    public async Task<PagedQueryResult<MessageDto>> GetMessagesAsync(MessageQueryDto queryDto)\n    {\n        var tableName = queryDto.MessageType == MessageType.Publish ? _pubName : _recName;\n        var where = string.Empty;\n        if (!string.IsNullOrEmpty(queryDto.StatusName)) where += \" AND [StatusName]=@StatusName\";\n\n        if (!string.IsNullOrEmpty(queryDto.Name)) where += \" AND [Name]=@Name\";\n\n        if (!string.IsNullOrEmpty(queryDto.Group)) where += \" AND [Group]=@Group\";\n\n        if (!string.IsNullOrEmpty(queryDto.Content)) where += \" AND [Content] LIKE @Content\";\n\n        var sqlQuery2008 =\n            $\"SELECT * FROM (SELECT p.*, ROW_NUMBER() OVER(ORDER BY p.Added DESC) AS RowNum FROM {tableName} AS p WHERE 1=1 {where}) as tbl WHERE tbl.RowNum BETWEEN @Offset AND @Offset + @Limit\";\n\n        var sqlQuery =\n            $\"SELECT * FROM {tableName} WHERE 1=1 {where} ORDER BY Added DESC OFFSET @Offset ROWS FETCH NEXT @Limit ROWS ONLY\";\n\n        object[] sqlParams =\n        {\n            new SqlParameter(\"@StatusName\", queryDto.StatusName ?? string.Empty),\n            new SqlParameter(\"@Group\", queryDto.Group ?? string.Empty),\n            new SqlParameter(\"@Name\", queryDto.Name ?? string.Empty),\n            new SqlParameter(\"@Content\", $\"%{queryDto.Content}%\"),\n            new SqlParameter(\"@Offset\", queryDto.CurrentPage * queryDto.PageSize),\n            new SqlParameter(\"@Limit\", queryDto.PageSize)\n        };\n\n        var connection = new SqlConnection(_options.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n\n        var count = await connection.ExecuteScalarAsync<int>($\"SELECT COUNT(1) FROM {tableName} WHERE 1=1 {where}\",\n            new SqlParameter(\"@StatusName\", queryDto.StatusName ?? string.Empty),\n            new SqlParameter(\"@Group\", queryDto.Group ?? string.Empty),\n            new SqlParameter(\"@Name\", queryDto.Name ?? string.Empty),\n            new SqlParameter(\"@Content\", $\"%{queryDto.Content}%\")).ConfigureAwait(false);\n\n        var items = await connection.ExecuteReaderAsync(_options.IsSqlServer2008 ? sqlQuery2008 : sqlQuery,\n            async reader =>\n            {\n                var messages = new List<MessageDto>();\n\n                while (await reader.ReadAsync().ConfigureAwait(false))\n                {\n                    var index = 0;\n                    messages.Add(new MessageDto\n                    {\n                        Id = reader.GetInt64(index++).ToString(),\n                        Version = reader.GetString(index++),\n                        Name = reader.GetString(index++),\n                        Group = queryDto.MessageType == MessageType.Subscribe ? reader.GetString(index++) : default,\n                        Content = reader.GetString(index++),\n                        Retries = reader.GetInt32(index++),\n                        Added = reader.GetDateTime(index++),\n                        ExpiresAt = reader.IsDBNull(index++) ? null : reader.GetDateTime(index - 1),\n                        StatusName = reader.GetString(index)\n                    });\n                }\n\n                return messages;\n            }, sqlParams: sqlParams).ConfigureAwait(false);\n\n        return new PagedQueryResult<MessageDto>\n        { Items = items, PageIndex = queryDto.CurrentPage, PageSize = queryDto.PageSize, Totals = count };\n    }\n\n    public ValueTask<int> PublishedFailedCount()\n    {\n        return GetNumberOfMessage(_pubName, nameof(StatusName.Failed));\n    }\n\n    public ValueTask<int> PublishedSucceededCount()\n    {\n        return GetNumberOfMessage(_pubName, nameof(StatusName.Succeeded));\n    }\n\n    public ValueTask<int> ReceivedFailedCount()\n    {\n        return GetNumberOfMessage(_recName, nameof(StatusName.Failed));\n    }\n\n    public ValueTask<int> ReceivedSucceededCount()\n    {\n        return GetNumberOfMessage(_recName, nameof(StatusName.Succeeded));\n    }\n\n    public async Task<MediumMessage?> GetPublishedMessageAsync(long id)\n    {\n        return await GetMessageAsync(_pubName, id).ConfigureAwait(false);\n    }\n\n    public async Task<MediumMessage?> GetReceivedMessageAsync(long id)\n    {\n        return await GetMessageAsync(_recName, id).ConfigureAwait(false);\n    }\n\n    private async ValueTask<int> GetNumberOfMessage(string tableName, string statusName)\n    {\n        var sqlQuery =\n            $\"SELECT COUNT(Id) FROM {tableName} WITH (NOLOCK) WHERE StatusName = @StatusName\";\n        var connection = new SqlConnection(_options.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        return await connection.ExecuteScalarAsync<int>(sqlQuery, new SqlParameter(\"@StatusName\", statusName))\n            .ConfigureAwait(false);\n    }\n\n    private Task<Dictionary<DateTime, int>> GetHourlyTimelineStats(string tableName, string statusName)\n    {\n        var endDate = DateTime.Now;\n        var dates = new List<DateTime>();\n        for (var i = 0; i < 24; i++)\n        {\n            dates.Add(endDate);\n            endDate = endDate.AddHours(-1);\n        }\n\n        var keyMaps = dates.ToDictionary(x => x.ToString(\"yyyy-MM-dd-HH\"), x => x);\n\n        return GetTimelineStats(tableName, statusName, keyMaps);\n    }\n\n    private async Task<Dictionary<DateTime, int>> GetTimelineStats(string tableName, string statusName, IDictionary<string, DateTime> keyMaps)\n    {\n        var sqlQuery2008 = $@\"\nWITH Aggr AS (\nSELECT REPLACE(CONVERT(varchar, Added, 111), '/','-') + '-' + CONVERT(varchar, DATEPART(hh, Added)) AS [Key],\n    COUNT(Id) [Count]\nFROM  {tableName}\nWHERE StatusName = @StatusName\nGROUP BY REPLACE(CONVERT(varchar, Added, 111), '/','-') + '-' + CONVERT(varchar, DATEPART(hh, Added))\n)\nSELECT [Key], [Count] FROM Aggr WITH (NOLOCK) WHERE [Key] >= @MinKey AND [Key] <= @MaxKey;\";\n\n        //SQL Server 2012+ \n        var sqlQuery = $@\"\nWITH Aggr AS (\nSELECT FORMAT(Added,'yyyy-MM-dd-HH') AS [Key],\n    COUNT(Id) [Count]\nFROM  {tableName}\nWHERE StatusName = @StatusName\nGROUP BY FORMAT(Added,'yyyy-MM-dd-HH')\n)\nSELECT [Key], [Count] FROM Aggr WITH (NOLOCK) WHERE [Key] >= @MinKey AND [Key] <= @MaxKey;\";\n\n        object[] sqlParams =\n        {\n            new SqlParameter(\"@StatusName\", statusName),\n            new SqlParameter(\"@MinKey\", keyMaps.Keys.Min()),\n            new SqlParameter(\"@MaxKey\", keyMaps.Keys.Max())\n        };\n\n        Dictionary<string, int> valuesMap;\n        var connection = new SqlConnection(_options.ConnectionString);\n        await using (connection.ConfigureAwait(false))\n        {\n            valuesMap = await connection.ExecuteReaderAsync(_options.IsSqlServer2008 ? sqlQuery2008 : sqlQuery,\n                async reader =>\n                {\n                    var dictionary = new Dictionary<string, int>();\n\n                    while (await reader.ReadAsync().ConfigureAwait(false))\n                    {\n                        dictionary.Add(reader.GetString(0), reader.GetInt32(1));\n                    }\n\n                    return dictionary;\n                }, sqlParams: sqlParams).ConfigureAwait(false);\n        }\n\n        foreach (var key in keyMaps.Keys)\n        {\n            valuesMap.TryAdd(key, 0);\n        }\n\n        var result = new Dictionary<DateTime, int>();\n        for (var i = 0; i < keyMaps.Count; i++)\n        {\n            var value = valuesMap[keyMaps.ElementAt(i).Key];\n            result.Add(keyMaps.ElementAt(i).Value, value);\n        }\n\n        return result;\n    }\n\n    private async Task<MediumMessage?> GetMessageAsync(string tableName, long id)\n    {\n        var sql = $\"SELECT TOP 1 Id AS DbId, Content, Added, ExpiresAt, Retries FROM {tableName} WITH (READPAST) WHERE Id={id}\";\n\n        var connection = new SqlConnection(_options.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        var mediumMessage = await connection.ExecuteReaderAsync(sql, async reader =>\n        {\n            MediumMessage? message = null;\n\n            while (await reader.ReadAsync().ConfigureAwait(false))\n            {\n                message = new MediumMessage\n                {\n                    DbId = reader.GetInt64(0).ToString(),\n                    Origin = _serializer.Deserialize(reader.GetString(1))!,\n                    Content = reader.GetString(1),\n                    Added = reader.GetDateTime(2),\n                    ExpiresAt = reader.GetDateTime(3),\n                    Retries = reader.GetInt32(4)\n                };\n            }\n\n            return message;\n        }).ConfigureAwait(false);\n\n        return mediumMessage;\n    }\n}"
  },
  {
    "path": "src/DotNetCore.CAP.SqlServer/IStorageInitializer.SqlServer.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System;\nusing System.Data;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Persistence;\nusing Microsoft.Data.SqlClient;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.SqlServer;\n\npublic class SqlServerStorageInitializer : IStorageInitializer\n{\n    private readonly IOptions<CapOptions> _capOptions;\n    private readonly ILogger _logger;\n    private readonly IOptions<SqlServerOptions> _options;\n\n    public SqlServerStorageInitializer(\n        ILogger<SqlServerStorageInitializer> logger,\n        IOptions<SqlServerOptions> options, IOptions<CapOptions> capOptions)\n    {\n        _capOptions = capOptions;\n        _options = options;\n        _logger = logger;\n    }\n\n    public virtual string GetPublishedTableName()\n    {\n        return $\"{_options.Value.Schema}.Published\";\n    }\n\n    public virtual string GetReceivedTableName()\n    {\n        return $\"{_options.Value.Schema}.Received\";\n    }\n\n    public virtual string GetLockTableName()\n    {\n        return $\"{_options.Value.Schema}.Lock\";\n    }\n\n    public async Task InitializeAsync(CancellationToken cancellationToken)\n    {\n        if (cancellationToken.IsCancellationRequested) return;\n\n        var sql = CreateDbTablesScript(_options.Value.Schema);\n        var connection = new SqlConnection(_options.Value.ConnectionString);\n        await using var _ = connection.ConfigureAwait(false);\n        object[] sqlParams =\n        {\n            new SqlParameter(\"@PubKey\", $\"publish_retry_{_capOptions.Value.Version}\"),\n            new SqlParameter(\"@RecKey\", $\"received_retry_{_capOptions.Value.Version}\"),\n            new SqlParameter(\"@LastLockTime\", DateTime.MinValue) { SqlDbType = SqlDbType.DateTime2 }\n        };\n        await connection.ExecuteNonQueryAsync(sql, sqlParams: sqlParams).ConfigureAwait(false);\n\n        _logger.LogDebug(\"Ensuring all create database tables script are applied.\");\n    }\n\n    protected virtual string CreateDbTablesScript(string schema)\n    {\n        var batchSql =\n            $@\"\nIF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = '{schema}')\nBEGIN\n\tEXEC('CREATE SCHEMA [{schema}]')\nEND;\n\nIF OBJECT_ID(N'{GetReceivedTableName()}',N'U') IS NULL\nBEGIN\nCREATE TABLE {GetReceivedTableName()}(\n\t[Id] [bigint] NOT NULL,\n    [Version] [nvarchar](20) NOT NULL,\n\t[Name] [nvarchar](200) NOT NULL,\n\t[Group] [nvarchar](200) NULL,\n\t[Content] [nvarchar](max) NULL,\n\t[Retries] [int] NOT NULL,\n\t[Added] [datetime2](7) NOT NULL,\n    [ExpiresAt] [datetime2](7) NULL,\n\t[StatusName] [nvarchar](50) NOT NULL,\n CONSTRAINT [PK_{GetReceivedTableName()}] PRIMARY KEY CLUSTERED\n(\n\t[Id] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\n\nCREATE NONCLUSTERED INDEX [IX_{GetReceivedTableName()}_Version_ExpiresAt_StatusName] ON {GetReceivedTableName()} ([Version] ASC,[ExpiresAt] ASC,[StatusName] ASC) \nINCLUDE ([Id], [Content], [Retries], [Added])\n\nCREATE NONCLUSTERED INDEX [IX_{GetReceivedTableName()}_ExpiresAt_StatusName] ON {GetReceivedTableName()} ([ExpiresAt] ASC,[StatusName] ASC)\n\nEND;\n\nIF OBJECT_ID(N'{GetPublishedTableName()}',N'U') IS NULL\nBEGIN\nCREATE TABLE {GetPublishedTableName()}(\n\t[Id] [bigint] NOT NULL,\n    [Version] [nvarchar](20) NOT NULL,\n\t[Name] [nvarchar](200) NOT NULL,\n\t[Content] [nvarchar](max) NULL,\n\t[Retries] [int] NOT NULL,\n\t[Added] [datetime2](7) NOT NULL,\n    [ExpiresAt] [datetime2](7) NULL,\n\t[StatusName] [nvarchar](50) NOT NULL,\n CONSTRAINT [PK_{GetPublishedTableName()}] PRIMARY KEY CLUSTERED\n(\n\t[Id] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\n\nCREATE NONCLUSTERED INDEX [IX_{GetPublishedTableName()}_Version_ExpiresAt_StatusName] ON {GetPublishedTableName()} ([Version] ASC,[ExpiresAt] ASC,[StatusName] ASC) \nINCLUDE ([Id], [Content], [Retries], [Added])\n\nCREATE NONCLUSTERED INDEX [IX_{GetPublishedTableName()}_ExpiresAt_StatusName] ON {GetPublishedTableName()} ([ExpiresAt] ASC,[StatusName] ASC)\n\nEND;\n\";\n        if (_capOptions.Value.UseStorageLock)\n            batchSql += $@\"\nIF OBJECT_ID(N'{GetLockTableName()}',N'U') IS NULL\nBEGIN\nCREATE TABLE {GetLockTableName()}(\n\t[Key] [nvarchar](128) NOT NULL,\n    [Instance] [nvarchar](256) NOT NULL,\n\t[LastLockTime] [datetime2](7) NOT NULL,\n CONSTRAINT [PK_{GetLockTableName()}] PRIMARY KEY CLUSTERED\n(\n\t[Key] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = ON, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] \nEND;\n\nINSERT INTO {GetLockTableName()} ([Key],[Instance],[LastLockTime]) VALUES(@PubKey,'',@LastLockTime);\nINSERT INTO {GetLockTableName()} ([Key],[Instance],[LastLockTime]) VALUES(@RecKey,'',@LastLockTime);\n\";\n        return batchSql;\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.AzureServiceBus.Test/DotNetCore.CAP.AzureServiceBus.Test.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n    <PropertyGroup>\n        <TargetFramework>net10.0</TargetFramework>\n        <Nullable>enable</Nullable>\n\n        <IsPackable>false</IsPackable>\n    </PropertyGroup>\n\n    <ItemGroup>\n        <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"18.0.1\" />\n        <PackageReference Include=\"Shouldly\" Version=\"4.3.0\" />\n        <PackageReference Include=\"xunit\" Version=\"2.9.3\" />\n        <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"3.1.5\">\n            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n            <PrivateAssets>all</PrivateAssets>\n        </PackageReference>\n        <PackageReference Include=\"coverlet.collector\" Version=\"6.0.4\">\n            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n            <PrivateAssets>all</PrivateAssets>\n        </PackageReference>\n    </ItemGroup>\n\n    <ItemGroup>\n        <ProjectReference Include=\"..\\..\\samples\\Sample.AzureServiceBus.InMemory\\Sample.AzureServiceBus.InMemory.csproj\" />\n        <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.AzureServiceBus\\DotNetCore.CAP.AzureServiceBus.csproj\" />\n    </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/DotNetCore.CAP.AzureServiceBus.Test/Helpers/ServiceBusHelperTests.cs",
    "content": "using System;\nusing DotNetCore.CAP.AzureServiceBus.Helpers;\nusing Xunit;\n\nnamespace DotNetCore.CAP.servicebus.Test.Helpers;\n\npublic class ServiceBusHelpersTests\n{\n    [Fact]\n    public void GetBrokerAddress_ShouldThrowArgumentException_WhenBothInputsAreNull()\n    {\n        // Arrange\n        string? connectionString = null;\n        string? @namespace = null;\n\n        // Act & Assert\n        var ex = Assert.Throws<ArgumentException>(() => ServiceBusHelpers.GetBrokerAddress(connectionString, @namespace));\n        Assert.Equal(\"Either connection string or namespace are required.\", ex.Message);\n    }\n\n    [Fact]\n    public void GetBrokerAddress_ShouldReturnNamespace_WhenConnectionStringIsNull()\n    {\n        // Arrange\n        string? connectionString = null;\n        string? @namespace = \"sb://mynamespace.servicebus.windows.net/\";\n\n        // Act\n        var result = ServiceBusHelpers.GetBrokerAddress(connectionString, @namespace);\n\n        // Assert\n        Assert.Equal(\"servicebus\", result.Name);\n        Assert.Equal(\"sb://mynamespace.servicebus.windows.net/\", result.Endpoint);\n    }\n\n    [Fact]\n    public void GetBrokerAddress_ShouldReturnExtractedNamespace_WhenNamespaceIsNull()\n    {\n        // Arrange\n        string? connectionString = \"Endpoint=sb://mynamespace.servicebus.windows.net/;SharedAccessKeyName=myPolicy;SharedAccessKey=myKey\";\n        string? @namespace = null;\n\n        // Act\n        var result = ServiceBusHelpers.GetBrokerAddress(connectionString, @namespace);\n\n        // Assert\n        Assert.Equal(\"servicebus\", result.Name);\n        Assert.Equal(\"sb://mynamespace.servicebus.windows.net/\", result.Endpoint);\n    }\n\n    [Fact]\n    public void GetBrokerAddress_ShouldThrowInvalidOperationException_WhenNamespaceExtractionFails()\n    {\n        // Arrange\n        string? connectionString = \"InvalidConnectionString\";\n        string? @namespace = null;\n\n        // Act & Assert\n        var ex = Assert.Throws<InvalidOperationException>(() => ServiceBusHelpers.GetBrokerAddress(connectionString, @namespace));\n        Assert.Equal(\"Unable to extract namespace from connection string.\", ex.Message);\n    }\n\n    [Fact]\n    public void GetBrokerAddress_ShouldReturnNamespace_WhenBothNamespaceAndConnectionStringAreProvided()\n    {\n        // Arrange\n        string? connectionString = \"Endpoint=sb://mynamespace.servicebus.windows.net/;SharedAccessKeyName=myPolicy;SharedAccessKey=myKey\";\n        string? @namespace = \"anothernamespace\";\n\n        // Act\n        var result = ServiceBusHelpers.GetBrokerAddress(connectionString, @namespace);\n\n        // Assert\n        Assert.Equal(\"servicebus\", result.Name);\n        Assert.Equal(\"anothernamespace\", result.Endpoint);\n    }\n\n    [Fact]\n    public void GetBrokerAddress_ShouldReturnExtractedNamespace_WhenConnectionStringIsValidAndNamespaceIsEmpty()\n    {\n        // Arrange\n        string? connectionString = \"Endpoint=sb://mynamespace.servicebus.windows.net/;SharedAccessKeyName=myPolicy;SharedAccessKey=myKey\";\n        string? @namespace = \"\";\n\n        // Act\n        var result = ServiceBusHelpers.GetBrokerAddress(connectionString, @namespace);\n\n        // Assert\n        Assert.Equal(\"servicebus\", result.Name);\n        Assert.Equal(\"sb://mynamespace.servicebus.windows.net/\", result.Endpoint);\n    }\n\n    [Fact]\n    public void GetBrokerAddress_ShouldReturnNamespace_WhenConnectionStringIsEmpty()\n    {\n        // Arrange\n        string? connectionString = \"\";\n        string? @namespace = \"sb://mynamespace.servicebus.windows.net/\";\n\n        // Act\n        var result = ServiceBusHelpers.GetBrokerAddress(connectionString, @namespace);\n\n        // Assert\n        Assert.Equal(\"servicebus\", result.Name);\n        Assert.Equal(\"sb://mynamespace.servicebus.windows.net/\", result.Endpoint);\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.AzureServiceBus.Test/Producer/ServiceBusProducerBuilderTests.cs",
    "content": "using DotNetCore.CAP.AzureServiceBus.Producer;\nusing Shouldly;\nusing Xunit;\n\nnamespace DotNetCore.CAP.AzureServiceBus.Test.Producer;\n\npublic record MessagePublished;\n\npublic class ServiceBusProducerBuilderTests\n{\n    [Fact]\n    public void Should_HavePropertiesCorrectlySet_When_Obsolete_BuildMethodIsExecuted()\n    {\n        var producer = new ServiceBusProducerDescriptorBuilder<MessagePublished>()\n            .UseTopic(\"my-destination\")\n            .Build();\n\n        producer.ShouldNotBeNull();\n        producer.TopicPath.ShouldBe(\"my-destination\");\n        producer.MessageTypeName.ShouldBe(nameof(MessagePublished));\n    }\n\n    [Theory]\n    [InlineData(\"my-destination1\", true)]\n    [InlineData(\"my-destination2\", false)]\n    public void Should_HavePropertiesCorrectlySet_When_BuildMethodIsExecuted(string topicName, bool subscriptionEnabled)\n    {\n        var builder = new ServiceBusProducerDescriptorBuilder<MessagePublished>()\n            .UseTopic(topicName);\n\n        if (subscriptionEnabled)\n        {\n            builder.WithSubscription();\n        }\n\n        var producer = builder.Build();\n        producer.ShouldNotBeNull();\n        producer.TopicPath.ShouldBe(topicName);\n        producer.CreateSubscription.ShouldBe(subscriptionEnabled);\n        producer.MessageTypeName.ShouldBe(nameof(MessagePublished));\n    }\n}\n"
  },
  {
    "path": "test/DotNetCore.CAP.AzureServiceBus.Test/ServiceBusTransportTests.cs",
    "content": "// Copyright (c) .NET Core Community. All rights reserved.\n// Licensed under the MIT License. See License.txt in the project root for license information.\n\nusing System.Collections.Generic;\nusing DotNetCore.CAP.Messages;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Sample.AzureServiceBus.InMemory.Contracts.DomainEvents;\nusing Shouldly;\nusing Xunit;\n\nnamespace DotNetCore.CAP.AzureServiceBus.Test;\n\npublic class ServiceBusTransportTests\n{\n    private readonly IOptions<AzureServiceBusOptions> _options;\n\n    public ServiceBusTransportTests()\n    {\n        var config = new AzureServiceBusOptions()\n        {\n            ConnectionString = \"Endpoint=sb://mynamespace.servicebus.windows.net/;SharedAccessKeyName=myPolicy;SharedAccessKey=myKey\" \n        };\n        \n        config.ConfigureCustomProducer<EntityCreated>(cfg => cfg.UseTopic(\"entity-created\").WithSubscription());\n\n        _options = Options.Create(config);\n    }\n\n    [Fact]\n    public void Transport_ShouldHaveCorrectBrokerAddress()\n    {\n        // Given, When\n        var transport = new AzureServiceBusTransport(NullLogger<AzureServiceBusTransport>.Instance, _options);\n        \n        // Then\n        transport.BrokerAddress.Endpoint.ShouldBe(\"sb://mynamespace.servicebus.windows.net/\");\n    }\n\n    [Fact]\n    public void CustomProducer_ShouldHaveCustomTopic()\n    {\n        // Given\n        var transport = new AzureServiceBusTransport(NullLogger<AzureServiceBusTransport>.Instance, _options);\n\n        var transportMessage = new TransportMessage(\n            headers: new Dictionary<string, string?>()\n            {\n                {Headers.MessageName, nameof(EntityCreated)}\n            },\n            body: null);\n\n        // When\n        var producer = transport.CreateProducerForMessage(transportMessage);\n\n        // Then\n        producer.MessageTypeName.ShouldBe(nameof(EntityCreated));\n        producer.TopicPath.ShouldBe(\"entity-created\");\n    }\n\n    [Fact]\n    public void DefaultProducer_ShouldHaveDefaultTopic()\n    {\n        // Given\n        var transport = new AzureServiceBusTransport(NullLogger<AzureServiceBusTransport>.Instance, _options);\n\n        var transportMessage = new TransportMessage(\n            headers: new Dictionary<string, string?>()\n            {\n                {Headers.MessageName, nameof(EntityDeleted)}\n            },\n            body: null);\n\n        // When\n        var producer = transport.CreateProducerForMessage(transportMessage);\n\n        // Then\n        producer.MessageTypeName.ShouldBe(nameof(EntityDeleted));\n        producer.TopicPath.ShouldBe(_options.Value.TopicPath);\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.MultiModuleSubscriberTests/DotNetCore.CAP.MultiModuleSubscriberTests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "test/DotNetCore.CAP.MultiModuleSubscriberTests/SubscriberClass.cs",
    "content": "﻿namespace DotNetCore.CAP.MultiModuleSubscriberTests\n{\n    public class SubscriberClass\n    {\n        public void TestSubscriber()\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "test/DotNetCore.CAP.MySql.Test/ConnectionUtil.cs",
    "content": "using System;\nusing MySqlConnector;\n\nnamespace DotNetCore.CAP.MySql.Test\n{\n    public static class ConnectionUtil\n    {\n        private const string ConnectionStringTemplateVariable = \"Cap_MySql_ConnectionString\";\n\n        private const string MasterDatabaseName = \"information_schema\";\n        private const string DefaultDatabaseName = \"cap_test\";\n\n        private const string DefaultConnectionString =\n            @\"Server=localhost;Database=cap_test;Uid=root;Pwd=123123;Allow User Variables=True;SslMode=none;AllowPublicKeyRetrieval=true\";\n\n        public static string GetDatabaseName()\n        {\n            return DefaultDatabaseName;\n        }\n\n        public static string GetMasterConnectionString()\n        {\n            return GetConnectionString().Replace(DefaultDatabaseName, MasterDatabaseName);\n        }\n\n        public static string GetConnectionString()\n        {\n            return\n                Environment.GetEnvironmentVariable(ConnectionStringTemplateVariable) ??\n                DefaultConnectionString;\n        }\n\n        public static MySqlConnection CreateConnection(string connectionString = null)\n        {\n            connectionString ??= GetConnectionString();\n            var connection = new MySqlConnection(connectionString);\n            connection.Open();\n            return connection;\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.MySql.Test/DatabaseTestHost.cs",
    "content": "using System.Threading;\nusing Dapper;\nusing DotNetCore.CAP.Persistence;\n\nnamespace DotNetCore.CAP.MySql.Test\n{\n    public abstract class DatabaseTestHost : TestHost\n    {\n        private static bool _sqlObjectInstalled;\n        public static object _lock = new object();\n\n        protected override void PostBuildServices()\n        {\n            base.PostBuildServices();\n            lock (_lock)\n            {\n                if (!_sqlObjectInstalled)\n                {\n                    InitializeDatabase();\n                }\n            }\n        }\n\n        public override void Dispose()\n        {\n            DeleteAllData();\n            base.Dispose();\n        }\n\n        private void InitializeDatabase()\n        {\n            using (CreateScope())\n            {\n                var storage = GetService<IStorageInitializer>();\n                var token = new CancellationTokenSource().Token;\n                CreateDatabase();\n                storage.InitializeAsync(token).GetAwaiter().GetResult();\n                _sqlObjectInstalled = true;\n            }\n        }\n\n        private void CreateDatabase()\n        {\n            var masterConn = ConnectionUtil.GetMasterConnectionString();\n            var databaseName = ConnectionUtil.GetDatabaseName();\n            using (var connection = ConnectionUtil.CreateConnection(masterConn))\n            {\n                connection.Execute($@\"\nDROP DATABASE IF EXISTS `{databaseName}`;\nCREATE DATABASE `{databaseName}`;\");\n            }\n        }\n\n        private void DeleteAllData()\n        {\n            var conn = ConnectionUtil.GetConnectionString();\n\n            using (var connection = ConnectionUtil.CreateConnection(conn))\n            {\n                connection.Execute($@\"\nTRUNCATE TABLE `cap.published`;\nTRUNCATE TABLE `cap.received`;\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.MySql.Test/DotNetCore.CAP.MySql.Test.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.MySql\\DotNetCore.CAP.MySql.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n  </ItemGroup>\n  \n  <ItemGroup>\n    <PackageReference Include=\"Dapper\" Version=\"2.1.66\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"18.0.1\" />\n    <PackageReference Include=\"xunit\" Version=\"2.9.3\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"3.1.5\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.4\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference> \n  </ItemGroup>\n \n</Project>"
  },
  {
    "path": "test/DotNetCore.CAP.MySql.Test/MySqlStorageConnectionTest.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Serialization;\nusing Microsoft.Extensions.Options;\nusing Xunit;\n\nnamespace DotNetCore.CAP.MySql.Test\n{\n    [Collection(\"MySql\")]\n    public class MySqlStorageConnectionTest : DatabaseTestHost\n    {\n        private readonly MySqlDataStorage _storage;\n        private ISnowflakeId _snowflakeId;\n\n        public MySqlStorageConnectionTest()\n        {\n            var serializer = GetService<ISerializer>();\n            var options = GetService<IOptions<MySqlOptions>>();\n            var capOptions = GetService<IOptions<CapOptions>>();\n            var initializer = GetService<IStorageInitializer>();\n            _snowflakeId = GetService<ISnowflakeId>();\n            _storage = new MySqlDataStorage(options, capOptions, initializer, serializer, _snowflakeId);\n        }\n\n        [Fact]\n        public void StorageMessageTest()\n        {\n            var msgId = _snowflakeId.NextId().ToString();\n            var header = new Dictionary<string, string>()\n            {\n                [Headers.MessageId] = msgId\n            };\n            var message = new Message(header, null);\n\n            var mdMessage = _storage.StoreMessageAsync(\"test.name\", message);\n            Assert.NotNull(mdMessage);\n        }\n\n        [Fact]\n        public void StoreReceivedMessageTest()\n        {\n            var msgId = _snowflakeId.NextId().ToString();\n            var header = new Dictionary<string, string>()\n            {\n                [Headers.MessageId] = msgId\n            };\n            var message = new Message(header, null);\n\n            var mdMessage = _storage.StoreReceivedMessageAsync(\"test.name\", \"test.group\", message);\n            Assert.NotNull(mdMessage);\n        }\n\n        [Fact]\n        public async Task StoreReceivedExceptionMessageTest()\n        {\n            await _storage.StoreReceivedExceptionMessageAsync(\"test.name\", \"test.group\", \"\");\n        }\n\n        [Fact]\n        public async Task ChangePublishStateTest()\n        {\n            var msgId = _snowflakeId.NextId().ToString();\n            var header = new Dictionary<string, string>()\n            {\n                [Headers.MessageId] = msgId\n            };\n            var message = new Message(header, null);\n\n            var mdMessage = await _storage.StoreMessageAsync(\"test.name\", message);\n\n            await _storage.ChangePublishStateAsync(mdMessage, StatusName.Succeeded);\n        }\n\n        [Fact]\n        public async Task ChangeReceiveStateTest()\n        {\n            var msgId = _snowflakeId.NextId().ToString();\n            var header = new Dictionary<string, string>()\n            {\n                [Headers.MessageId] = msgId\n            };\n            var message = new Message(header, null);\n\n            var mdMessage = await _storage.StoreMessageAsync(\"test.name\", message);\n\n            await _storage.ChangeReceiveStateAsync(mdMessage, StatusName.Succeeded);\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.MySql.Test/MySqlStorageTest.cs",
    "content": "﻿using Dapper;\nusing Xunit;\n\nnamespace DotNetCore.CAP.MySql.Test\n{\n    [Collection(\"MySql\")]\n    public class MySqlStorageTest : DatabaseTestHost\n    {\n        private readonly string _dbName;\n        private readonly string _masterDbConnectionString;\n\n        public MySqlStorageTest()\n        {\n            _dbName = ConnectionUtil.GetDatabaseName();\n            _masterDbConnectionString = ConnectionUtil.GetMasterConnectionString();\n        }\n\n        [Fact]\n        public void Database_IsExists()\n        {\n            using (var connection = ConnectionUtil.CreateConnection(_masterDbConnectionString))\n            {\n                var databaseName = ConnectionUtil.GetDatabaseName();\n                var sql = $@\"SELECT SCHEMA_NAME FROM SCHEMATA WHERE SCHEMA_NAME = '{databaseName}'\";\n                var result = connection.QueryFirstOrDefault<string>(sql);\n                Assert.NotNull(result);\n                Assert.True(databaseName.Equals(result, System.StringComparison.CurrentCultureIgnoreCase));\n            }\n        }\n\n        [Theory]\n        [InlineData(\"cap.published\")]\n        [InlineData(\"cap.received\")]\n        public void DatabaseTable_IsExists(string tableName)\n        {\n            using (var connection = ConnectionUtil.CreateConnection(_masterDbConnectionString))\n            {\n                var sql = $\"SELECT TABLE_NAME FROM `TABLES` WHERE TABLE_SCHEMA='{_dbName}' AND TABLE_NAME = '{tableName}'\";\n                var result = connection.QueryFirstOrDefault<string>(sql);\n                Assert.NotNull(result);\n                Assert.Equal(tableName, result);\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.MySql.Test/TestHost.cs",
    "content": "using System;\n\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Serialization;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace DotNetCore.CAP.MySql.Test\n{\n    public abstract class TestHost : IDisposable\n    {\n        protected IServiceCollection _services;\n        protected string ConnectionString;\n        private IServiceProvider _provider;\n        private IServiceProvider _scopedProvider;\n\n        public TestHost()\n        {\n            CreateServiceCollection();\n            PreBuildServices();\n            BuildServices();\n            PostBuildServices();\n        }\n\n        protected IServiceProvider Provider => _scopedProvider ?? _provider;\n\n        private void CreateServiceCollection()\n        {\n            var services = new ServiceCollection();\n\n            services.AddOptions();\n            services.AddLogging();\n\n            ConnectionString = ConnectionUtil.GetConnectionString();\n            services.AddOptions<CapOptions>();\n            services.Configure<MySqlOptions>(x =>\n            {\n                x.ConnectionString = ConnectionString;\n            });\n            services.AddSingleton<MySqlDataStorage>();            \n            services.AddSingleton<IStorageInitializer,MySqlStorageInitializer>();\n            services.AddSingleton<ISerializer, JsonUtf8Serializer>();\n            services.AddSingleton<ISnowflakeId>(e => new SnowflakeId(10));\n            _services = services;\n        }\n\n        protected virtual void PreBuildServices()\n        {\n        }\n\n        private void BuildServices()\n        {\n            _provider = _services.BuildServiceProvider();\n        }\n\n        protected virtual void PostBuildServices()\n        {\n        }\n\n        public IDisposable CreateScope()\n        {\n            var scope = CreateScope(_provider);\n            var loc = scope.ServiceProvider;\n            _scopedProvider = loc;\n            return new DelegateDisposable(() =>\n            {\n                if (_scopedProvider == loc)\n                {\n                    _scopedProvider = null;\n                }\n                scope.Dispose();\n            });\n        }\n\n        public IServiceScope CreateScope(IServiceProvider provider)\n        {\n            var scope = provider.GetService<IServiceScopeFactory>().CreateScope();\n            return scope;\n        }\n\n        public T GetService<T>() => Provider.GetService<T>();\n\n        public virtual void Dispose()\n        {\n            (_provider as IDisposable)?.Dispose();\n        }\n\n        private class DelegateDisposable : IDisposable\n        {\n            private Action _dispose;\n\n            public DelegateDisposable(Action dispose)\n            {\n                _dispose = dispose;\n            }\n\n            public void Dispose()\n            {\n                _dispose();\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/CAP.BuilderTest.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Xunit;\n\nnamespace DotNetCore.CAP.Test\n{\n    public class CapBuilderTest\n    {\n\n        [Fact]\n        public void CanCreateInstanceAndGetService()\n        {\n            var services = new ServiceCollection();\n\n            services.AddSingleton<ICapPublisher, MyProducerService>();\n            var builder = new CapBuilder(services);\n            Assert.NotNull(builder);\n\n            var count = builder.Services.Count;\n            Assert.Equal(1, count);\n\n            var provider = services.BuildServiceProvider();\n            var capPublisher = provider.GetService<ICapPublisher>();\n            Assert.NotNull(capPublisher);\n        }\n\n        [Fact]\n        public void CanAddCapService()\n        {\n            var services = new ServiceCollection();\n            services.AddCap(x => { });\n            var builder = services.BuildServiceProvider();\n\n            var markService = builder.GetService<CapMarkerService>();\n            Assert.NotNull(markService);\n        }\n\n        [Fact]\n        public void CanResolveCapOptions()\n        {\n            var services = new ServiceCollection();\n            services.AddCap(x => { });\n            var builder = services.BuildServiceProvider();\n            var capOptions = builder.GetService<IOptions<CapOptions>>().Value;\n            Assert.NotNull(capOptions);\n        }\n\n        private class MyProducerService : ICapPublisher\n        {\n            public IServiceProvider ServiceProvider { get; }\n\n            public ICapTransaction Transaction { get; set; }\n\n            public Task PublishAsync<T>(string name, T contentObj, string callbackName = null,\n                CancellationToken cancellationToken = default(CancellationToken))\n            {\n                throw new NotImplementedException();\n            }\n\n            public Task PublishAsync<T>(string name, T contentObj, IDictionary<string, string> optionHeaders = null,\n                CancellationToken cancellationToken = default)\n            {\n                throw new NotImplementedException();\n            }\n\n            public void Publish<T>(string name, T contentObj, string callbackName = null)\n            {\n                throw new NotImplementedException();\n            }\n\n            public void Publish<T>(string name, T contentObj, IDictionary<string, string> headers)\n            {\n                throw new NotImplementedException();\n            }\n\n            public Task PublishDelayAsync<T>(TimeSpan delayTime, string name, T value, IDictionary<string, string> headers, CancellationToken cancellationToken = default)\n            {\n                throw new NotImplementedException();\n            }\n\n            public Task PublishDelayAsync<T>(TimeSpan delayTime, string name, T value, string callbackName = null, CancellationToken cancellationToken = default)\n            {\n                throw new NotImplementedException();\n            }\n\n            public void PublishDelay<T>(TimeSpan delayTime, string name, T value, IDictionary<string, string> headers)\n            {\n                throw new NotImplementedException();\n            }\n\n            public void PublishDelay<T>(TimeSpan delayTime, string name, T value, string callbackName = null)\n            {\n                throw new NotImplementedException();\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/ConsumerServiceSelectorTest.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing Microsoft.Extensions.DependencyInjection;\nusing Xunit;\n\nnamespace DotNetCore.CAP.Test\n{\n    public class ConsumerServiceSelectorTest\n    {\n        private readonly IServiceProvider _provider;\n\n        public ConsumerServiceSelectorTest()\n        {\n            var services = new ServiceCollection();\n            services.AddOptions();\n            services.PostConfigure<CapOptions>(x=>{});\n            services.AddSingleton<IServiceCollection>(_ => services);\n            services.AddSingleton<IConsumerServiceSelector, ConsumerServiceSelector>();\n            services.AddScoped<IFooTest, CandidatesFooTest>();\t\t\t\n            services.AddScoped<IBarTest, CandidatesBarTest>();\n\t\t\tservices.AddScoped<IAbstractTest, CandidatesAbstractTest>();\n\t\t\tservices.AddScoped<ICancellationTest, CancellationTokenTest>();\n            services.AddLogging();\n            _provider = services.BuildServiceProvider();\n        }\n\n        [Fact]\n        public void CanFindAllConsumerService()\n        {\n            var selector = _provider.GetRequiredService<IConsumerServiceSelector>();\n            var candidates = selector.SelectCandidates();\n            \n            Assert.Equal(13, candidates.Count);\n        }\n\n        [Theory]\n        [InlineData(\"Candidates.Foo\")]\n        [InlineData(\"Candidates.Foo3\")]\n        [InlineData(\"Candidates.Foo4\")]\n        public void CanFindSpecifiedTopic(string topic)\n        {\n            var selector = _provider.GetRequiredService<IConsumerServiceSelector>();\n            var candidates = selector.SelectCandidates();\n            var bestCandidates = selector.SelectBestCandidate(topic, candidates);\n\n            Assert.NotNull(bestCandidates);\n            Assert.NotNull(bestCandidates.MethodInfo);\n            Assert.Equal(typeof(Task), bestCandidates.MethodInfo.ReturnType);\n        }\n\t\t\n\t\t[Theory]\n\t\t[InlineData(\"Candidates.Abstract\")]\n\t\t[InlineData(\"Candidates.Abstract2\")]\n\t\tpublic void CanFindInheritedMethodsTopic(string topic)\n\t\t{\n\t\t\tvar selector = _provider.GetRequiredService<IConsumerServiceSelector>();\n\t\t\tvar candidates = selector.SelectCandidates();\n\t\t\tvar bestCandidates = selector.SelectBestCandidate(topic, candidates);\n\n\t\t\tAssert.NotNull(bestCandidates);\n\t\t\tAssert.NotNull(bestCandidates.MethodInfo);\n\t\t\tAssert.Equal(typeof(Task), bestCandidates.MethodInfo.ReturnType);\n\t\t}\n\n\n        [Theory]\n        [InlineData(\"Candidates.Asterisk\")]\n        [InlineData(\"candidates.Asterisk\")]\n        [InlineData(\"AAA.BBB.Asterisk\")]\n        [InlineData(\"aaa.bbb.Asterisk\")]\n        public void CanFindAsteriskTopic(string topic)\n        {\n            var selector = _provider.GetRequiredService<IConsumerServiceSelector>();\n            var candidates = selector.SelectCandidates();\n\n            var bestCandidates = selector.SelectBestCandidate(topic, candidates);\n            Assert.NotNull(bestCandidates);\n        }\n\n        [Theory]\n        [InlineData(\"Candidates.Asterisk.AAA\")]\n        [InlineData(\"AAA.BBB.CCC.Asterisk\")]\n        [InlineData(\"aaa.BBB.ccc.Asterisk\")]\n        public void CanNotFindAsteriskTopic(string topic)\n        {\n            var selector = _provider.GetRequiredService<IConsumerServiceSelector>();\n            var candidates = selector.SelectCandidates();\n\n            var bestCandidates = selector.SelectBestCandidate(topic, candidates);\n            Assert.Null(bestCandidates);\n        }\n\n        [Theory]\n        [InlineData(\"Asterisk.aaa.bbb\")]\n        public void CanNotFindAsteriskTopic2(string topic)\n        {\n            var selector = _provider.GetRequiredService<IConsumerServiceSelector>();\n            var candidates = selector.SelectCandidates();\n\n            var bestCandidates = selector.SelectBestCandidate(topic, candidates);\n            Assert.Null(bestCandidates);\n        }\n\n        [Theory]\n        [InlineData(\"Candidates.Pound.AAA\")]\n        [InlineData(\"Candidates.Pound.AAA.BBB\")]\n        [InlineData(\"AAA.Pound\")]\n        [InlineData(\"aaa.Pound\")]\n        [InlineData(\"aaa.bbb.Pound\")]\n        [InlineData(\"aaa.BBB.Pound\")]\n        public void CanFindPoundTopic(string topic)\n        {\n            var selector = _provider.GetRequiredService<IConsumerServiceSelector>();\n            var candidates = selector.SelectCandidates();\n\n            var bestCandidates = selector.SelectBestCandidate(topic, candidates);\n            Assert.NotNull(bestCandidates);\n        }\n\n        [Theory]\n        [InlineData(\"Pound\")]\n        [InlineData(\"Pound.AAA\")]\n        [InlineData(\"Pound.aaa\")]\n        [InlineData(\"AAA.Pound.aaa\")]\n        public void CanNotFindPoundTopic(string topic)\n        {\n            var selector = _provider.GetRequiredService<IConsumerServiceSelector>();\n            var candidates = selector.SelectCandidates();\n\n            var bestCandidates = selector.SelectBestCandidate(topic, candidates);\n            Assert.Null(bestCandidates);\n        }\n\n        [Theory]\n        [InlineData(\"CancellationToken.NoAdditionalParameters\", 1, 1)]\n        [InlineData(\"CancellationToken.OneAdditionalParameter\", 2, 2)]\n        [InlineData(\"CancellationToken.CommonArrangement\", 3, 2)]\n        public void CanFindTopicSuccessfully(string topic, int parameterCount, int fromCapCount)\n        {\n            var selector = _provider.GetRequiredService<IConsumerServiceSelector>();\n            var candidates = selector.SelectCandidates();\n\n            var bestCandidate = selector.SelectBestCandidate(topic, candidates);\n            Assert.NotEmpty( candidates);\n            Assert.NotNull(bestCandidate);\n            Assert.Equal(bestCandidate.Parameters.Count, parameterCount);\n            Assert.Equal(fromCapCount, bestCandidate.Parameters.Count(x => x.IsFromCap));\n        }\n    }\n\n    public class CandidatesTopic : TopicAttribute\n    {\n        public CandidatesTopic(string topicName, bool isPartial = false) : base(topicName, isPartial)\n        {\n        }\n    }\n\n    public interface IFooTest\n    {\n    }\n\n    public interface IBarTest\n    {\n    }\n\n    public interface IAbstractTest\n    {\n    }\n\n    public interface ICancellationTest\n    {\n    }\n\n    [CandidatesTopic(\"Candidates\")]\n    public class CandidatesFooTest : IFooTest, ICapSubscribe\n    {\n        [CandidatesTopic(\"Candidates.Foo\")]\n        public Task GetFoo()\n        {\n            Console.WriteLine(\"GetFoo() method has bee excuted.\");\n            return Task.CompletedTask;\n        }\n\n        [CandidatesTopic(\"Candidates.Foo2\")]\n        public void GetFoo2()\n        {\n            Console.WriteLine(\"GetFoo2() method has bee excuted.\");\n        }\n\n        [CandidatesTopic(\"Foo3\", isPartial: true)]\n        public Task GetFoo3()\n        {\n            Console.WriteLine(\"GetFoo3() method has bee excuted.\");\n            return Task.CompletedTask;\n        }\n\n        [CandidatesTopic(\".Foo4\", isPartial: true)]\n        public Task GetFoo4()\n        {\n            Console.WriteLine(\"GetFoo4() method has bee excuted.\");\n            return Task.CompletedTask;\n        }\n\n        [CandidatesTopic(\"*.*.Asterisk\")]\n        [CandidatesTopic(\"*.Asterisk\")]\n        public void GetFooAsterisk()\n        {\n            Console.WriteLine(\"GetFoo2Asterisk() method has bee excuted.\");\n        }\n\n        [CandidatesTopic(\"Candidates.Pound.#\")]\n        [CandidatesTopic(\"#.Pound\")]\n        public void GetFooPound()\n        {\n            Console.WriteLine(\"GetFoo2Pound() method has bee excuted.\");\n        }\n\n    }\n\n    public class CandidatesBarTest : IBarTest\n    {\n        [CandidatesTopic(\"Candidates.Bar\")]\n        public Task GetBar()\n        {\n            Console.WriteLine(\"GetBar() method has bee excuted.\");\n            return Task.CompletedTask;\n        }\n\n        [CandidatesTopic(\"Candidates.Bar2\")]\n        public void GetBar2()\n        {\n            Console.WriteLine(\"GetBar2() method has bee excuted.\");\n        }\n\n        public void GetBar3()\n        {\n            Console.WriteLine(\"GetBar3() method has bee excuted.\");\n        }\n    }\n\t\n\t/// <summary>\n\t/// Test to verify if an inherited class also gets the subscribed methods.\n\t/// Abstract class doesn't have a subscribe topic, inherited class with a topic\n\t/// should also get the partial subscribed methods.\n\t/// </summary>\n\tpublic abstract class CandidatesAbstractBaseTest : ICapSubscribe, IAbstractTest\n\t{\n\t\t[CandidatesTopic(\"Candidates.Abstract\")]\n\t\tpublic virtual Task GetAbstract()\n\t\t{\n\t\t  Console.WriteLine(\"GetAbstract() method has been excuted.\");\n\t\t  return Task.CompletedTask;\n\t\t}\n\n\t\t[CandidatesTopic(\"Abstract2\", isPartial: true)]\n\t\tpublic virtual Task GetAbstract2()\n\t\t{\n\t\t  Console.WriteLine(\"GetAbstract2() method has been excuted.\");\n\t\t  return Task.CompletedTask;\n\t\t}\n\t}\n\n\t[CandidatesTopic(\"Candidates\")]\n\tpublic class CandidatesAbstractTest : CandidatesAbstractBaseTest\n\t{\n\t}\n    \n    [CandidatesTopic(\"Candidates\")]\n    public class CancellationTokenTest : ICancellationTest, ICapSubscribe\n    {\n        [CandidatesTopic(\"CancellationToken.NoAdditionalParameters\")]\n        public Task NoAdditionalParameters(CancellationToken cancellationToken)\n        {\n            Console.WriteLine($\"{nameof(NoAdditionalParameters)} method has been executed.\");\n            return Task.CompletedTask;\n        }\n\n        [CandidatesTopic(\"CancellationToken.OneAdditionalParameter\")]\n        public Task OneAdditionalParameter([FromCap] CapHeader headers, CancellationToken cancellationToken)\n        {\n            Console.WriteLine($\"{nameof(OneAdditionalParameter)} method has been executed.\");\n            return Task.CompletedTask;\n        }\n\n        [CandidatesTopic(\"CancellationToken.CommonArrangement\")]\n        public Task CommonArrangement(DateTime date, [FromCap] IDictionary<string, string> headers, CancellationToken cancellationToken)\n        {\n            Console.WriteLine($\"{nameof(CommonArrangement)} method has been executed.\");\n            return Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/CustomConsumerSubscribeTest.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Xunit;\n\nnamespace DotNetCore.CAP.Test\n{\n    public class CustomConsumerSubscribeTest\n    {\n        private const string TopicNamePrefix = \"topic\";\n        private const string GroupNamePrefix = \"group\";\n\n        private readonly IServiceProvider _provider;\n\n        public CustomConsumerSubscribeTest()\n        {\n            var services = new ServiceCollection();\n            services.AddSingleton<IConsumerServiceSelector, MyConsumerServiceSelector>();\n            services.AddTransient<IMySubscribe, CustomInterfaceTypesClass>();\n            services.AddLogging();\n            services.AddCap(x =>\n            {\n                x.TopicNamePrefix = TopicNamePrefix;\n                x.GroupNamePrefix = GroupNamePrefix;\n            });\n            _provider = services.BuildServiceProvider();\n        }\n\n        [Fact]\n        public void CanFindAllConsumerService()\n        {\n            var selector = _provider.GetRequiredService<IConsumerServiceSelector>();\n            var candidates = selector.SelectCandidates();\n\n            Assert.Equal(2, candidates.Count);\n        }\n\n        [Fact]\n        public void CanFindSpecifiedTopic()\n        {\n            var selector = _provider.GetRequiredService<IConsumerServiceSelector>();\n            var candidates = selector.SelectCandidates();\n            var bestCandidates = selector.SelectBestCandidate($\"{TopicNamePrefix}.Candidates.Foo\", candidates);\n\n            Assert.NotNull(bestCandidates);\n            Assert.NotNull(bestCandidates.MethodInfo);\n            Assert.StartsWith(GroupNamePrefix, bestCandidates.Attribute.Group);\n            Assert.StartsWith(TopicNamePrefix, bestCandidates.TopicName);\n            Assert.Equal(typeof(Task), bestCandidates.MethodInfo.ReturnType);\n        }\n    }\n\n    public class MyConsumerServiceSelector : ConsumerServiceSelector\n    {\n        private readonly CapOptions _capOptions;\n\n        public MyConsumerServiceSelector(IServiceProvider serviceProvider)\n            : base(serviceProvider)\n        {\n            _capOptions = serviceProvider.GetService<IOptions<CapOptions>>().Value;\n        }\n\n        protected override IEnumerable<ConsumerExecutorDescriptor> FindConsumersFromInterfaceTypes(IServiceProvider provider)\n        {\n            var executorDescriptorList = new List<ConsumerExecutorDescriptor>();\n\n            using (var scoped = provider.CreateScope())\n            {\n                var scopedProvider = scoped.ServiceProvider;\n                var consumerServices = scopedProvider.GetServices<IMySubscribe>();\n                foreach (var service in consumerServices)\n                {\n                    var typeInfo = service.GetType().GetTypeInfo();\n                    if (!typeof(IMySubscribe).GetTypeInfo().IsAssignableFrom(typeInfo))\n                    {\n                        continue;\n                    }\n\n                    executorDescriptorList.AddRange(GetMyDescription(typeInfo));\n                }\n\n                return executorDescriptorList;\n            }\n        }\n\n        private IEnumerable<ConsumerExecutorDescriptor> GetMyDescription(TypeInfo typeInfo)\n        {\n            foreach (var method in typeInfo.DeclaredMethods)\n            {\n                var topicAttr = method.GetCustomAttributes<MySubscribeAttribute>(true);\n                var topicAttributes = topicAttr as IList<MySubscribeAttribute> ?? topicAttr.ToList();\n\n                if (!topicAttributes.Any())\n                {\n                    continue;\n                }\n\n                foreach (var attr in topicAttributes)\n                {\n                    if (attr.Group == null)\n                    {\n                        attr.Group = _capOptions.DefaultGroupName + \".\" + _capOptions.Version;\n                    }\n                    else\n                    {\n                        attr.Group = attr.Group + \".\" + _capOptions.Version;\n                    }\n\n                    if (!string.IsNullOrEmpty(_capOptions.GroupNamePrefix))\n                    {\n                        attr.Group = $\"{_capOptions.GroupNamePrefix}.{attr.Group}\";\n                    }\n\n                    var parameters = method.GetParameters()\n                    .Select(parameter => new ParameterDescriptor\n                    {\n                        Name = parameter.Name,\n                        ParameterType = parameter.ParameterType,\n                        IsFromCap = parameter.GetCustomAttributes(typeof(FromCapAttribute)).Any()\n                    }).ToList();\n\n                    yield return new ConsumerExecutorDescriptor\n                    {\n                        Attribute = new CapSubscribeAttribute(attr.Name)\n                        {\n                            Group = attr.Group\n                        },\n                        Parameters = parameters,\n                        MethodInfo = method,\n                        ImplTypeInfo = typeInfo,\n                        TopicNamePrefix = _capOptions.TopicNamePrefix\n                    };\n                }\n            }\n        }\n    }\n\n    public interface IMySubscribe { }\n\n    public class MySubscribeAttribute : Attribute\n    {\n        public MySubscribeAttribute(string name)\n        {\n            Name = name;\n        }\n\n        public string Name { get; }\n\n        public string Group { get; set; }\n    }\n\n    public class CustomInterfaceTypesClass : IMySubscribe\n    {\n        [MySubscribe(\"Candidates.Foo\")]\n        public Task GetFoo()\n        {\n            Console.WriteLine(\"GetFoo() method has been excuted.\");\n            return Task.CompletedTask;\n        }\n\n        [MySubscribe(\"Candidates.Foo2\")]\n        public void GetFoo2()\n        {\n            Console.WriteLine(\"GetFoo2() method has been excuted.\");\n        }\n\n        public void DistracterMethod()\n        {\n            Console.WriteLine(\"DistracterMethod() method has been excuted.\");\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/DispatcherTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Processor;\nusing DotNetCore.CAP.Test.Helpers;\nusing FluentAssertions;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing NSubstitute;\nusing Xunit;\n\nnamespace DotNetCore.CAP.Test;\n\npublic class DispatcherTests\n{\n    private readonly ILogger<Dispatcher> _logger;\n    private readonly ISubscribeExecutor _executor;\n    private readonly IDataStorage _storage;\n\n    public DispatcherTests()\n    {\n        _logger = Substitute.For<ILogger<Dispatcher>>();\n        _executor = Substitute.For<ISubscribeExecutor>();\n        _storage = Substitute.For<IDataStorage>();\n    }\n\n    [Fact]\n    public async Task EnqueueToPublish_ShouldInvokeSend_WhenParallelSendDisabled()\n    {\n        // Arrange\n        var sender = new TestThreadSafeMessageSender();\n        var options = Options.Create(new CapOptions\n        {\n            EnableSubscriberParallelExecute = true,\n            EnablePublishParallelSend = false,\n            SubscriberParallelExecuteThreadCount = 2,\n            SubscriberParallelExecuteBufferFactor = 2\n        });\n\n        var dispatcher = new Dispatcher(_logger, sender, options, _executor, _storage);\n\n        using var cts = new CancellationTokenSource();\n        var messageId = \"testId\";\n\n        // Act\n        await dispatcher.StartAsync(cts.Token);\n        await dispatcher.EnqueueToPublish(CreateTestMessage(messageId));\n        await cts.CancelAsync();\n\n        // Assert\n        sender.Count.Should().Be(1);\n        sender.ReceivedMessages.First().DbId.Should().Be(messageId);\n    }\n\n    [Fact]\n    public async Task EnqueueToPublish_ShouldBeThreadSafe_WhenParallelSendDisabled()\n    {\n        // Arrange\n        var sender = new TestThreadSafeMessageSender();\n        var options = Options.Create(new CapOptions\n        {\n            EnableSubscriberParallelExecute = true,\n            EnablePublishParallelSend = false,\n            SubscriberParallelExecuteThreadCount = 2,\n            SubscriberParallelExecuteBufferFactor = 2\n        });\n        var dispatcher = new Dispatcher(_logger, sender, options, _executor, _storage);\n\n        using var cts = new CancellationTokenSource();\n        var messages = Enumerable.Range(1, 100)\n            .Select(i => CreateTestMessage(i.ToString()))\n            .ToArray();\n\n        // Act\n        await dispatcher.StartAsync(cts.Token);\n\n        var tasks = messages\n            .Select(msg => Task.Run(() => dispatcher.EnqueueToPublish(msg), CancellationToken.None));\n        await Task.WhenAll(tasks);\n        await cts.CancelAsync();\n\n        // Assert\n        sender.Count.Should().Be(100);\n        var receivedMessages = sender.ReceivedMessages.Select(m => m.DbId).Order().ToList();\n        var expected = messages.Select(m => m.DbId).Order().ToList();\n        expected.Should().Equal(receivedMessages);\n    }\n\n    [Fact]\n    public async Task EnqueueToScheduler_ShouldBeThreadSafe_WhenDelayLessThenMinute()\n    {\n        // Arrange\n        var sender = new TestThreadSafeMessageSender();\n        var options = Options.Create(new CapOptions\n        {\n            EnableSubscriberParallelExecute = true,\n            EnablePublishParallelSend = false,\n            SubscriberParallelExecuteThreadCount = 2,\n            SubscriberParallelExecuteBufferFactor = 2\n        });\n        var dispatcher = new Dispatcher(_logger, sender, options, _executor, _storage);\n\n        using var cts = new CancellationTokenSource();\n        var messages = Enumerable.Range(1, 10000)\n            .Select(i => CreateTestMessage(i.ToString()))\n            .ToArray();\n\n        // Act\n        await dispatcher.StartAsync(cts.Token);\n        var dateTime = DateTime.Now.AddSeconds(1);\n        await Parallel.ForEachAsync(messages, CancellationToken.None,\n            async (m, ct) => { await dispatcher.EnqueueToScheduler(m, dateTime); });\n\n        await Task.Delay(1500, CancellationToken.None);\n\n        await cts.CancelAsync();\n\n        // Assert\n        sender.Count.Should().Be(10000);\n\n        var receivedMessages = sender.ReceivedMessages.Select(m => m.DbId).Order().ToList();\n        var expected = messages.Select(m => m.DbId).Order().ToList();\n        expected.Should().Equal(receivedMessages);\n    }\n\n    [Fact]\n    public async Task EnqueueToScheduler_ShouldSendMessagesInCorrectOrder_WhenEarlierMessageIsSentLater()\n    {\n        // Arrange\n        var sender = new TestThreadSafeMessageSender();\n        var options = Options.Create(new CapOptions\n        {\n            EnableSubscriberParallelExecute = true,\n            EnablePublishParallelSend = false,\n            SubscriberParallelExecuteThreadCount = 2,\n            SubscriberParallelExecuteBufferFactor = 2\n        });\n        var dispatcher = new Dispatcher(_logger, sender, options, _executor, _storage);\n\n        using var cts = new CancellationTokenSource();\n        var messages = Enumerable.Range(1, 3)\n            .Select(i => CreateTestMessage(i.ToString()))\n            .ToArray();\n\n        // Act\n        await dispatcher.StartAsync(cts.Token);\n        var dateTime = DateTime.Now;\n\n        await dispatcher.EnqueueToScheduler(messages[0], dateTime.AddSeconds(1));\n        await dispatcher.EnqueueToScheduler(messages[1], dateTime.AddMilliseconds(200));\n        await dispatcher.EnqueueToScheduler(messages[2], dateTime.AddMilliseconds(100));\n\n        await Task.Delay(1200, CancellationToken.None);\n        await cts.CancelAsync();\n\n        // Assert\n        sender.ReceivedMessages.Select(m => m.DbId).Should().Equal([\"3\", \"2\", \"1\"]);\n    }\n\n    [Fact]\n    public async Task EnqueueToScheduler_ShouldBeThreadSafe_WhenDelayLessThenMinuteAndParallelSendEnabled()\n    {\n        // Arrange\n        var sender = new TestThreadSafeMessageSender();\n        var options = Options.Create(new CapOptions\n        {\n            EnableSubscriberParallelExecute = false,\n            EnablePublishParallelSend = true,\n            SubscriberParallelExecuteThreadCount = 2,\n            SubscriberParallelExecuteBufferFactor = 2\n        });\n        var dispatcher = new Dispatcher(_logger, sender, options, _executor, _storage);\n\n        using var cts = new CancellationTokenSource();\n        var messages = Enumerable.Range(1, 10000)\n            .Select(i => CreateTestMessage(i.ToString()))\n            .ToArray();\n\n        // Act\n        await dispatcher.StartAsync(cts.Token);\n        var dateTime = DateTime.Now.AddMilliseconds(50);\n        await Parallel.ForEachAsync(messages, CancellationToken.None,\n            async (m, ct) => { await dispatcher.EnqueueToScheduler(m, dateTime); });\n\n        await Task.Delay(3000, CancellationToken.None);\n\n        await cts.CancelAsync();\n\n        // Assert\n        sender.Count.Should().Be(10000);\n\n        var receivedMessages = sender.ReceivedMessages.Select(m => m.DbId).Order().ToList();\n        var expected = messages.Select(m => m.DbId).Order().ToList();\n        expected.Should().Equal(receivedMessages);\n    }\n\n    [Fact]\n    public async Task EnqueueToScheduler_ShouldSendMessagesInCorrectOrder_WhenParallelSendEnabled()\n    {\n        // Arrange\n        var sender = new TestThreadSafeMessageSender();\n        var options = Options.Create(new CapOptions\n        {\n            EnableSubscriberParallelExecute = true,\n            EnablePublishParallelSend = true,\n            SubscriberParallelExecuteThreadCount = 2,\n            SubscriberParallelExecuteBufferFactor = 2,\n        });\n        var dispatcher = new Dispatcher(_logger, sender, options, _executor, _storage);\n\n        using var cts = new CancellationTokenSource();\n        var messages = Enumerable.Range(1, 3)\n            .Select(i => CreateTestMessage(i.ToString()))\n            .ToArray();\n\n        // Act\n        await dispatcher.StartAsync(cts.Token);\n        var dateTime = DateTime.Now;\n\n        await dispatcher.EnqueueToScheduler(messages[0], dateTime.AddSeconds(1));\n        await dispatcher.EnqueueToScheduler(messages[1], dateTime.AddMilliseconds(200));\n        await dispatcher.EnqueueToScheduler(messages[2], dateTime.AddMilliseconds(100));\n\n        await Task.Delay(1200, CancellationToken.None);\n        await cts.CancelAsync();\n\n        // Assert\n        sender.ReceivedMessages.Select(m => m.DbId).Should().Equal([\"3\", \"2\", \"1\"]);\n    }\n\n    private MediumMessage CreateTestMessage(string id = \"1\")\n    {\n        return new MediumMessage()\n        {\n            DbId = id,\n            Origin = new Message(\n                headers: new Dictionary<string, string>()\n                {\n                    { \"cap-msg-id\", id }\n                },\n                value: new MessageValue(\"test@test.com\", \"User\"))\n        };\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<TargetFramework>net10.0</TargetFramework>\n\t\t<IsPackable>false</IsPackable>\n\t</PropertyGroup>\n\n\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|AnyCPU'\">\n\t\t<NoWarn>1701;1702;CS0067;CA1822</NoWarn>\n\t</PropertyGroup>\n\n\t<ItemGroup>\n\t\t<PackageReference Include=\"Microsoft.Extensions.DependencyInjection\" Version=\"10.0.0\" />\n\t\t<PackageReference Include=\"Microsoft.Extensions.Logging\" Version=\"10.0.0\" />\n\t\t<PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"18.0.1\" />\n\t\t<PackageReference Include=\"xunit\" Version=\"2.9.3\" />\n\t\t<PackageReference Include=\"xunit.runner.visualstudio\" Version=\"3.1.5\">\n\t\t\t<PrivateAssets>all</PrivateAssets>\n\t\t\t<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n\t\t</PackageReference>\n\t\t<PackageReference Include=\"coverlet.collector\" Version=\"6.0.4\">\n\t\t\t<PrivateAssets>all</PrivateAssets>\n\t\t\t<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n\t\t</PackageReference>\n\t\t<PackageReference Include=\"FluentAssertions\" Version=\"8.8.0\" />\n\t\t<PackageReference Include=\"NSubstitute\" Version=\"5.3.0\" />\n\t</ItemGroup>\n\n\t<ItemGroup>\n\t\t<ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP.InMemoryStorage\\DotNetCore.CAP.InMemoryStorage.csproj\" />\n\t\t<ProjectReference Include=\"..\\..\\src\\DotNetCore.CAP\\DotNetCore.CAP.csproj\" />\n\t\t<ProjectReference Include=\"..\\DotNetCore.CAP.MultiModuleSubscriberTests\\DotNetCore.CAP.MultiModuleSubscriberTests.csproj\" />\n\t</ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/DotNetCore.CAP.Test/FakeInMemoryQueue/CAP.FakeQueueOptionsExtension.cs",
    "content": "﻿using DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace DotNetCore.CAP.Test.FakeInMemoryQueue\n{\n    internal sealed class FakeQueueOptionsExtension : ICapOptionsExtension\n    {\n\n        public void AddServices(IServiceCollection services)\n        {\n            services.AddSingleton<CapMessageQueueMakerService>();\n\n            services.AddSingleton<InMemoryQueue>();\n            services.AddSingleton<IConsumerClientFactory, InMemoryConsumerClientFactory>();\n            services.AddSingleton<ITransport, FakeInMemoryQueueTransport>();\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/FakeInMemoryQueue/CAP.Options.Extensions.cs",
    "content": "﻿namespace DotNetCore.CAP.Test.FakeInMemoryQueue\n{\n    public static class CapOptionsExtensions\n    {\n        public static CapOptions UseFakeTransport(this CapOptions options)\n        {\n            options.RegisterExtension(new FakeQueueOptionsExtension());\n            return options;\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/FakeInMemoryQueue/ITransport.FakeInMemory.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Logging;\n\nnamespace DotNetCore.CAP.Test.FakeInMemoryQueue\n{\n    internal class FakeInMemoryQueueTransport : ITransport\n    {\n        private readonly InMemoryQueue _queue;\n        private readonly ILogger _logger;\n\n        public FakeInMemoryQueueTransport(InMemoryQueue queue, ILogger<FakeInMemoryQueueTransport> logger)\n        {\n            _queue = queue;\n            _logger = logger;\n        }\n\n        public BrokerAddress BrokerAddress { get; } = new BrokerAddress(\"InMemory\", string.Empty);\n\n        public Task<OperateResult> SendAsync(TransportMessage message)\n        {\n            try\n            {\n                _queue.Send(message.GetName(), message);\n\n                _logger.LogDebug($\"Event message [{message.GetName()}] has been published.\");\n\n                return Task.FromResult(OperateResult.Success);\n            }\n            catch (Exception ex)\n            {\n                var wrapperEx = new PublisherSentFailedException(ex.Message, ex);\n\n                return Task.FromResult(OperateResult.Failed(wrapperEx));\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryConsumerClient.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Logging;\n\nnamespace DotNetCore.CAP.Test.FakeInMemoryQueue\n{\n    internal sealed class InMemoryConsumerClient : IConsumerClient\n    {\n        private readonly ILogger _logger;\n        private readonly InMemoryQueue _queue;\n        private readonly SemaphoreSlim _semaphore;\n        private readonly byte _concurrent;\n        private readonly string _subscriptionName;\n\n        public InMemoryConsumerClient(ILogger logger, InMemoryQueue queue, string subscriptionName, byte concurrent)\n        {\n            _logger = logger;\n            _queue = queue;\n            _concurrent = concurrent;\n            _semaphore = new SemaphoreSlim(_concurrent);\n            _subscriptionName = subscriptionName;\n        }\n\n        public Func<TransportMessage, object, Task> OnMessageCallback { get; set; }\n\n        public Action<LogMessageEventArgs> OnLogCallback { get; set; }\n\n        public BrokerAddress BrokerAddress => new BrokerAddress(\"InMemory\", string.Empty);\n\n        public Task SubscribeAsync(IEnumerable<string> topics)\n        {\n            if (topics == null) throw new ArgumentNullException(nameof(topics));\n\n            foreach (var topic in topics)\n            {\n                _queue.Subscribe(_subscriptionName, OnConsumerReceived, topic);\n\n                _logger.LogInformation($\"InMemory message queue initialize the topic: {topic}\");\n            }\n\n            return Task.CompletedTask;\n        }\n\n        public Task ListeningAsync(TimeSpan timeout, CancellationToken cancellationToken)\n        {\n            while (!cancellationToken.IsCancellationRequested)\n            {\n                cancellationToken.WaitHandle.WaitOne(timeout);\n            }\n            return Task.CompletedTask;\n        }\n\n        public Task CommitAsync(object sender)\n        {\n            _semaphore.Release();\n            return Task.CompletedTask;\n        }\n\n        public Task RejectAsync(object sender)\n        {\n            _semaphore.Release();\n            return Task.CompletedTask;\n        }\n\n        public ValueTask DisposeAsync()\n        {\n            _queue.ClearSubscriber();\n            return ValueTask.CompletedTask;\n        }\n\n        #region private methods\n\n        private void OnConsumerReceived(TransportMessage e)\n        {\n            var headers = e.Headers;\n            headers.TryAdd(Headers.Group, _subscriptionName);\n            if (_concurrent > 0)\n            {\n                _semaphore.Wait();\n                Task.Run(() => OnMessageCallback(e, null)).ConfigureAwait(false);\n            }\n            else\n            {\n                OnMessageCallback(e, null).GetAwaiter().GetResult();\n            }\n        }\n        #endregion private methods\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryConsumerClientFactory.cs",
    "content": "﻿using System.Threading.Tasks;\nusing DotNetCore.CAP.Transport;\nusing Microsoft.Extensions.Logging;\n\nnamespace DotNetCore.CAP.Test.FakeInMemoryQueue\n{\n    internal sealed class InMemoryConsumerClientFactory : IConsumerClientFactory\n    {\n        private readonly ILoggerFactory _loggerFactory;\n        private readonly InMemoryQueue _queue;\n\n        public InMemoryConsumerClientFactory(ILoggerFactory loggerFactory, InMemoryQueue queue)\n        {\n            _loggerFactory = loggerFactory;\n            _queue = queue;\n        }\n\n        public Task<IConsumerClient> CreateAsync(string groupName, byte groupConcurrent)\n        {\n            var logger = _loggerFactory.CreateLogger(typeof(InMemoryConsumerClient));\n            var client = new InMemoryConsumerClient(logger, _queue, groupName, groupConcurrent);\n            return Task.FromResult<IConsumerClient>(client);\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryQueue.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing DotNetCore.CAP.Messages;\nusing Microsoft.Extensions.Logging;\n\nnamespace DotNetCore.CAP.Test.FakeInMemoryQueue\n{\n    internal class InMemoryQueue\n    {\n        private readonly ILogger<InMemoryQueue> _logger;\n        private static readonly object Lock = new object();\n\n        private readonly Dictionary<string, (Action<TransportMessage>, List<string>)> _groupTopics;\n\n        public Dictionary<string, TransportMessage> Messages { get; }\n\n        public InMemoryQueue(ILogger<InMemoryQueue> logger)\n        {\n            _logger = logger;\n            _groupTopics = new Dictionary<string, (Action<TransportMessage>, List<string>)>();\n            Messages = new Dictionary<string, TransportMessage>();\n        }\n\n        public void Subscribe(string groupId, Action<TransportMessage> received, string topic)\n        {\n            lock (Lock)\n            {\n                if (_groupTopics.ContainsKey(groupId))\n                {\n                    var topics = _groupTopics[groupId];\n                    if (!topics.Item2.Contains(topic))\n                    {\n                        topics.Item2.Add(topic);\n                    }\n                }\n                else\n                {\n                    _groupTopics.Add(groupId, (received, new List<string> { topic }));\n                }\n            }\n        }\n\n        public void ClearSubscriber()\n        {\n            _groupTopics.Clear();\n        }\n\n        public void Send(string topic, TransportMessage message)\n        {\n            Messages.Add(topic, message);\n            foreach (var groupTopic in _groupTopics)\n            {\n                if (groupTopic.Value.Item2.Contains(topic))\n                {\n                    try\n                    {\n                        groupTopic.Value.Item1?.Invoke(message);\n                    }\n                    catch (Exception e)\n                    {\n                        _logger.LogError(e, $\"Consumption message raises an exception. Group-->{groupTopic.Key} Name-->{topic}\");\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/DotNetCore.CAP.Test/GenericConsumerServiceSelector.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing DotNetCore.CAP.Internal;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\n\nnamespace DotNetCore.CAP.Test\n{\n    /// <summary>\n    /// Allows caller to supply subscribe interface and attribute when adding services.\n    /// </summary>\n    /// <typeparam name=\"TSubscriber\"></typeparam>\n    /// <typeparam name=\"TSubscriptionAttribute\"></typeparam>\n    public class GenericConsumerServiceSelector<TSubscriber, TSubscriptionAttribute> : ConsumerServiceSelector\n        where TSubscriptionAttribute : Attribute, INamedGroup\n    {\n        private readonly CapOptions _capOptions;\n        \n        public GenericConsumerServiceSelector(IServiceProvider serviceProvider)\n            : base(serviceProvider)\n        {\n            _capOptions = serviceProvider.GetRequiredService<IOptions<CapOptions>>().Value;\n        }\n\n        /// <inheritdoc cref=\"ConsumerServiceSelector\"/>\n        protected override IEnumerable<ConsumerExecutorDescriptor> FindConsumersFromInterfaceTypes(IServiceProvider provider)\n        {\n            var executorDescriptorList = new List<ConsumerExecutorDescriptor>();\n\n            using (var scoped = provider.CreateScope())\n            {\n                var scopedProvider = scoped.ServiceProvider;\n                var subscribers = scopedProvider.GetServices<TSubscriber>();\n                var subscriberTypeInfo = typeof(TSubscriber).GetTypeInfo();\n                foreach (var service in subscribers)\n                {\n                    var serviceTypeInfo = service?.GetType().GetTypeInfo();\n                    if (serviceTypeInfo == null || !subscriberTypeInfo.IsAssignableFrom(serviceTypeInfo))\n                    {\n                        continue;\n                    }\n\n                    var descriptors = _GetDescriptors(serviceTypeInfo);\n                    executorDescriptorList.AddRange(descriptors);\n                }\n\n                return executorDescriptorList;\n            }\n        }\n\n        private IEnumerable<ConsumerExecutorDescriptor> _GetDescriptors(TypeInfo typeInfo)\n        {\n            foreach (var method in typeInfo.DeclaredMethods)\n            {\n                var topicAttr = method.GetCustomAttributes<TSubscriptionAttribute>(true);\n                var topicAttributes = topicAttr as IList<TSubscriptionAttribute> ?? topicAttr.ToList();\n\n                if (!topicAttributes.Any())\n                {\n                    continue;\n                }\n\n                foreach (var attr in topicAttributes)\n                {\n                    _SetAttributeGroup(attr);\n\n                    yield return new ConsumerExecutorDescriptor\n                    {\n                        Attribute = new CapSubscribeAttribute(attr.Name)\n                        {\n                            Group = attr.Group\n                        },\n                        MethodInfo = method,\n                        ImplTypeInfo = typeInfo,\n                        TopicNamePrefix = _capOptions.TopicNamePrefix,\n                        Parameters = _GetParameterDescriptors(method)\n                    };\n                }\n            }\n        }\n\n        private void _SetAttributeGroup(TSubscriptionAttribute attr)\n        {\n            if (attr.Group == null)\n            {\n                attr.Group = _capOptions.DefaultGroupName + \".\" + _capOptions.Version;\n            }\n            else\n            {\n                attr.Group = attr.Group + \".\" + _capOptions.Version;\n            }\n\n            if (!string.IsNullOrEmpty(_capOptions.GroupNamePrefix))\n            {\n                attr.Group = $\"{_capOptions.GroupNamePrefix}.{attr.Group}\";\n            }\n        }\n\n        private IList<ParameterDescriptor> _GetParameterDescriptors(MethodInfo method)\n        {\n            var descriptors = method.GetParameters().Select(p => new ParameterDescriptor()\n                {Name = p.Name, ParameterType = p.ParameterType, IsFromCap = p.GetCustomAttributes<FromCapAttribute>().Any()});\n            return new List<ParameterDescriptor>(descriptors.ToArray());\n        }\n    }\n    \n    /// <summary>\n    /// Implementers have a name and a group.\n    /// </summary>\n    public interface INamedGroup\n    {\n        string Name { get; }\n\n        string Group { get; set; }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/HelperTest.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing DotNetCore.CAP.Internal;\nusing Xunit;\n\nnamespace DotNetCore.CAP.Test\n{\n    public class HelperTest\n    {\n        [Fact]\n        public void IsControllerTest()\n        {\n            //Arrange\n            var typeInfo = typeof(HomeController).GetTypeInfo();\n\n            //Act\n            var result = Helper.IsController(typeInfo);\n\n            //Assert\n            Assert.True(result);\n        }\n\n        [Fact]\n        public void IsControllerAbstractTest()\n        {\n            //Arrange\n            var typeInfo = typeof(AbstractController).GetTypeInfo();\n\n            //Act\n            var result = Helper.IsController(typeInfo);\n\n            //Assert\n            Assert.False(result);\n        }\n\n        [Theory]\n        [InlineData(typeof(string))]\n        [InlineData(typeof(decimal))]\n        [InlineData(typeof(DateTime))]\n        [InlineData(typeof(DateTimeOffset))]\n        [InlineData(typeof(Guid))]\n        [InlineData(typeof(TimeSpan))]\n        [InlineData(typeof(Uri))]\n        public void IsSimpleTypeTest(Type type)\n        {\n            //Act\n            var result = Helper.IsComplexType(type);\n\n            //Assert \n            Assert.False(result);\n        }\n\n        [Theory]\n        [InlineData(typeof(HomeController))]\n        [InlineData(typeof(Exception))]\n        public void IsComplexTypeTest(Type type)\n        {\n            //Act\n            var result = Helper.IsComplexType(type);\n\n            //Assert \n            Assert.True(result);\n        }\n\n        [Theory]\n        [InlineData(\"10.0.0.1\")]\n        [InlineData(\"172.16.0.1\")]\n        [InlineData(\"192.168.1.1\")]\n        public void IsInnerIPTest(string ipAddress)\n        {\n            Assert.True(Helper.IsInnerIP(ipAddress));\n        }\n    }\n\n    public class HomeController\n    {\n        \n    }\n\n    public abstract class AbstractController\n    {\n\n    }\n}\n"
  },
  {
    "path": "test/DotNetCore.CAP.Test/Helpers/ObservableCollectionExtensions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Collections.Specialized;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace DotNetCore.CAP.Test.Helpers\n{\n    public static class ObservableCollectionExtensions\n    {\n        public static async Task WaitOneMessage<T>(this ObservableCollection<T> collection,\n            CancellationToken cancellationToken)\n        {\n            await WaitForMessages(collection,\n                x => x.Count() == 1,\n                cancellationToken);\n        }\n\n        public static async Task WaitForMessages<T>(this ObservableCollection<T> collection, \n            Func<IEnumerable<T>, bool> comparison,\n            CancellationToken cancellationToken)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            var cts = new CancellationTokenSource();\n            cancellationToken.Register(() => cts.Cancel());\n\n            await Task.Run(async () =>\n            {\n                void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)\n                {\n                    if (comparison(collection))\n                    {\n                        cts.Cancel();\n                    }\n                }\n\n                collection.CollectionChanged += OnCollectionChanged;\n                \n                if (collection.Count > 0)\n                {\n                    OnCollectionChanged(collection, default);\n                }\n\n                try\n                {\n                    await Task.Delay(-1, cts.Token);\n                }\n                catch (TaskCanceledException)\n                {\n                }\n                finally\n                {\n                    collection.CollectionChanged -= OnCollectionChanged;\n                }\n\n                cancellationToken.ThrowIfCancellationRequested();\n\n            }, cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/Helpers/TestBootstrapService.cs",
    "content": "﻿using System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Hosting;\n\nnamespace DotNetCore.CAP.Test.Helpers\n{\n    public class TestBootstrapService : IHostedService\n    {\n        private readonly IBootstrapper _bootstrapper;\n\n        public TestBootstrapService(IBootstrapper bootstrapper)\n        {\n            _bootstrapper = bootstrapper;\n        }\n\n        public async Task StartAsync(CancellationToken cancellationToken)\n        {\n            await _bootstrapper.BootstrapAsync();\n        }\n\n        public Task StopAsync(CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/Helpers/TestHostedServiceExtensions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\n\nnamespace DotNetCore.CAP.Test.Helpers\n{\n    public static class TestHostedServiceExtensions\n    {\n        public static void StartHostedServices(this IServiceProvider serviceProvider, CancellationToken cancellationToken)\n        {\n            Task.Run(async () =>\n                {\n                    var hostedServices = serviceProvider.GetRequiredService<IEnumerable<IHostedService>>();\n                    foreach (var hostedService in hostedServices)\n                    {\n                        await hostedService.StartAsync(cancellationToken);\n                    }\n                }, cancellationToken)\n                .GetAwaiter().GetResult();\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/Helpers/TestLogger.cs",
    "content": "﻿using System;\nusing Microsoft.Extensions.Logging;\nusing Xunit.Abstractions;\n\nnamespace DotNetCore.CAP.Test.Helpers\n{\n    public class TestLogger : ILogger\n    {\n        private readonly ITestOutputHelper _outputHelper;\n\n        public TestLogger(ITestOutputHelper outputHelper, string categoryName)\n        {\n            _outputHelper = outputHelper;\n            CategoryName = categoryName;\n        }\n\n        public string CategoryName { get; }\n\n        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)\n        {\n            _outputHelper.WriteLine($\"[{logLevel}] {formatter.Invoke(state, exception)}\");\n        }\n\n        public bool IsEnabled(LogLevel logLevel)\n        {\n            return true;\n        }\n\n        public IDisposable BeginScope<TState>(TState state)\n        {\n            return new DisposableAction(state);\n        }\n\n        private class DisposableAction : IDisposable\n        {\n            private readonly object _state;\n\n            public DisposableAction(object state)\n            {\n                _state = state;\n            }\n\n            public void Dispose()\n            {\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/Helpers/TestLoggingExtensions.cs",
    "content": "﻿using Microsoft.Extensions.Logging;\nusing Xunit.Abstractions;\n\nnamespace DotNetCore.CAP.Test.Helpers\n{\n    public static class TestLoggingExtensions\n    {\n        public static void AddTestLogging(this ILoggingBuilder builder, ITestOutputHelper outputHelper)\n        {\n            builder.AddProvider(new TestLoggingProvider(outputHelper));\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/Helpers/TestLoggingProvider.cs",
    "content": "﻿using Microsoft.Extensions.Logging;\nusing Xunit.Abstractions;\n\nnamespace DotNetCore.CAP.Test.Helpers\n{\n    public class TestLoggingProvider : ILoggerProvider\n    {\n        private readonly ITestOutputHelper _outputHelper;\n\n        public TestLoggingProvider(ITestOutputHelper outputHelper)\n        {\n            _outputHelper = outputHelper;\n        }\n\n        public void Dispose()\n        {\n        }\n\n        public ILogger CreateLogger(string categoryName)\n        {\n            return new TestLogger(_outputHelper, categoryName);\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/Helpers/TestMessageCollector.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace DotNetCore.CAP.Test.Helpers\n{\n    public class TestMessageCollector\n    {\n        private readonly ICollection<object> _handledMessages;\n\n        public TestMessageCollector(ICollection<object> handledMessages)\n        {\n            _handledMessages = handledMessages;\n        }\n\n        public void Add(object data)\n        {\n            _handledMessages.Add(data);\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/Helpers/TestServiceCollectionExtensions.cs",
    "content": "﻿using System.Threading;\nusing DotNetCore.CAP.Test.FakeInMemoryQueue;\nusing Microsoft.Extensions.DependencyInjection;\nusing Xunit.Abstractions;\n\nnamespace DotNetCore.CAP.Test.Helpers\n{\n    public static class TestServiceCollectionExtensions\n    {\n        public const string TestGroupName = \"Test\";\n\n        public static void AddTestSetup(this IServiceCollection services, ITestOutputHelper testOutput)\n        {\n            services.AddLogging(x => x.AddTestLogging(testOutput));\n            services.AddCap(x =>\n            {\n                x.DefaultGroupName = TestGroupName;\n                x.UseFakeTransport();\n                x.UseInMemoryStorage();\n            });\n        }\n\n        public static ServiceProvider BuildTestContainer(this IServiceCollection services, CancellationToken cancellationToken)\n        {\n            var container = services.BuildServiceProvider();\n            container.GetRequiredService<IBootstrapper>().BootstrapAsync(cancellationToken).Wait();\n            return container;\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/Helpers/TestThreadSafeMessageSender.cs",
    "content": "﻿using System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Persistence;\n\nnamespace DotNetCore.CAP.Test.Helpers;\n\npublic class TestThreadSafeMessageSender : IMessageSender\n{\n    private readonly ConcurrentQueue<MediumMessage> _messagesInOrder = [];\n\n    public Task<OperateResult> SendAsync(MediumMessage message)\n    {\n        lock (_messagesInOrder)\n        {\n            _messagesInOrder.Enqueue(message);\n        }\n        return Task.FromResult(OperateResult.Success);\n    }\n\n    public int Count => _messagesInOrder.Count;\n    public List<MediumMessage> ReceivedMessages => _messagesInOrder.ToList();\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/IntegrationTests/CancellationTokenSubscriberTest.cs",
    "content": "﻿using System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Test.Helpers;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace DotNetCore.CAP.Test.IntegrationTests\n{\n    public class CancellationTokenSubscriberTest : IntegrationTestBase\n    {\n        public CancellationTokenSubscriberTest(ITestOutputHelper testOutput)\n            : base(testOutput)\n        {\n        }\n\n        [Fact]\n        public async Task Execute()\n        {\n            await Publisher.PublishAsync(nameof(CancellationTokenSubscriberTest), \"Test Message\");\n            await HandledMessages.WaitOneMessage(CancellationToken);\n\n            // Explicitly stop Bootstrapper to prove the cancellation token works.\n            var bootstrapper = Container.GetRequiredService<IBootstrapper>();\n       \n            await bootstrapper.DisposeAsync();\n\n            var (message, token) = HandledMessages\n                .OfType<(string Message, CancellationToken Token)>()\n                .Single();\n\n            Assert.Equal(\"Test Message\", message);\n            Assert.True(token.IsCancellationRequested);\n        }\n\n        protected override void ConfigureServices(IServiceCollection services)\n        {\n            services.AddTransient<TestEventSubscriber>();\n        }\n\n        private class TestEventSubscriber : ICapSubscribe\n        {\n            private readonly TestMessageCollector _collector;\n            private readonly ILogger<TestEventSubscriber> _logger;\n\n            public TestEventSubscriber(ILogger<TestEventSubscriber> logger, TestMessageCollector collector)\n            {\n                _logger = logger;\n                _collector = collector;\n            }\n\n            [CapSubscribe(nameof(CancellationTokenSubscriberTest),\n                Group = TestServiceCollectionExtensions.TestGroupName)]\n            public void Handle(string message, CancellationToken cancellationToken)\n            {\n                _logger.LogWarning($\"{nameof(Handle)} method called. {message}\");\n                _collector.Add((message, cancellationToken));\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/IntegrationTests/IntegrationTestBase.cs",
    "content": "﻿using System;\nusing System.Collections.ObjectModel;\nusing System.Threading;\nusing DotNetCore.CAP.Test.Helpers;\nusing Microsoft.Extensions.DependencyInjection;\nusing Xunit.Abstractions;\n\nnamespace DotNetCore.CAP.Test.IntegrationTests\n{\n    public abstract class IntegrationTestBase : IDisposable\n    {\n        protected readonly CancellationTokenSource CancellationTokenSource = new(TimeSpan.FromSeconds(10));\n        protected readonly ServiceProvider Container;\n        protected readonly ObservableCollection<object> HandledMessages = new();\n        protected readonly ICapPublisher Publisher;\n\n        protected IntegrationTestBase(ITestOutputHelper testOutput)\n        {\n            var services = new ServiceCollection();\n            services.AddTestSetup(testOutput);\n            services.AddSingleton(new CapMessageQueueMakerService(\"Broker\"));\n            services.AddSingleton(new CapStorageMarkerService(\"Storage\"));\n            services.AddSingleton(sp => new TestMessageCollector(HandledMessages));\n\n            ConfigureServices(services);\n\n            Container = services.BuildTestContainer(CancellationToken);\n            Scope = Container.CreateScope();\n            Publisher = Scope.ServiceProvider.GetRequiredService<ICapPublisher>();\n        }\n\n        protected IServiceScope Scope { get; }\n\n        protected CancellationToken CancellationToken => CancellationTokenSource.Token;\n\n        public void Dispose()\n        {\n            Scope?.Dispose();\n            Container?.Dispose();\n        }\n\n        protected abstract void ConfigureServices(IServiceCollection services);\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/MessageExtensionTest.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing DotNetCore.CAP.Messages;\nusing Xunit;\n\nnamespace DotNetCore.CAP.Test\n{\n    public class MessageExtensionTest\n    {\n        [Fact]\n        public void GetIdTest()\n        {\n            var msgId = Guid.NewGuid().ToString();\n            var header = new Dictionary<string, string>()\n            {\n                [Headers.MessageId] = msgId\n            };\n            var message = new Message(header, null);\n            \n            Assert.NotNull(message.GetId());\n            Assert.Equal(msgId,message.GetId());\n        }\n\n        [Fact]\n        public void GetNameTest()\n        {\n            var msgName = Guid.NewGuid().ToString();\n            var header = new Dictionary<string, string>()\n            {\n                [Headers.MessageName] = msgName\n            };\n            var message = new Message(header, null);\n\n            Assert.NotNull(message.GetName());\n            Assert.Equal(msgName, message.GetName());\n        }\n\n        [Fact]\n        public void GetCallbackNameTest()\n        {\n            var callbackName = Guid.NewGuid().ToString();\n            var header = new Dictionary<string, string>()\n            {\n                [Headers.CallbackName] = callbackName\n            };\n            var message = new Message(header, null);\n\n            Assert.NotNull(message.GetCallbackName());\n            Assert.Equal(callbackName, message.GetCallbackName());\n        }\n\n        [Fact]\n        public void GetGroupTest()\n        {\n            var group = Guid.NewGuid().ToString();\n            var header = new Dictionary<string, string>()\n            {\n                [Headers.Group] = group\n            };\n            var message = new Message(header, null);\n\n            Assert.NotNull(message.GetGroup());\n            Assert.Equal(group, message.GetGroup());\n        }\n\n        [Fact]\n        public void GetCorrelationSequenceTest()\n        {\n            var seq = 1;\n            var header = new Dictionary<string, string>()\n            {\n                [Headers.CorrelationSequence] = seq.ToString()\n            };\n            var message = new Message(header, null);\n\n            Assert.Equal(seq, message.GetCorrelationSequence());\n        }\n\n        [Fact]\n        public void HasExceptionTest()\n        {\n            var exception = \"exception message\";\n            var header = new Dictionary<string, string>()\n            {\n                [Headers.Exception] = exception\n            };\n            var message = new Message(header, null);\n\n            Assert.True(message.HasException());\n        }\n    }\n}\n"
  },
  {
    "path": "test/DotNetCore.CAP.Test/MessageTest.cs",
    "content": "using System;\r\nusing System.Collections.Generic;\r\nusing DotNetCore.CAP.Messages;\r\nusing DotNetCore.CAP.Serialization;\r\nusing Microsoft.Extensions.DependencyInjection;\r\nusing Xunit;\r\n\r\nnamespace DotNetCore.CAP.Test\r\n{\r\n    public class MessageTest\r\n    {\r\n        private readonly IServiceProvider _provider;\r\n\r\n        public MessageTest()\r\n        {\r\n            var services = new ServiceCollection();\r\n\r\n            services.AddOptions();\r\n            services.AddSingleton<IServiceCollection>(_ => services);\r\n            services.AddSingleton<ISerializer, JsonUtf8Serializer>();\r\n            _provider = services.BuildServiceProvider();\r\n        }\r\n\r\n        [Fact]\r\n        public void Serialize_then_Deserialize_Message_With_Utf8JsonSerializer()\r\n        {\r\n            // Given  \r\n            var givenMessage = new Message(\r\n                headers: new Dictionary<string, string>() {\r\n                    { \"cap-msg-name\", \"authentication.users.update\"},\r\n                    { \"cap-msg-type\", \"User\" },\r\n                    { \"cap-corr-seq\", \"0\"},\r\n                    { \"cap-msg-group\",\"service.v1\"}\r\n                },\r\n                value: new MessageValue(\"test@test.com\", \"User\"));\r\n\r\n            // When\r\n            var serializer = _provider.GetRequiredService<ISerializer>();\r\n            var json = serializer.Serialize(givenMessage);\r\n            var deserializedMessage = serializer.Deserialize(json);\r\n\r\n            // Then\r\n            Assert.True(serializer.IsJsonType(deserializedMessage.Value));\r\n            \r\n            var result = serializer.Deserialize(deserializedMessage.Value, typeof(MessageValue)) as MessageValue;\r\n            Assert.NotNull(result);\r\n            Assert.Equal(result.Email, ((MessageValue)givenMessage.Value).Email);\r\n            Assert.Equal(result.Name, ((MessageValue)givenMessage.Value).Name);\r\n        }\r\n    }\r\n\r\n    public class MessageValue\r\n    {\r\n        public MessageValue(string email, string name)\r\n        {\r\n            Email = email;\r\n            Name = name;\r\n        }\r\n\r\n        public string Email { get; }\r\n        public string Name { get; }\r\n    }\r\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/SnowflakeIdTest.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing Xunit;\n\nnamespace DotNetCore.CAP.Test\n{\n    public class SnowflakeIdTest\n    {\n        ISnowflakeId _snowflakeId;\n\n        public SnowflakeIdTest()\n        {\n            _snowflakeId = new SnowflakeId(Util.GenerateWorkerId(1023));\n        }\n\n        [Fact]\n        public void NextIdTest()\n        {\n            var instance = _snowflakeId;\n            var result = instance.NextId();\n            var result2 = instance.NextId();\n\n            Assert.True(result2 - result == 1);\n        }\n\n        [Fact]\n        public void ConcurrentNextIdTest()\n        {\n            var array = new long[1000];\n\n            Parallel.For(0, 1000, i =>\n            {\n                var id = _snowflakeId.NextId();\n                array[i] = id;\n            });\n\n            Assert.True(array.Distinct().Count() == 1000);\n        }\n\n        [Fact]\n        public void TestNegativeWorkerId()\n        {\n            Assert.Throws<ArgumentException>(() => new SnowflakeId(-1));\n        }\n\n        [Fact]\n        public void TestTooLargeWorkerId()\n        {\n            Assert.Throws<ArgumentException>(() => new SnowflakeId(1024));\n        }\n    }\n}\n"
  },
  {
    "path": "test/DotNetCore.CAP.Test/SubscribeInvokerTest.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Serialization;\nusing Microsoft.Extensions.DependencyInjection;\nusing Xunit;\n\nnamespace DotNetCore.CAP.Test\n{\n    public class SubscribeInvokerTest\n    {\n        private readonly IServiceProvider _serviceProvider;\n\n        public SubscribeInvokerTest()\n        {\n            var serviceCollection = new ServiceCollection();\n            serviceCollection.AddLogging();\n            serviceCollection.AddSingleton<ISerializer, JsonUtf8Serializer>();\n            serviceCollection.AddSingleton<ISubscribeInvoker, SubscribeInvoker>();\n            serviceCollection.AddSingleton<ISnowflakeId>(r => new SnowflakeId(Util.GenerateWorkerId(1023)));\n            _serviceProvider = serviceCollection.BuildServiceProvider();\n        }\n\n        private ISubscribeInvoker SubscribeInvoker => _serviceProvider.GetService<ISubscribeInvoker>();\n\n        [Fact]\n        public async Task InvokeTest()\n        {\n            var snowflakeId = _serviceProvider.GetRequiredService<ISnowflakeId>();\n            var descriptor = new ConsumerExecutorDescriptor()\n            {\n                Attribute = new CandidatesTopic(\"fake.output.integer\"),\n                ServiceTypeInfo = typeof(FakeSubscriber).GetTypeInfo(),\n                ImplTypeInfo = typeof(FakeSubscriber).GetTypeInfo(),\n                MethodInfo = typeof(FakeSubscriber).GetMethod(nameof(FakeSubscriber.OutputIntegerSub)),\n                Parameters = new List<ParameterDescriptor>()\n            };\n\n            var header = new Dictionary<string, string>()\n            {\n                [Headers.MessageId] = snowflakeId.NextId().ToString(),\n                [Headers.MessageName] = \"fake.output.integer\"\n            };\n            var message = new Message(header, null);\n            var mediumMessage = new MediumMessage() { Origin = message };\n            var context = new ConsumerContext(descriptor, mediumMessage);\n\n            var ret = await SubscribeInvoker.InvokeAsync(context);\n            Assert.Equal(int.MaxValue, ret.Result);\n        }\n    }\n\n    public class FakeSubscriber : ICapSubscribe\n    {\n        [CapSubscribe(\"fake.output.integer\")]\n        public int OutputIntegerSub()\n        {\n            return int.MaxValue;\n        }\n    }\n}\n"
  },
  {
    "path": "test/DotNetCore.CAP.Test/SubscribeInvokerWithCancellation.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing DotNetCore.CAP.Internal;\nusing DotNetCore.CAP.Messages;\nusing DotNetCore.CAP.Persistence;\nusing DotNetCore.CAP.Serialization;\nusing Microsoft.Extensions.DependencyInjection;\nusing Xunit;\n\nnamespace DotNetCore.CAP.Test\n{\n    public class SubscribeInvokerWithCancellation\n    {\n        private readonly IServiceProvider _serviceProvider;\n\n        public SubscribeInvokerWithCancellation()\n        {\n            var serviceCollection = new ServiceCollection();\n            serviceCollection.AddLogging();\n            serviceCollection.AddSingleton<IBootstrapper, Bootstrapper>();\n            serviceCollection.AddSingleton<ISerializer, JsonUtf8Serializer>();\n            serviceCollection.AddSingleton<ISubscribeInvoker, SubscribeInvoker>();\n            serviceCollection.AddSingleton<ISnowflakeId>(r => new SnowflakeId(Util.GenerateWorkerId(1023)));\n            _serviceProvider = serviceCollection.BuildServiceProvider();\n        }\n\n        private ISubscribeInvoker SubscribeInvoker => _serviceProvider.GetService<ISubscribeInvoker>();\n\n        [Fact]\n        public async Task InvokeTest()\n        {\n            var snowflakeId = _serviceProvider.GetRequiredService<ISnowflakeId>();\n            var descriptor = new ConsumerExecutorDescriptor()\n            {\n                Attribute = new CandidatesTopic(\"fake.output.withcancellation\"),\n                ServiceTypeInfo = typeof(FakeSubscriberWithCancellation).GetTypeInfo(),\n                ImplTypeInfo = typeof(FakeSubscriberWithCancellation).GetTypeInfo(),\n                MethodInfo = typeof(FakeSubscriberWithCancellation)\n                    .GetMethod(nameof(FakeSubscriberWithCancellation.CancellationTokenInjected)),\n                Parameters = new List<ParameterDescriptor>\n                {\n                    new ParameterDescriptor {\n                        ParameterType = typeof(CancellationToken),\n                        IsFromCap = true,\n                        Name = \"cancellationToken\"\n                    }\n                }\n            };\n\n            var header = new Dictionary<string, string>()\n            {\n                [Headers.MessageId] = snowflakeId.NextId().ToString(),\n                [Headers.MessageName] = \"fake.output.withcancellation\"\n            };\n            var message = new Message(header, null);\n            var mediumMessage = new MediumMessage() { Origin = message };\n            var context = new ConsumerContext(descriptor, mediumMessage);\n\n            var cancellationToken = new CancellationToken();\n            var ret = await SubscribeInvoker.InvokeAsync(context, cancellationToken);\n            Assert.Equal(cancellationToken, ret.Result);\n        }\n    }\n\n    public class FakeSubscriberWithCancellation : ICapSubscribe\n    {\n        [CapSubscribe(\"fake.output.withcancellation\")]\n        public CancellationToken CancellationTokenInjected(CancellationToken cancellationToken)\n        {\n            return cancellationToken;\n        }\n    }\n}\n"
  },
  {
    "path": "test/DotNetCore.CAP.Test/SubscriberCollisionTests/NewMethodTests.cs",
    "content": "﻿using Xunit;\nusing ExternalModuleSubscriberClass = DotNetCore.CAP.MultiModuleSubscriberTests.SubscriberClass;\n\nnamespace DotNetCore.CAP.Test.SubscriberCollisionTests\n{\n    public class NewMethodTests\n    {\n        [Fact]\n        public void NoCollision_SameClassAndMethod_DifferentAssemblies()\n        {\n            var methodInfo = typeof(SubscriberClass).GetMethod(nameof(SubscriberClass.TestSubscriber));\n            var externalMethodInfo = typeof(ExternalModuleSubscriberClass).GetMethod(nameof(ExternalModuleSubscriberClass.TestSubscriber));\n\n            Assert.NotEqual(methodInfo.MethodHandle, externalMethodInfo.MethodHandle);\n        }\n\n        [Fact]\n        public void Collision_Subclass_SameAssembly_MethodHandleOnly()\n        {\n            var methodInfo1 = typeof(Subclass1OfSubscriberClass).GetMethod(nameof(SubscriberClass.TestSubscriber));\n            var methodInfo2 = typeof(Subclass2OfSubscriberClass).GetMethod(nameof(SubscriberClass.TestSubscriber));\n\n            Assert.Equal(methodInfo1.MethodHandle.Value,\n                methodInfo2.MethodHandle.Value);\n        }\n\n        [Fact]\n        public void NoCollision_Subclass_SameAssembly_TypeAndMethodHandle()\n        {\n            var methodInfo1 = typeof(Subclass1OfSubscriberClass).GetMethod(nameof(SubscriberClass.TestSubscriber));\n            var methodInfo2 = typeof(Subclass2OfSubscriberClass).GetMethod(nameof(SubscriberClass.TestSubscriber));\n\n            Assert.NotEqual($\"{methodInfo1.MethodHandle.Value}_{methodInfo1.ReflectedType.TypeHandle.Value}\",\n                $\"{methodInfo2.MethodHandle.Value}_{methodInfo2.ReflectedType.TypeHandle.Value}\");\n        }\n\n        [Fact]\n        public void NoCollision_SubclassOfGenericOpenType_SameAssembly_Handle()\n        {\n            var methodInfo1 = typeof(BaseClass<>)\n                .MakeGenericType(typeof(MessageType1))\n                .GetMethod(nameof(BaseClass<object>.Handle));\n            var methodInfo2 = typeof(BaseClass<>)\n                .MakeGenericType(typeof(MessageType2))\n                .GetMethod(nameof(BaseClass<object>.Handle));\n\n            Assert.NotEqual($\"{methodInfo1.MethodHandle.Value}_{methodInfo1.ReflectedType.TypeHandle.Value}\",\n                $\"{methodInfo2.MethodHandle.Value}_{methodInfo2.ReflectedType.TypeHandle.Value}\");\n        }\n\n        private class Subclass1OfSubscriberClass : SubscriberClass { }\n        private class Subclass2OfSubscriberClass : SubscriberClass { }\n\n        private class MessageType1 { }\n        private class MessageType2 { }\n        private abstract class BaseClass<T>\n        {\n            public void Handle()\n            {\n            }\n        }\n\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/SubscriberCollisionTests/OldMethodTests.cs",
    "content": "﻿using Xunit;\nusing ExternalModuleSubscriberClass = DotNetCore.CAP.MultiModuleSubscriberTests.SubscriberClass;\n\nnamespace DotNetCore.CAP.Test.SubscriberCollisionTests\n{\n    public class OldMethodTests\n    {\n            [Fact]\n            public void NoCollision_SameClassAndMethod_DifferentAssemblies()\n            {\n                var methodInfo = typeof(SubscriberClass).GetMethod(nameof(SubscriberClass.TestSubscriber));\n                var externalMethodInfo = typeof(ExternalModuleSubscriberClass).GetMethod(nameof(ExternalModuleSubscriberClass.TestSubscriber));\n\n                var reflectedType = methodInfo.ReflectedType.Name;\n                var key = $\"{methodInfo.Module.Name}_{reflectedType}_{methodInfo.MetadataToken}\";\n                var externalReflectedType = methodInfo.ReflectedType.Name;\n                var externalKey = $\"{externalMethodInfo.Module.Name}_{externalReflectedType}_{externalMethodInfo.MetadataToken}\";\n\n                Assert.NotEqual(key, externalKey);\n            }\n\n            [Fact]\n            public void NoCollision_Subclasses_SameAssembly()\n            {\n                var methodInfo1 = typeof(Subclass1OfSubscriberClass).GetMethod(nameof(SubscriberClass.TestSubscriber));\n                var methodInfo2 = typeof(Subclass2OfSubscriberClass).GetMethod(nameof(SubscriberClass.TestSubscriber));\n\n                var reflectedType = methodInfo1.ReflectedType.Name;\n                var key = $\"{methodInfo1.Module.Name}_{reflectedType}_{methodInfo1.MetadataToken}\";\n                var externalReflectedType = methodInfo2.ReflectedType.Name;\n                var externalKey = $\"{methodInfo2.Module.Name}_{externalReflectedType}_{methodInfo2.MetadataToken}\";\n\n                Assert.NotEqual(key, externalKey);\n            }\n\n            [Fact]\n            public void Collision_SubclassOfGenericOpenType_SameAssembly_Handle()\n            {\n                var method1 = typeof(BaseClass<>)\n                    .MakeGenericType(typeof(MessageType1))\n                    .GetMethod(nameof(BaseClass<object>.Handle));\n                var method2 = typeof(BaseClass<>)\n                    .MakeGenericType(typeof(MessageType2))\n                    .GetMethod(nameof(BaseClass<object>.Handle));\n\n                Assert.Equal(method1.MetadataToken, method2.MetadataToken);\n            }\n\n            private class Subclass1OfSubscriberClass : SubscriberClass {}\n            private class Subclass2OfSubscriberClass : SubscriberClass {}\n            \n            private class MessageType1 { }\n            private class MessageType2 { }\n            private abstract class BaseClass<T>\n            {\n                public void Handle()\n                {\n                }\n            }\n    }\n}"
  },
  {
    "path": "test/DotNetCore.CAP.Test/SubscriberCollisionTests/SubscriberClass.cs",
    "content": "﻿namespace DotNetCore.CAP.Test.SubscriberCollisionTests\n{\n    public class SubscriberClass\n    {\n        public void TestSubscriber()\n        {\n        }\n    }\n}"
  }
]