From d7812aabba768b6bd52a5bd91fe0b3c64f01d469 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Sun, 21 Dec 2025 04:24:25 +0200 Subject: [PATCH 01/27] - Split dispatch prepper into partial class - Updated Workflow - Updated Documentation --- .github/workflows/deploy.yml | 20 +- README.md | 35 +-- doc/{statepulse-doc => }/.gitignore | 0 doc/{statepulse-doc => }/README.md | 0 .../blog/2025-07-11Test.md | 0 doc/{statepulse-doc => }/blog/authors.yml | 0 doc/{statepulse-doc => }/blog/tags.yml | 0 doc/{statepulse-doc => }/build/.nojekyll | 0 doc/{statepulse-doc => }/build/404.html | 4 +- .../build/assets/css/styles.e8d85d9e.css | 0 .../build/assets/js/01a85c17.862c65d0.js | 0 .../build/assets/js/02105171.5d7951a6.js | 0 .../build/assets/js/0bc25be7.282e267f.js | 0 .../build/assets/js/0d8668ed.85a2571d.js | 0 .../build/assets/js/0e30184d.2549f073.js | 0 .../build/assets/js/17896441.145b706a.js | 0 .../build/assets/js/1f391b9e.47fc6bcb.js | 0 .../build/assets/js/2237.2847df75.js | 0 .../assets/js/22dd74f7.01add2a9.js} | 2 +- .../build/assets/js/2e6f86e1.0b70acfd.js | 0 .../build/assets/js/3217192f.839e2666.js | 0 .../build/assets/js/33fc5bb8.71cc9278.js | 0 .../build/assets/js/36994c47.39393642.js | 0 .../build/assets/js/3720c009.ccae4646.js | 0 .../build/assets/js/393be207.2823742b.js | 0 .../build/assets/js/3a2db09e.282370d5.js | 0 .../build/assets/js/4ebf985a.a97ef297.js | 0 .../build/assets/js/547f2087.d07a2638.js | 0 .../build/assets/js/59af61a6.9f2d00f9.js | 0 .../build/assets/js/5e90a9b3.e7712624.js | 0 .../build/assets/js/5e95c892.9334a2c8.js | 0 .../build/assets/js/6120.b521cc9a.js | 0 .../build/assets/js/621db11d.8a8315d5.js | 0 .../build/assets/js/6875c492.4b51a67c.js | 0 .../build/assets/js/68ee3bbe.20abb41a.js | 0 .../build/assets/js/6932.bfc2f6fe.js | 0 .../build/assets/js/7048d6c3.094da11e.js | 0 .../build/assets/js/742328d7.5ff212f5.js | 0 .../build/assets/js/7691d1c3.1689ceb1.js | 0 .../build/assets/js/79199b91.2c32870b.js | 0 .../build/assets/js/7954e82b.358816fa.js | 0 .../build/assets/js/814f3328.7ec3573c.js | 0 .../build/assets/js/8c3a5864.4dc1b980.js | 0 .../build/assets/js/8edd9378.74846925.js | 0 .../build/assets/js/90c0aa62.5eb5689f.js | 0 .../build/assets/js/936b9f1e.dfeb0090.js | 0 doc/build/assets/js/94cf9043.2507e390.js | 1 + .../build/assets/js/9cc31a46.968cd617.js | 0 .../build/assets/js/9e4087bc.7497232a.js | 0 .../build/assets/js/a6aa9e1f.613b3683.js | 0 .../build/assets/js/a7456010.336f95fe.js | 0 .../build/assets/js/a7bd4aaa.f2d2fe61.js | 0 .../build/assets/js/a94703ab.abc249b9.js | 0 .../build/assets/js/aba21aa0.5a986477.js | 0 .../build/assets/js/acecf23e.b595c8e0.js | 0 .../build/assets/js/c15d9823.c717e7e9.js | 0 .../build/assets/js/c5fd082d.0836ff42.js | 0 .../build/assets/js/c92171c2.a59a22be.js | 0 .../build/assets/js/c9c672c1.39aedffb.js | 0 .../build/assets/js/cc87a84e.b58788db.js | 0 .../build/assets/js/ccc49370.24b047ad.js | 0 .../build/assets/js/cd69296b.c353b6fa.js | 0 .../build/assets/js/d5b5cc03.04954f93.js | 0 .../build/assets/js/dbf990ff.f9a1d8e6.js | 0 .../build/assets/js/df203c0f.c82ea539.js | 0 .../build/assets/js/e48d0160.acea7c7a.js | 0 .../assets/js/e4b9287f.17e09519.js} | 2 +- .../build/assets/js/e925e243.eaa2c69c.js | 0 .../build/assets/js/ef8b811a.724d7ea4.js | 0 doc/build/assets/js/f179eaed.fef2718c.js | 1 + .../build/assets/js/f2ace840.16526adf.js | 0 .../build/assets/js/f552f37d.15137b77.js | 0 .../build/assets/js/f6f0caca.6f80119e.js | 0 .../build/assets/js/f81c1134.801b7b65.js | 0 .../build/assets/js/febfe999.614202d2.js | 0 .../assets/js/main.1e4c436b.js} | 4 +- .../assets/js/main.1e4c436b.js.LICENSE.txt} | 0 .../assets/js/runtime~main.c3a751da.js} | 2 +- .../build/blog/archive/index.html | 4 +- doc/{statepulse-doc => }/build/blog/atom.css | 0 doc/{statepulse-doc => }/build/blog/atom.xml | 0 doc/{statepulse-doc => }/build/blog/atom.xsl | 0 .../build/blog/authors/index.html | 4 +- .../build/blog/authors/mshimshon/index.html | 4 +- .../build/blog/first-blog-post/index.html | 4 +- .../build/blog/index.html | 4 +- doc/{statepulse-doc => }/build/blog/rss.css | 0 doc/{statepulse-doc => }/build/blog/rss.xml | 0 doc/{statepulse-doc => }/build/blog/rss.xsl | 0 .../build/blog/tags/docusaurus/index.html | 4 +- .../build/blog/tags/hola/index.html | 4 +- .../build/blog/tags/index.html | 4 +- .../build/gs-state/index.html | 4 +- .../build/gs-the-action/index.html | 4 +- .../build/gs-the-dispatcher/index.html | 4 +- .../build/gs-the-effect/index.html | 4 +- .../build/gs-the-middlewares/index.html | 6 +- .../build/gs-the-reducer/index.html | 4 +- .../build/img/docusaurus-social-card.jpg | Bin .../build/img/docusaurus.png | Bin .../build/img/favicon.ico | Bin doc/{statepulse-doc => }/build/img/icon.png | Bin doc/{statepulse-doc => }/build/img/logo.svg | 0 .../build/img/nuget-logo.png | Bin .../build/img/undraw_docusaurus_mountain.svg | 0 .../build/img/undraw_docusaurus_react.svg | 0 .../build/img/undraw_docusaurus_tree.svg | 0 doc/{statepulse-doc => }/build/index.html | 6 +- .../build/markdown-page/index.html | 4 +- .../build/setup-blazor-project/index.html | 4 +- doc/{statepulse-doc => }/build/sitemap.xml | 0 .../build/tags/actions/index.html | 4 +- .../build/tags/async/index.html | 4 +- .../build/tags/await/index.html | 4 +- .../build/tags/blazor/index.html | 4 +- .../build/tags/csharp/index.html | 4 +- .../tags/dependency-injection/index.html | 4 +- .../build/tags/dispatcher/index.html | 4 +- .../build/tags/effects/index.html | 4 +- .../build/tags/immutable/index.html | 4 +- .../build/tags/index.html | 4 +- .../build/tags/installation/index.html | 4 +- .../build/tags/isafeaction/index.html | 4 +- .../build/tags/net/index.html | 4 +- .../build/tags/performance/index.html | 4 +- .../build/tags/pure-functions/index.html | 4 +- .../build/tags/reducer/index.html | 4 +- .../build/tags/redux/index.html | 4 +- .../build/tags/safedispatch/index.html | 4 +- .../build/tags/setup/index.html | 4 +- .../build/tags/side-effects/index.html | 4 +- .../build/tags/state-management/index.html | 4 +- .../build/tags/state/index.html | 4 +- .../build/tags/statepulse/index.html | 4 +- .../build/versions/index.html | 43 +++- doc/{statepulse-doc => }/docs/0.Versions.md | 22 ++ .../docs/1. Setup Blazor Project.md | 0 .../docs/2. Creating Actions.md | 0 .../docs/3.Create State.md | 0 .../docs/4 Create Effects.md | 0 .../docs/5.Create Reducer.md | 0 .../docs/6.Inject Dispatcher.md | 0 .../Middlewares.md => docs/7.Middlewares.md} | 0 .../docs/Getting Started.md | 2 +- doc/{statepulse-doc => }/docusaurus.config.ts | 0 doc/{statepulse-doc => }/package-lock.json | 0 doc/{statepulse-doc => }/package.json | 0 doc/{statepulse-doc => }/sidebars.ts | 0 doc/{statepulse-doc => }/src/css/custom.css | 0 .../src/pages/markdown-page.md | 0 .../build/assets/js/6638fef1.00b4e006.js | 1 - .../build/assets/js/94cf9043.d09cd2bd.js | 1 - doc/{statepulse-doc => }/static/.nojekyll | 0 .../static/img/docusaurus-social-card.jpg | Bin .../static/img/docusaurus.png | Bin .../static/img/favicon.ico | Bin doc/{statepulse-doc => }/static/img/icon.png | Bin doc/{statepulse-doc => }/static/img/logo.svg | 0 .../static/img/nuget-logo.png | Bin .../static/img/undraw_docusaurus_mountain.svg | 0 .../static/img/undraw_docusaurus_react.svg | 0 .../static/img/undraw_docusaurus_tree.svg | 0 doc/{statepulse-doc => }/tsconfig.json | 0 src/StatePulse.NET.sln | 5 +- .../Configuration/ConfigureOptions.cs | 19 +- .../DispatchEffectExecutionBehavior.cs | 19 ++ .../Configuration/DispatchOrdering.cs | 19 ++ .../InvalidDispatchCombinationException.cs | 14 ++ .../Implementations/DispatcherPrepper.cs | 75 +++++-- .../DispatcherPrepper_Flags.cs | 88 ++++++++ src/StatePulse.NET/IDispatchPrepperExt.cs | 1 + src/StatePulse.NET/README.md | 201 ------------------ src/StatePulse.NET/ServiceRegisterExt.cs | 22 +- src/StatePulse.NET/StatePulse.NET.csproj | 24 +-- .../IDispatcherPrepper.cs | 6 + .../StatePulse.Net.Abstractions.csproj | 9 +- tests/StatPulse.NET.Tests/TestBase.cs | 54 ++--- .../InitializerTests/StatePulseInitTests.cs | 2 +- .../ProfileCardDefineActionValidator.cs | 4 + 179 files changed, 460 insertions(+), 406 deletions(-) rename doc/{statepulse-doc => }/.gitignore (100%) rename doc/{statepulse-doc => }/README.md (100%) rename doc/{statepulse-doc => }/blog/2025-07-11Test.md (100%) rename doc/{statepulse-doc => }/blog/authors.yml (100%) rename doc/{statepulse-doc => }/blog/tags.yml (100%) rename doc/{statepulse-doc => }/build/.nojekyll (100%) rename doc/{statepulse-doc => }/build/404.html (98%) rename doc/{statepulse-doc => }/build/assets/css/styles.e8d85d9e.css (100%) rename doc/{statepulse-doc => }/build/assets/js/01a85c17.862c65d0.js (100%) rename doc/{statepulse-doc => }/build/assets/js/02105171.5d7951a6.js (100%) rename doc/{statepulse-doc => }/build/assets/js/0bc25be7.282e267f.js (100%) rename doc/{statepulse-doc => }/build/assets/js/0d8668ed.85a2571d.js (100%) rename doc/{statepulse-doc => }/build/assets/js/0e30184d.2549f073.js (100%) rename doc/{statepulse-doc => }/build/assets/js/17896441.145b706a.js (100%) rename doc/{statepulse-doc => }/build/assets/js/1f391b9e.47fc6bcb.js (100%) rename doc/{statepulse-doc => }/build/assets/js/2237.2847df75.js (100%) rename doc/{statepulse-doc/build/assets/js/22dd74f7.0636519f.js => build/assets/js/22dd74f7.01add2a9.js} (97%) rename doc/{statepulse-doc => }/build/assets/js/2e6f86e1.0b70acfd.js (100%) rename doc/{statepulse-doc => }/build/assets/js/3217192f.839e2666.js (100%) rename doc/{statepulse-doc => }/build/assets/js/33fc5bb8.71cc9278.js (100%) rename doc/{statepulse-doc => }/build/assets/js/36994c47.39393642.js (100%) rename doc/{statepulse-doc => }/build/assets/js/3720c009.ccae4646.js (100%) rename doc/{statepulse-doc => }/build/assets/js/393be207.2823742b.js (100%) rename doc/{statepulse-doc => }/build/assets/js/3a2db09e.282370d5.js (100%) rename doc/{statepulse-doc => }/build/assets/js/4ebf985a.a97ef297.js (100%) rename doc/{statepulse-doc => }/build/assets/js/547f2087.d07a2638.js (100%) rename doc/{statepulse-doc => }/build/assets/js/59af61a6.9f2d00f9.js (100%) rename doc/{statepulse-doc => }/build/assets/js/5e90a9b3.e7712624.js (100%) rename doc/{statepulse-doc => }/build/assets/js/5e95c892.9334a2c8.js (100%) rename doc/{statepulse-doc => }/build/assets/js/6120.b521cc9a.js (100%) rename doc/{statepulse-doc => }/build/assets/js/621db11d.8a8315d5.js (100%) rename doc/{statepulse-doc => }/build/assets/js/6875c492.4b51a67c.js (100%) rename doc/{statepulse-doc => }/build/assets/js/68ee3bbe.20abb41a.js (100%) rename doc/{statepulse-doc => }/build/assets/js/6932.bfc2f6fe.js (100%) rename doc/{statepulse-doc => }/build/assets/js/7048d6c3.094da11e.js (100%) rename doc/{statepulse-doc => }/build/assets/js/742328d7.5ff212f5.js (100%) rename doc/{statepulse-doc => }/build/assets/js/7691d1c3.1689ceb1.js (100%) rename doc/{statepulse-doc => }/build/assets/js/79199b91.2c32870b.js (100%) rename doc/{statepulse-doc => }/build/assets/js/7954e82b.358816fa.js (100%) rename doc/{statepulse-doc => }/build/assets/js/814f3328.7ec3573c.js (100%) rename doc/{statepulse-doc => }/build/assets/js/8c3a5864.4dc1b980.js (100%) rename doc/{statepulse-doc => }/build/assets/js/8edd9378.74846925.js (100%) rename doc/{statepulse-doc => }/build/assets/js/90c0aa62.5eb5689f.js (100%) rename doc/{statepulse-doc => }/build/assets/js/936b9f1e.dfeb0090.js (100%) create mode 100644 doc/build/assets/js/94cf9043.2507e390.js rename doc/{statepulse-doc => }/build/assets/js/9cc31a46.968cd617.js (100%) rename doc/{statepulse-doc => }/build/assets/js/9e4087bc.7497232a.js (100%) rename doc/{statepulse-doc => }/build/assets/js/a6aa9e1f.613b3683.js (100%) rename doc/{statepulse-doc => }/build/assets/js/a7456010.336f95fe.js (100%) rename doc/{statepulse-doc => }/build/assets/js/a7bd4aaa.f2d2fe61.js (100%) rename doc/{statepulse-doc => }/build/assets/js/a94703ab.abc249b9.js (100%) rename doc/{statepulse-doc => }/build/assets/js/aba21aa0.5a986477.js (100%) rename doc/{statepulse-doc => }/build/assets/js/acecf23e.b595c8e0.js (100%) rename doc/{statepulse-doc => }/build/assets/js/c15d9823.c717e7e9.js (100%) rename doc/{statepulse-doc => }/build/assets/js/c5fd082d.0836ff42.js (100%) rename doc/{statepulse-doc => }/build/assets/js/c92171c2.a59a22be.js (100%) rename doc/{statepulse-doc => }/build/assets/js/c9c672c1.39aedffb.js (100%) rename doc/{statepulse-doc => }/build/assets/js/cc87a84e.b58788db.js (100%) rename doc/{statepulse-doc => }/build/assets/js/ccc49370.24b047ad.js (100%) rename doc/{statepulse-doc => }/build/assets/js/cd69296b.c353b6fa.js (100%) rename doc/{statepulse-doc => }/build/assets/js/d5b5cc03.04954f93.js (100%) rename doc/{statepulse-doc => }/build/assets/js/dbf990ff.f9a1d8e6.js (100%) rename doc/{statepulse-doc => }/build/assets/js/df203c0f.c82ea539.js (100%) rename doc/{statepulse-doc => }/build/assets/js/e48d0160.acea7c7a.js (100%) rename doc/{statepulse-doc/build/assets/js/e4b9287f.da013039.js => build/assets/js/e4b9287f.17e09519.js} (99%) rename doc/{statepulse-doc => }/build/assets/js/e925e243.eaa2c69c.js (100%) rename doc/{statepulse-doc => }/build/assets/js/ef8b811a.724d7ea4.js (100%) create mode 100644 doc/build/assets/js/f179eaed.fef2718c.js rename doc/{statepulse-doc => }/build/assets/js/f2ace840.16526adf.js (100%) rename doc/{statepulse-doc => }/build/assets/js/f552f37d.15137b77.js (100%) rename doc/{statepulse-doc => }/build/assets/js/f6f0caca.6f80119e.js (100%) rename doc/{statepulse-doc => }/build/assets/js/f81c1134.801b7b65.js (100%) rename doc/{statepulse-doc => }/build/assets/js/febfe999.614202d2.js (100%) rename doc/{statepulse-doc/build/assets/js/main.16c181e8.js => build/assets/js/main.1e4c436b.js} (98%) rename doc/{statepulse-doc/build/assets/js/main.16c181e8.js.LICENSE.txt => build/assets/js/main.1e4c436b.js.LICENSE.txt} (100%) rename doc/{statepulse-doc/build/assets/js/runtime~main.257bc31b.js => build/assets/js/runtime~main.c3a751da.js} (68%) rename doc/{statepulse-doc => }/build/blog/archive/index.html (98%) rename doc/{statepulse-doc => }/build/blog/atom.css (100%) rename doc/{statepulse-doc => }/build/blog/atom.xml (100%) rename doc/{statepulse-doc => }/build/blog/atom.xsl (100%) rename doc/{statepulse-doc => }/build/blog/authors/index.html (98%) rename doc/{statepulse-doc => }/build/blog/authors/mshimshon/index.html (99%) rename doc/{statepulse-doc => }/build/blog/first-blog-post/index.html (99%) rename doc/{statepulse-doc => }/build/blog/index.html (99%) rename doc/{statepulse-doc => }/build/blog/rss.css (100%) rename doc/{statepulse-doc => }/build/blog/rss.xml (100%) rename doc/{statepulse-doc => }/build/blog/rss.xsl (100%) rename doc/{statepulse-doc => }/build/blog/tags/docusaurus/index.html (99%) rename doc/{statepulse-doc => }/build/blog/tags/hola/index.html (99%) rename doc/{statepulse-doc => }/build/blog/tags/index.html (98%) rename doc/{statepulse-doc => }/build/gs-state/index.html (99%) rename doc/{statepulse-doc => }/build/gs-the-action/index.html (99%) rename doc/{statepulse-doc => }/build/gs-the-dispatcher/index.html (99%) rename doc/{statepulse-doc => }/build/gs-the-effect/index.html (99%) rename doc/{statepulse-doc => }/build/gs-the-middlewares/index.html (92%) rename doc/{statepulse-doc => }/build/gs-the-reducer/index.html (99%) rename doc/{statepulse-doc => }/build/img/docusaurus-social-card.jpg (100%) rename doc/{statepulse-doc => }/build/img/docusaurus.png (100%) rename doc/{statepulse-doc => }/build/img/favicon.ico (100%) rename doc/{statepulse-doc => }/build/img/icon.png (100%) rename doc/{statepulse-doc => }/build/img/logo.svg (100%) rename doc/{statepulse-doc => }/build/img/nuget-logo.png (100%) rename doc/{statepulse-doc => }/build/img/undraw_docusaurus_mountain.svg (100%) rename doc/{statepulse-doc => }/build/img/undraw_docusaurus_react.svg (100%) rename doc/{statepulse-doc => }/build/img/undraw_docusaurus_tree.svg (100%) rename doc/{statepulse-doc => }/build/index.html (99%) rename doc/{statepulse-doc => }/build/markdown-page/index.html (98%) rename doc/{statepulse-doc => }/build/setup-blazor-project/index.html (99%) rename doc/{statepulse-doc => }/build/sitemap.xml (100%) rename doc/{statepulse-doc => }/build/tags/actions/index.html (98%) rename doc/{statepulse-doc => }/build/tags/async/index.html (98%) rename doc/{statepulse-doc => }/build/tags/await/index.html (98%) rename doc/{statepulse-doc => }/build/tags/blazor/index.html (98%) rename doc/{statepulse-doc => }/build/tags/csharp/index.html (98%) rename doc/{statepulse-doc => }/build/tags/dependency-injection/index.html (98%) rename doc/{statepulse-doc => }/build/tags/dispatcher/index.html (98%) rename doc/{statepulse-doc => }/build/tags/effects/index.html (98%) rename doc/{statepulse-doc => }/build/tags/immutable/index.html (98%) rename doc/{statepulse-doc => }/build/tags/index.html (98%) rename doc/{statepulse-doc => }/build/tags/installation/index.html (98%) rename doc/{statepulse-doc => }/build/tags/isafeaction/index.html (98%) rename doc/{statepulse-doc => }/build/tags/net/index.html (98%) rename doc/{statepulse-doc => }/build/tags/performance/index.html (98%) rename doc/{statepulse-doc => }/build/tags/pure-functions/index.html (98%) rename doc/{statepulse-doc => }/build/tags/reducer/index.html (98%) rename doc/{statepulse-doc => }/build/tags/redux/index.html (98%) rename doc/{statepulse-doc => }/build/tags/safedispatch/index.html (98%) rename doc/{statepulse-doc => }/build/tags/setup/index.html (98%) rename doc/{statepulse-doc => }/build/tags/side-effects/index.html (98%) rename doc/{statepulse-doc => }/build/tags/state-management/index.html (98%) rename doc/{statepulse-doc => }/build/tags/state/index.html (98%) rename doc/{statepulse-doc => }/build/tags/statepulse/index.html (98%) rename doc/{statepulse-doc => }/build/versions/index.html (75%) rename doc/{statepulse-doc => }/docs/0.Versions.md (59%) rename doc/{statepulse-doc => }/docs/1. Setup Blazor Project.md (100%) rename doc/{statepulse-doc => }/docs/2. Creating Actions.md (100%) rename doc/{statepulse-doc => }/docs/3.Create State.md (100%) rename doc/{statepulse-doc => }/docs/4 Create Effects.md (100%) rename doc/{statepulse-doc => }/docs/5.Create Reducer.md (100%) rename doc/{statepulse-doc => }/docs/6.Inject Dispatcher.md (100%) rename doc/{statepulse-doc/docs/Middlewares.md => docs/7.Middlewares.md} (100%) rename doc/{statepulse-doc => }/docs/Getting Started.md (99%) rename doc/{statepulse-doc => }/docusaurus.config.ts (100%) rename doc/{statepulse-doc => }/package-lock.json (100%) rename doc/{statepulse-doc => }/package.json (100%) rename doc/{statepulse-doc => }/sidebars.ts (100%) rename doc/{statepulse-doc => }/src/css/custom.css (100%) rename doc/{statepulse-doc => }/src/pages/markdown-page.md (100%) delete mode 100644 doc/statepulse-doc/build/assets/js/6638fef1.00b4e006.js delete mode 100644 doc/statepulse-doc/build/assets/js/94cf9043.d09cd2bd.js rename doc/{statepulse-doc => }/static/.nojekyll (100%) rename doc/{statepulse-doc => }/static/img/docusaurus-social-card.jpg (100%) rename doc/{statepulse-doc => }/static/img/docusaurus.png (100%) rename doc/{statepulse-doc => }/static/img/favicon.ico (100%) rename doc/{statepulse-doc => }/static/img/icon.png (100%) rename doc/{statepulse-doc => }/static/img/logo.svg (100%) rename doc/{statepulse-doc => }/static/img/nuget-logo.png (100%) rename doc/{statepulse-doc => }/static/img/undraw_docusaurus_mountain.svg (100%) rename doc/{statepulse-doc => }/static/img/undraw_docusaurus_react.svg (100%) rename doc/{statepulse-doc => }/static/img/undraw_docusaurus_tree.svg (100%) rename doc/{statepulse-doc => }/tsconfig.json (100%) create mode 100644 src/StatePulse.NET/Configuration/DispatchEffectExecutionBehavior.cs create mode 100644 src/StatePulse.NET/Configuration/DispatchOrdering.cs create mode 100644 src/StatePulse.NET/Engine/Exceptions/InvalidDispatchCombinationException.cs create mode 100644 src/StatePulse.NET/Engine/Implementations/DispatcherPrepper_Flags.cs delete mode 100644 src/StatePulse.NET/README.md diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index c805790..6119b99 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -38,9 +38,15 @@ jobs: - name: Pack StatePulse.Net.Abstractions run: dotnet pack src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj -c Release --no-build -o ./artifacts - + + - name: NuGet login (OIDC β†’ temp API key) + uses: NuGet/login@v1 + id: login + with: + user: ${{ secrets.NUGET_USER }} + - name: Push StatePulse.Net.Abstractions - run: dotnet nuget push ./artifacts/StatePulse.Net.Abstractions.*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate + run: dotnet nuget push ./artifacts/StatePulse.Net.Abstractions.*.nupkg --api-key ${{steps.login.outputs.NUGET_API_KEY}} --source https://api.nuget.org/v3/index.json --skip-duplicate - name: Wait for NuGet indexing run: sleep 120 deploy-core: @@ -72,6 +78,12 @@ jobs: - name: Pack StatePulse.NET run: dotnet pack src/StatePulse.NET/StatePulse.NET.csproj -c Release --no-build -o ./artifacts - + + - name: NuGet login (OIDC β†’ temp API key) + uses: NuGet/login@v1 + id: login + with: + user: ${{ secrets.NUGET_USER }} + - name: Push StatePulse.NET - run: dotnet nuget push ./artifacts/StatePulse.NET.*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate + run: dotnet nuget push ./artifacts/StatePulse.NET.*.nupkg --api-key ${{steps.login.outputs.NUGET_API_KEY}} --source https://api.nuget.org/v3/index.json --skip-duplicate diff --git a/README.md b/README.md index 0ad607f..3b37b10 100644 --- a/README.md +++ b/README.md @@ -64,22 +64,6 @@ public record ProfileCardDefineAction : IAction ``` -### **Define Actions Validator** (Optional): - -```csharp -/* -You are not required to create have an action validator but it is very useful when you have business logic that conditionally only contionally fires. -When validation fails it ignores the dispatch and move on. -*/ -internal class ProfileCardDefineActionValidator : IActionValidator -{ - public void Validate(ProfileCardDefineAction action, ref ValidationResult result) - { - if (action.TestData == "Error") - result.AddError("ErrorName", "Name Cannot be Error"); - } -} -``` ### **Define Effect**: @@ -104,6 +88,25 @@ internal class ProfileCardDefineEffect : IEffect } + +### **Define Effect Validator** (Optional): + +```csharp +/* +* This is the best way to define clean conditional effects, it either run or not... this is not meant for triggering errors. +* This is meant for optional/condition effects to either run or not base on the action settings... +*/ +internal class ProfileCardDefineActionValidator : IEffectValidator +{ + public Task Validate(ProfileCardDefineAction action) + { + if (action.TestData == "Error") + return Task.FromResult(false); + return Task.FromResult(true); + } +} +``` + ``` ### **Define Reducer**: diff --git a/doc/statepulse-doc/.gitignore b/doc/.gitignore similarity index 100% rename from doc/statepulse-doc/.gitignore rename to doc/.gitignore diff --git a/doc/statepulse-doc/README.md b/doc/README.md similarity index 100% rename from doc/statepulse-doc/README.md rename to doc/README.md diff --git a/doc/statepulse-doc/blog/2025-07-11Test.md b/doc/blog/2025-07-11Test.md similarity index 100% rename from doc/statepulse-doc/blog/2025-07-11Test.md rename to doc/blog/2025-07-11Test.md diff --git a/doc/statepulse-doc/blog/authors.yml b/doc/blog/authors.yml similarity index 100% rename from doc/statepulse-doc/blog/authors.yml rename to doc/blog/authors.yml diff --git a/doc/statepulse-doc/blog/tags.yml b/doc/blog/tags.yml similarity index 100% rename from doc/statepulse-doc/blog/tags.yml rename to doc/blog/tags.yml diff --git a/doc/statepulse-doc/build/.nojekyll b/doc/build/.nojekyll similarity index 100% rename from doc/statepulse-doc/build/.nojekyll rename to doc/build/.nojekyll diff --git a/doc/statepulse-doc/build/404.html b/doc/build/404.html similarity index 98% rename from doc/statepulse-doc/build/404.html rename to doc/build/404.html index 3c8a83c..746a7f7 100644 --- a/doc/statepulse-doc/build/404.html +++ b/doc/build/404.html @@ -5,8 +5,8 @@ StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/assets/css/styles.e8d85d9e.css b/doc/build/assets/css/styles.e8d85d9e.css similarity index 100% rename from doc/statepulse-doc/build/assets/css/styles.e8d85d9e.css rename to doc/build/assets/css/styles.e8d85d9e.css diff --git a/doc/statepulse-doc/build/assets/js/01a85c17.862c65d0.js b/doc/build/assets/js/01a85c17.862c65d0.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/01a85c17.862c65d0.js rename to doc/build/assets/js/01a85c17.862c65d0.js diff --git a/doc/statepulse-doc/build/assets/js/02105171.5d7951a6.js b/doc/build/assets/js/02105171.5d7951a6.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/02105171.5d7951a6.js rename to doc/build/assets/js/02105171.5d7951a6.js diff --git a/doc/statepulse-doc/build/assets/js/0bc25be7.282e267f.js b/doc/build/assets/js/0bc25be7.282e267f.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/0bc25be7.282e267f.js rename to doc/build/assets/js/0bc25be7.282e267f.js diff --git a/doc/statepulse-doc/build/assets/js/0d8668ed.85a2571d.js b/doc/build/assets/js/0d8668ed.85a2571d.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/0d8668ed.85a2571d.js rename to doc/build/assets/js/0d8668ed.85a2571d.js diff --git a/doc/statepulse-doc/build/assets/js/0e30184d.2549f073.js b/doc/build/assets/js/0e30184d.2549f073.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/0e30184d.2549f073.js rename to doc/build/assets/js/0e30184d.2549f073.js diff --git a/doc/statepulse-doc/build/assets/js/17896441.145b706a.js b/doc/build/assets/js/17896441.145b706a.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/17896441.145b706a.js rename to doc/build/assets/js/17896441.145b706a.js diff --git a/doc/statepulse-doc/build/assets/js/1f391b9e.47fc6bcb.js b/doc/build/assets/js/1f391b9e.47fc6bcb.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/1f391b9e.47fc6bcb.js rename to doc/build/assets/js/1f391b9e.47fc6bcb.js diff --git a/doc/statepulse-doc/build/assets/js/2237.2847df75.js b/doc/build/assets/js/2237.2847df75.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/2237.2847df75.js rename to doc/build/assets/js/2237.2847df75.js diff --git a/doc/statepulse-doc/build/assets/js/22dd74f7.0636519f.js b/doc/build/assets/js/22dd74f7.01add2a9.js similarity index 97% rename from doc/statepulse-doc/build/assets/js/22dd74f7.0636519f.js rename to doc/build/assets/js/22dd74f7.01add2a9.js index 5495572..b0a9362 100644 --- a/doc/statepulse-doc/build/assets/js/22dd74f7.0636519f.js +++ b/doc/build/assets/js/22dd74f7.01add2a9.js @@ -1 +1 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[1567],{5226:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Updates","href":"/versions","docId":"Versions","unlisted":false},{"type":"link","label":"Get Started","href":"/","docId":"Getting Started","unlisted":false},{"type":"link","label":"Setup Blazor Project","href":"/setup-blazor-project","docId":"Setup Blazor Project","unlisted":false},{"type":"link","label":"The Actions","href":"/gs-the-action","docId":"Creating Actions","unlisted":false},{"type":"link","label":"The States","href":"/gs-state","docId":"Create State","unlisted":false},{"type":"link","label":"The Effects","href":"/gs-the-effect","docId":"4 Create Effects","unlisted":false},{"type":"link","label":"The Reducers","href":"/gs-the-reducer","docId":"Create Reducer","unlisted":false},{"type":"link","label":"The Dispatcher","href":"/gs-the-dispatcher","docId":"Inject Dispatcher","unlisted":false},{"type":"link","label":"The Middlewares","href":"/gs-the-middlewares","docId":"Middlewares","unlisted":false}]},"docs":{"4 Create Effects":{"id":"4 Create Effects","title":"The Effects","description":"What are Effects","sidebar":"tutorialSidebar"},"Create Reducer":{"id":"Create Reducer","title":"The Reducers","description":"\ud83d\udd04 Reducers \u2013 Pure State Updates","sidebar":"tutorialSidebar"},"Create State":{"id":"Create State","title":"The States","description":"Defining a State","sidebar":"tutorialSidebar"},"Creating Actions":{"id":"Creating Actions","title":"The Actions","description":"Type of Actions","sidebar":"tutorialSidebar"},"Getting Started":{"id":"Getting Started","title":"Get Started","description":"License: MIT","sidebar":"tutorialSidebar"},"Inject Dispatcher":{"id":"Inject Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","sidebar":"tutorialSidebar"},"Middlewares":{"id":"Middlewares","title":"The Middlewares","description":"\u2699\ufe0f What are Middlewares?","sidebar":"tutorialSidebar"},"Setup Blazor Project":{"id":"Setup Blazor Project","title":"Setup Blazor Project","description":"\ud83d\udce6 Installation & Setup","sidebar":"tutorialSidebar"},"Versions":{"id":"Versions","title":"Updates","description":"\ud83d\udce6 v1.1.0","sidebar":"tutorialSidebar"}}}}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[1567],{5226:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Updates","href":"/versions","docId":"Versions","unlisted":false},{"type":"link","label":"Get Started","href":"/","docId":"Getting Started","unlisted":false},{"type":"link","label":"Setup Blazor Project","href":"/setup-blazor-project","docId":"Setup Blazor Project","unlisted":false},{"type":"link","label":"The Actions","href":"/gs-the-action","docId":"Creating Actions","unlisted":false},{"type":"link","label":"The States","href":"/gs-state","docId":"Create State","unlisted":false},{"type":"link","label":"The Effects","href":"/gs-the-effect","docId":"4 Create Effects","unlisted":false},{"type":"link","label":"The Reducers","href":"/gs-the-reducer","docId":"Create Reducer","unlisted":false},{"type":"link","label":"The Dispatcher","href":"/gs-the-dispatcher","docId":"Inject Dispatcher","unlisted":false},{"type":"link","label":"The Middlewares","href":"/gs-the-middlewares","docId":"Middlewares","unlisted":false}]},"docs":{"4 Create Effects":{"id":"4 Create Effects","title":"The Effects","description":"What are Effects","sidebar":"tutorialSidebar"},"Create Reducer":{"id":"Create Reducer","title":"The Reducers","description":"\ud83d\udd04 Reducers \u2013 Pure State Updates","sidebar":"tutorialSidebar"},"Create State":{"id":"Create State","title":"The States","description":"Defining a State","sidebar":"tutorialSidebar"},"Creating Actions":{"id":"Creating Actions","title":"The Actions","description":"Type of Actions","sidebar":"tutorialSidebar"},"Getting Started":{"id":"Getting Started","title":"Get Started","description":"License: MIT","sidebar":"tutorialSidebar"},"Inject Dispatcher":{"id":"Inject Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","sidebar":"tutorialSidebar"},"Middlewares":{"id":"Middlewares","title":"The Middlewares","description":"\u2699\ufe0f What are Middlewares?","sidebar":"tutorialSidebar"},"Setup Blazor Project":{"id":"Setup Blazor Project","title":"Setup Blazor Project","description":"\ud83d\udce6 Installation & Setup","sidebar":"tutorialSidebar"},"Versions":{"id":"Versions","title":"Updates","description":"\ud83d\udce6 v2.0.0","sidebar":"tutorialSidebar"}}}}')}}]); \ No newline at end of file diff --git a/doc/statepulse-doc/build/assets/js/2e6f86e1.0b70acfd.js b/doc/build/assets/js/2e6f86e1.0b70acfd.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/2e6f86e1.0b70acfd.js rename to doc/build/assets/js/2e6f86e1.0b70acfd.js diff --git a/doc/statepulse-doc/build/assets/js/3217192f.839e2666.js b/doc/build/assets/js/3217192f.839e2666.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/3217192f.839e2666.js rename to doc/build/assets/js/3217192f.839e2666.js diff --git a/doc/statepulse-doc/build/assets/js/33fc5bb8.71cc9278.js b/doc/build/assets/js/33fc5bb8.71cc9278.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/33fc5bb8.71cc9278.js rename to doc/build/assets/js/33fc5bb8.71cc9278.js diff --git a/doc/statepulse-doc/build/assets/js/36994c47.39393642.js b/doc/build/assets/js/36994c47.39393642.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/36994c47.39393642.js rename to doc/build/assets/js/36994c47.39393642.js diff --git a/doc/statepulse-doc/build/assets/js/3720c009.ccae4646.js b/doc/build/assets/js/3720c009.ccae4646.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/3720c009.ccae4646.js rename to doc/build/assets/js/3720c009.ccae4646.js diff --git a/doc/statepulse-doc/build/assets/js/393be207.2823742b.js b/doc/build/assets/js/393be207.2823742b.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/393be207.2823742b.js rename to doc/build/assets/js/393be207.2823742b.js diff --git a/doc/statepulse-doc/build/assets/js/3a2db09e.282370d5.js b/doc/build/assets/js/3a2db09e.282370d5.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/3a2db09e.282370d5.js rename to doc/build/assets/js/3a2db09e.282370d5.js diff --git a/doc/statepulse-doc/build/assets/js/4ebf985a.a97ef297.js b/doc/build/assets/js/4ebf985a.a97ef297.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/4ebf985a.a97ef297.js rename to doc/build/assets/js/4ebf985a.a97ef297.js diff --git a/doc/statepulse-doc/build/assets/js/547f2087.d07a2638.js b/doc/build/assets/js/547f2087.d07a2638.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/547f2087.d07a2638.js rename to doc/build/assets/js/547f2087.d07a2638.js diff --git a/doc/statepulse-doc/build/assets/js/59af61a6.9f2d00f9.js b/doc/build/assets/js/59af61a6.9f2d00f9.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/59af61a6.9f2d00f9.js rename to doc/build/assets/js/59af61a6.9f2d00f9.js diff --git a/doc/statepulse-doc/build/assets/js/5e90a9b3.e7712624.js b/doc/build/assets/js/5e90a9b3.e7712624.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/5e90a9b3.e7712624.js rename to doc/build/assets/js/5e90a9b3.e7712624.js diff --git a/doc/statepulse-doc/build/assets/js/5e95c892.9334a2c8.js b/doc/build/assets/js/5e95c892.9334a2c8.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/5e95c892.9334a2c8.js rename to doc/build/assets/js/5e95c892.9334a2c8.js diff --git a/doc/statepulse-doc/build/assets/js/6120.b521cc9a.js b/doc/build/assets/js/6120.b521cc9a.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/6120.b521cc9a.js rename to doc/build/assets/js/6120.b521cc9a.js diff --git a/doc/statepulse-doc/build/assets/js/621db11d.8a8315d5.js b/doc/build/assets/js/621db11d.8a8315d5.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/621db11d.8a8315d5.js rename to doc/build/assets/js/621db11d.8a8315d5.js diff --git a/doc/statepulse-doc/build/assets/js/6875c492.4b51a67c.js b/doc/build/assets/js/6875c492.4b51a67c.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/6875c492.4b51a67c.js rename to doc/build/assets/js/6875c492.4b51a67c.js diff --git a/doc/statepulse-doc/build/assets/js/68ee3bbe.20abb41a.js b/doc/build/assets/js/68ee3bbe.20abb41a.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/68ee3bbe.20abb41a.js rename to doc/build/assets/js/68ee3bbe.20abb41a.js diff --git a/doc/statepulse-doc/build/assets/js/6932.bfc2f6fe.js b/doc/build/assets/js/6932.bfc2f6fe.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/6932.bfc2f6fe.js rename to doc/build/assets/js/6932.bfc2f6fe.js diff --git a/doc/statepulse-doc/build/assets/js/7048d6c3.094da11e.js b/doc/build/assets/js/7048d6c3.094da11e.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/7048d6c3.094da11e.js rename to doc/build/assets/js/7048d6c3.094da11e.js diff --git a/doc/statepulse-doc/build/assets/js/742328d7.5ff212f5.js b/doc/build/assets/js/742328d7.5ff212f5.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/742328d7.5ff212f5.js rename to doc/build/assets/js/742328d7.5ff212f5.js diff --git a/doc/statepulse-doc/build/assets/js/7691d1c3.1689ceb1.js b/doc/build/assets/js/7691d1c3.1689ceb1.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/7691d1c3.1689ceb1.js rename to doc/build/assets/js/7691d1c3.1689ceb1.js diff --git a/doc/statepulse-doc/build/assets/js/79199b91.2c32870b.js b/doc/build/assets/js/79199b91.2c32870b.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/79199b91.2c32870b.js rename to doc/build/assets/js/79199b91.2c32870b.js diff --git a/doc/statepulse-doc/build/assets/js/7954e82b.358816fa.js b/doc/build/assets/js/7954e82b.358816fa.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/7954e82b.358816fa.js rename to doc/build/assets/js/7954e82b.358816fa.js diff --git a/doc/statepulse-doc/build/assets/js/814f3328.7ec3573c.js b/doc/build/assets/js/814f3328.7ec3573c.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/814f3328.7ec3573c.js rename to doc/build/assets/js/814f3328.7ec3573c.js diff --git a/doc/statepulse-doc/build/assets/js/8c3a5864.4dc1b980.js b/doc/build/assets/js/8c3a5864.4dc1b980.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/8c3a5864.4dc1b980.js rename to doc/build/assets/js/8c3a5864.4dc1b980.js diff --git a/doc/statepulse-doc/build/assets/js/8edd9378.74846925.js b/doc/build/assets/js/8edd9378.74846925.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/8edd9378.74846925.js rename to doc/build/assets/js/8edd9378.74846925.js diff --git a/doc/statepulse-doc/build/assets/js/90c0aa62.5eb5689f.js b/doc/build/assets/js/90c0aa62.5eb5689f.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/90c0aa62.5eb5689f.js rename to doc/build/assets/js/90c0aa62.5eb5689f.js diff --git a/doc/statepulse-doc/build/assets/js/936b9f1e.dfeb0090.js b/doc/build/assets/js/936b9f1e.dfeb0090.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/936b9f1e.dfeb0090.js rename to doc/build/assets/js/936b9f1e.dfeb0090.js diff --git a/doc/build/assets/js/94cf9043.2507e390.js b/doc/build/assets/js/94cf9043.2507e390.js new file mode 100644 index 0000000..0c30909 --- /dev/null +++ b/doc/build/assets/js/94cf9043.2507e390.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[6683],{8453:(e,n,i)=>{i.d(n,{R:()=>t,x:()=>d});var s=i(6540);const r={},l=s.createContext(r);function t(e){const n=s.useContext(l);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:t(e.components),s.createElement(l.Provider,{value:n},e.children)}},8886:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>d,default:()=>h,frontMatter:()=>t,metadata:()=>s,toc:()=>o});const s=JSON.parse('{"id":"Versions","title":"Updates","description":"\ud83d\udce6 v2.0.0","source":"@site/docs/0.Versions.md","sourceDirName":".","slug":"/versions","permalink":"/versions","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/0.Versions.md","tags":[],"version":"current","sidebarPosition":0,"frontMatter":{"slug":"versions","title":"Updates","sidebar_position":0},"sidebar":"tutorialSidebar","next":{"title":"Get Started","permalink":"/"}}');var r=i(4848),l=i(8453);const t={slug:"versions",title:"Updates",sidebar_position:0},d=void 0,c={},o=[{value:"\ud83d\udce6 v2.0.0",id:"-v200",level:2},{value:"\u2728 BREAKING CHANGES",id:"-breaking-changes",level:3},{value:"\u2728 New Features",id:"-new-features",level:3},{value:"\ud83d\udce6 v1.1.0",id:"-v110",level:2},{value:"\u2728 Minor Change",id:"-minor-change",level:3},{value:"\ud83d\udce6 v1.0.2",id:"-v102",level:2},{value:"\ud83d\udc1e Fixes",id:"-fixes",level:3},{value:"\ud83d\udce6 v1.0.1",id:"-v101",level:2},{value:"\u2728 Minor Change",id:"-minor-change-1",level:3},{value:"\ud83d\udce6 v1.0.0",id:"-v100",level:2},{value:"\u2728 New Features",id:"-new-features-1",level:3},{value:"\ud83d\udca5 Breaking Changes",id:"-breaking-changes-1",level:3},{value:"\ud83d\ude80 Performance Improvements",id:"-performance-improvements",level:3},{value:"\ud83e\uddfc Clean Code Improvements",id:"-clean-code-improvements",level:3},{value:"\ud83d\udc1e Fixes",id:"-fixes-1",level:3},{value:"v0.9.41",id:"v0941",level:2},{value:"v0.9.4",id:"v094",level:2},{value:"v0.9.21",id:"v0921",level:2},{value:"v0.9.2 (Blazor Packages)",id:"v092-blazor-packages",level:2}];function a(e){const n={code:"code",h2:"h2",h3:"h3",li:"li",strong:"strong",ul:"ul",...(0,l.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h2,{id:"-v200",children:"\ud83d\udce6 v2.0.0"}),"\n",(0,r.jsx)(n.h3,{id:"-breaking-changes",children:"\u2728 BREAKING CHANGES"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"The signature of interfaces changed so any plugin-based system could potentially break if core updates and plugins don't unless plugin isolation is respected."}),"\n",(0,r.jsxs)(n.li,{children:["The REDUCERS now run before the effects! so any pipelines relying on post-effect reducers should configure StatePulse to execute reducers post effect (simple config flip) ",(0,r.jsx)(n.code,{children:"Configure.DispatchOrderBehavior = DispatchOrdering.EffectsFirst;"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"-new-features",children:"\u2728 New Features"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"\u2699\ufe0f Enhanced Configuration Options"})," - New global configuration properties:","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"DispatchOrderBehavior"})," - Set default ordering (EffectsFirst/ReducersFirst)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"DispatchEffectExecutionBehavior"})," - Set default execution mode (YieldAndFire/FireAndForget)"]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"\ud83c\udf9b\ufe0f Configurable Dispatch Ordering"})," - Choose between ",(0,r.jsx)(n.code,{children:"EffectsFirst"})," (default) or ",(0,r.jsx)(n.code,{children:"ReducersFirst"})," execution order globally or per-dispatch"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"\u26a1 True Fire-and-Forget Execution Mode"})," - New ",(0,r.jsx)(n.code,{children:"DispatchEffectExecutionBehavior.FireAndForget"})," for true background execution without yielding and awaiting effects"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"\ud83d\udd27 Per-Dispatch Execution Control"})," - Override global settings per dispatch with fluent API:","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:".ExecFireAndForget()"})," - Fully detached background execution"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:".ExecYieldAndFire()"})," - Yield to caller but await until all effects are done to move down the pipeline"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:".EffectsFirst()"})," - Run effects before reducers"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:".ReducersFirst()"})," - Run reducers before effects"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:".SequentialEffects()"})," - Force effects to run in sequence"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:".ParallelEffects()"})," - Force effects to run in parallel"]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"\ud83d\udee1\ufe0f Invalid Configuration Detection"})," - New ",(0,r.jsx)(n.code,{children:"InvalidDispatchCombinationException"})," thrown at dispatch time for incompatible configuration combinations (Plan to generate compiler errors later)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"\u267b\ufe0f Recursive Dispatch Support"})," - Fire-and-forget mode enables safe recursive dispatch patterns without deadlocks"]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"-v110",children:"\ud83d\udce6 v1.1.0"}),"\n",(0,r.jsx)(n.h3,{id:"-minor-change",children:"\u2728 Minor Change"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Upgraded to .NET 10"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"-v102",children:"\ud83d\udce6 v1.0.2"}),"\n",(0,r.jsx)(n.h3,{id:"-fixes",children:"\ud83d\udc1e Fixes"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Added StatePulse.Net.Abstractions package reference instead of project reference to fix IL trimming issues."}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"-v101",children:"\ud83d\udce6 v1.0.1"}),"\n",(0,r.jsx)(n.h3,{id:"-minor-change-1",children:"\u2728 Minor Change"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Splited Abstractions into StatePulse.Net.Abstractions (Will not break anything Namespace is the same)"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"-v100",children:"\ud83d\udce6 v1.0.0"}),"\n",(0,r.jsx)(n.h3,{id:"-new-features-1",children:"\u2728 New Features"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\u2705 ",(0,r.jsx)(n.strong,{children:"Action Effect Validator"}),": Allows effects to run conditionally by validating them before execution."]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83e\udde9 ",(0,r.jsx)(n.strong,{children:"Middleware Support"}),":","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"IEffectMiddleware"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"IReducerMiddleware"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"IDispatchMiddleware"})}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\u2699\ufe0f ",(0,r.jsx)(n.strong,{children:"Behavior Configuration"}),": You can configure execution behaviors via:","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"DispatchEffectBehavior"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"MiddlewareEffectBehavior"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"MiddlewareTaskBehavior"})}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83d\udee0\ufe0f ",(0,r.jsx)(n.strong,{children:"Strict Manual Registration"}),": Manual service registration ",(0,r.jsx)(n.strong,{children:"must use"})," extension methods:","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"AddStatePulse()"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"AddStatePulseEffect<>()"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"AddStatePulseAction<>()"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"AddStatePulseReducer<>()"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"AddStatePulseStateFeature<>()"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"AddStatePulseEffectValidator<>()"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"-breaking-changes-1",children:"\ud83d\udca5 Breaking Changes"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\u274c Removed ",(0,r.jsx)(n.strong,{children:"Action Validator"})," \u2013 validating action data is not the responsibility of the state management layer."]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83d\udd04 Renamed:","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"IStateAccessor<>.StateChanged"})," \u2192 ",(0,r.jsx)(n.code,{children:"OnStateChanged"})]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"UsingSynchronousMode"})," \u2192 ",(0,r.jsx)(n.strong,{children:"Removed"})]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"Sync()"})," \u2192 ",(0,r.jsx)(n.code,{children:"Await()"})," for clarity and accuracy"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"-performance-improvements",children:"\ud83d\ude80 Performance Improvements"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\ud83e\udde0 Improved ",(0,r.jsx)(n.strong,{children:"dispatcher caching"})]}),"\n",(0,r.jsxs)(n.li,{children:["\u26a1 Enhanced ",(0,r.jsx)(n.strong,{children:"type cache"})," in ",(0,r.jsx)(n.code,{children:"StatePulseRegistry"})]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83e\uddec Replaced reflection with ",(0,r.jsx)(n.strong,{children:"dynamic method caching"})," for faster dispatching"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"-clean-code-improvements",children:"\ud83e\uddfc Clean Code Improvements"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\ud83e\uddf9 Refactored ",(0,r.jsx)(n.code,{children:"DispatchPrepper"})," for cleaner and lighter internal logic"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"-fixes-1",children:"\ud83d\udc1e Fixes"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\ud83d\udee0\ufe0f Resolved several ",(0,r.jsx)(n.strong,{children:"null reference warnings"})]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83e\uddfd Removed leftover ",(0,r.jsx)(n.strong,{children:"internal artifacts"})]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"v0941",children:"v0.9.41"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Fix: Added Anti-Service duplication to avoid double triggers."}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"v094",children:"v0.9.4"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Breaking Change, StateOf no longer accept lambda will throw exception you must define a Task directly... this was necessary due to Garbage Collector and tracking behavior."}),"\n",(0,r.jsx)(n.li,{children:"Deprecated UsingSynchronousMode() instead use Sync()."}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"v0921",children:"v0.9.21"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Implement the Blazor Package and removed dependencies to Blazor ComponentBase which is no longer required..."}),"\n",(0,r.jsx)(n.li,{children:"Any objects within .NET can now use IStatePulse and benefit from state management without extra implementations."}),"\n",(0,r.jsx)(n.li,{children:"Renamed IPulse to IStatePulse"}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"using IStatePulse.StateOf(()=>this, () => InvokeAsync(StateHasChanged));"})}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"v092-blazor-packages",children:"v0.9.2 (Blazor Packages)"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Deprecated now part of StatePulse regular since we have removed the dependencies to blazor component.\r\n... that was quick!"}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,l.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(a,{...e})}):a(e)}}}]); \ No newline at end of file diff --git a/doc/statepulse-doc/build/assets/js/9cc31a46.968cd617.js b/doc/build/assets/js/9cc31a46.968cd617.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/9cc31a46.968cd617.js rename to doc/build/assets/js/9cc31a46.968cd617.js diff --git a/doc/statepulse-doc/build/assets/js/9e4087bc.7497232a.js b/doc/build/assets/js/9e4087bc.7497232a.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/9e4087bc.7497232a.js rename to doc/build/assets/js/9e4087bc.7497232a.js diff --git a/doc/statepulse-doc/build/assets/js/a6aa9e1f.613b3683.js b/doc/build/assets/js/a6aa9e1f.613b3683.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/a6aa9e1f.613b3683.js rename to doc/build/assets/js/a6aa9e1f.613b3683.js diff --git a/doc/statepulse-doc/build/assets/js/a7456010.336f95fe.js b/doc/build/assets/js/a7456010.336f95fe.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/a7456010.336f95fe.js rename to doc/build/assets/js/a7456010.336f95fe.js diff --git a/doc/statepulse-doc/build/assets/js/a7bd4aaa.f2d2fe61.js b/doc/build/assets/js/a7bd4aaa.f2d2fe61.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/a7bd4aaa.f2d2fe61.js rename to doc/build/assets/js/a7bd4aaa.f2d2fe61.js diff --git a/doc/statepulse-doc/build/assets/js/a94703ab.abc249b9.js b/doc/build/assets/js/a94703ab.abc249b9.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/a94703ab.abc249b9.js rename to doc/build/assets/js/a94703ab.abc249b9.js diff --git a/doc/statepulse-doc/build/assets/js/aba21aa0.5a986477.js b/doc/build/assets/js/aba21aa0.5a986477.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/aba21aa0.5a986477.js rename to doc/build/assets/js/aba21aa0.5a986477.js diff --git a/doc/statepulse-doc/build/assets/js/acecf23e.b595c8e0.js b/doc/build/assets/js/acecf23e.b595c8e0.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/acecf23e.b595c8e0.js rename to doc/build/assets/js/acecf23e.b595c8e0.js diff --git a/doc/statepulse-doc/build/assets/js/c15d9823.c717e7e9.js b/doc/build/assets/js/c15d9823.c717e7e9.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/c15d9823.c717e7e9.js rename to doc/build/assets/js/c15d9823.c717e7e9.js diff --git a/doc/statepulse-doc/build/assets/js/c5fd082d.0836ff42.js b/doc/build/assets/js/c5fd082d.0836ff42.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/c5fd082d.0836ff42.js rename to doc/build/assets/js/c5fd082d.0836ff42.js diff --git a/doc/statepulse-doc/build/assets/js/c92171c2.a59a22be.js b/doc/build/assets/js/c92171c2.a59a22be.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/c92171c2.a59a22be.js rename to doc/build/assets/js/c92171c2.a59a22be.js diff --git a/doc/statepulse-doc/build/assets/js/c9c672c1.39aedffb.js b/doc/build/assets/js/c9c672c1.39aedffb.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/c9c672c1.39aedffb.js rename to doc/build/assets/js/c9c672c1.39aedffb.js diff --git a/doc/statepulse-doc/build/assets/js/cc87a84e.b58788db.js b/doc/build/assets/js/cc87a84e.b58788db.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/cc87a84e.b58788db.js rename to doc/build/assets/js/cc87a84e.b58788db.js diff --git a/doc/statepulse-doc/build/assets/js/ccc49370.24b047ad.js b/doc/build/assets/js/ccc49370.24b047ad.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/ccc49370.24b047ad.js rename to doc/build/assets/js/ccc49370.24b047ad.js diff --git a/doc/statepulse-doc/build/assets/js/cd69296b.c353b6fa.js b/doc/build/assets/js/cd69296b.c353b6fa.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/cd69296b.c353b6fa.js rename to doc/build/assets/js/cd69296b.c353b6fa.js diff --git a/doc/statepulse-doc/build/assets/js/d5b5cc03.04954f93.js b/doc/build/assets/js/d5b5cc03.04954f93.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/d5b5cc03.04954f93.js rename to doc/build/assets/js/d5b5cc03.04954f93.js diff --git a/doc/statepulse-doc/build/assets/js/dbf990ff.f9a1d8e6.js b/doc/build/assets/js/dbf990ff.f9a1d8e6.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/dbf990ff.f9a1d8e6.js rename to doc/build/assets/js/dbf990ff.f9a1d8e6.js diff --git a/doc/statepulse-doc/build/assets/js/df203c0f.c82ea539.js b/doc/build/assets/js/df203c0f.c82ea539.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/df203c0f.c82ea539.js rename to doc/build/assets/js/df203c0f.c82ea539.js diff --git a/doc/statepulse-doc/build/assets/js/e48d0160.acea7c7a.js b/doc/build/assets/js/e48d0160.acea7c7a.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/e48d0160.acea7c7a.js rename to doc/build/assets/js/e48d0160.acea7c7a.js diff --git a/doc/statepulse-doc/build/assets/js/e4b9287f.da013039.js b/doc/build/assets/js/e4b9287f.17e09519.js similarity index 99% rename from doc/statepulse-doc/build/assets/js/e4b9287f.da013039.js rename to doc/build/assets/js/e4b9287f.17e09519.js index 24dc02c..c749f5e 100644 --- a/doc/statepulse-doc/build/assets/js/e4b9287f.da013039.js +++ b/doc/build/assets/js/e4b9287f.17e09519.js @@ -1 +1 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[7778],{4661:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>s,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"Getting Started","title":"Get Started","description":"License: MIT","source":"@site/docs/Getting Started.md","sourceDirName":".","slug":"/","permalink":"/","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/Getting Started.md","tags":[],"version":"current","sidebarPosition":1,"frontMatter":{"slug":"/","title":"Get Started","sidebar_position":1},"sidebar":"tutorialSidebar","previous":{"title":"Updates","permalink":"/versions"},"next":{"title":"Setup Blazor Project","permalink":"/setup-blazor-project"}}');var r=t(4848),a=t(8453);const s={slug:"/",title:"Get Started",sidebar_position:1},o="StatePulse.NET",l={},c=[{value:"Official Documentation",id:"official-documentation",level:3},{value:"\u2728 Features",id:"-features",level:2},{value:"\ud83d\ude80 State Management with Zero Boilerplate and Zero Compromises",id:"-state-management-with-zero-boilerplate-and-zero-compromises",level:3},{value:"\ud83d\udce6 Installation & Setup",id:"-installation--setup",level:2},{value:"\ud83e\udded How It Works",id:"-how-it-works",level:2},{value:"Define Actions:",id:"define-actions",level:3},{value:"Define Actions Validator (Optional):",id:"define-actions-validator-optional",level:3},{value:"Define Effect:",id:"define-effect",level:3},{value:"Define Reducer:",id:"define-reducer",level:3},{value:"Define StateFeature:",id:"define-statefeature",level:3},{value:"Trigger Dispatch:",id:"trigger-dispatch",level:3},{value:"Important Notes",id:"important-notes",level:3},{value:"Access State:",id:"access-state",level:3},{value:"Blazor Example Usage",id:"blazor-example-usage",level:3}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.a,{href:"https://opensource.org/licenses/MIT",children:(0,r.jsx)(n.img,{src:"https://img.shields.io/badge/License-MIT-brightgreen.svg",alt:"License: MIT"})}),"\r\n",(0,r.jsx)(n.a,{href:"https://www.nuget.org/packages/StatePulse.NET",children:(0,r.jsx)(n.img,{src:"https://img.shields.io/nuget/v/StatePulse.Net",alt:"NuGet Version"})}),"\r\n",(0,r.jsx)(n.a,{href:"https://www.nuget.org/packages/StatePulse.NET",children:(0,r.jsx)(n.img,{src:"https://img.shields.io/nuget/dt/StatePulse.NET?label=Downloads",alt:""})})]}),"\n",(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"statepulsenet",children:"StatePulse.NET"})}),"\n",(0,r.jsx)(n.h3,{id:"official-documentation",children:(0,r.jsx)(n.a,{href:"https://statepulse.net/",children:"Official Documentation"})}),"\n",(0,r.jsx)(n.p,{children:"StatePulse.NET is a precision-tuned state and action management system that balances high-performance fire-and-forget operations with optional, internally controlled execution order when explicitly required.\r\nIt enables anti-duplication chaining for critical flows, preventing race conditions and ensuring consistent outcomes even under rapid user input or concurrent triggers.\r\nIts internal tracking infrastructure provides near-zero overhead cancellation and dispatch control, drastically reducing inconsistency.\r\nAt the same time, it preserves the flexibility of traditional untracked state management, letting developers selectively enforce order and reliability without compromising overall responsiveness or introducing global locks."}),"\n",(0,r.jsx)(n.h2,{id:"-features",children:"\u2728 Features"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\u26a1 ",(0,r.jsx)(n.strong,{children:"Fast Fire-and-Forget"})," \u2014 Executes actions immediately even tracked action are fire-and-forget."]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83d\udee1 ",(0,r.jsx)(n.strong,{children:"Anti-Duplicate Dispatching"})," \u2014 Prevents redundant or overlapping actions that can cause race condition state inconsistency."]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83d\udd0d ",(0,r.jsx)(n.strong,{children:"Effect Validator System"})," \u2014 Supports multiple effect validators for modular and reusable rule enforcement."]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83e\uddea ",(0,r.jsx)(n.strong,{children:"Synchronous Debug Mode"})," \u2014 Optional lockstep mode for testing, diagnostics, and ",(0,r.jsx)(n.code,{children:"Task.WhenAll"})," pipelines."]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83e\uddf5 ",(0,r.jsx)(n.strong,{children:"DispatchTracker"})," \u2014 High-performance cancellation and deduplication logic via optimized concurrent tracking."]}),"\n"]}),"\n",(0,r.jsxs)(n.h3,{id:"-state-management-with-zero-boilerplate-and-zero-compromises",children:["\ud83d\ude80 ",(0,r.jsx)(n.strong,{children:"State Management with Zero Boilerplate and Zero Compromises"})]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Lazy State Access Model:"})," Inject ",(0,r.jsx)(n.code,{children:"IStatePulse"})," directly into your Blazor component and call ",(0,r.jsx)(n.code,{children:"StateOf(()=>this, TaskMethod)"})," to get scoped state access."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Component-Scoped Event Listening:"})," Automatically registers event listeners only for that component, ensuring ",(0,r.jsx)(n.code,{children:"StateHasChanged()"})," is called exclusively on components subscribed to state changes."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"No Base Classes or Global Event Listeners:"})," Avoids global re-renders and boilerplate base class inheritance, giving you fine-grained control over component rendering and event subscription without forcing you into base classes."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Automatic Listener Disposal:"})," Event listeners are automatically tracked and disposed with the component lifecycle, preventing memory leaks and dangling references."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsxs)(n.strong,{children:["Transient ",(0,r.jsx)(n.code,{children:"IStatePulse"})," Service:"]})," Each component gets its own ",(0,r.jsx)(n.code,{children:"IStatePulse"})," instance, isolating event subscriptions and making state updates scoped and efficient."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"-installation--setup",children:"\ud83d\udce6 Installation & Setup"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"Install-Package StatePulse.Net\r\n\r\ndotnet add package StatePulse.Net\r\n\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"services.AddStatePulseServices(o =>\r\n {\r\n o.ScanAssemblies = new Type[] { typeof(Program) };\r\n });\n"})}),"\n",(0,r.jsx)(n.h2,{id:"-how-it-works",children:"\ud83e\udded How It Works"}),"\n",(0,r.jsxs)(n.h3,{id:"define-actions",children:[(0,r.jsx)(n.strong,{children:"Define Actions"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"\r\n// IAction { }\r\n// ISafeAction { } // Cannot be dispatched unsafely\r\n\r\npublic record ProfileCardDefineAction : IAction\r\n{\r\n public string? TestData { get; set; }\r\n}\r\n\n"})}),"\n",(0,r.jsxs)(n.h3,{id:"define-actions-validator-optional",children:[(0,r.jsx)(n.strong,{children:"Define Actions Validator"})," (Optional):"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:'/*\r\nYou are not required to create have an action validator but it is very useful when you have business logic that conditionally only contionally fires.\r\nWhen validation fails it ignores the dispatch and move on.\r\n*/\r\ninternal class ProfileCardDefineActionValidator : IActionValidator\r\n{\r\n public void Validate(ProfileCardDefineAction action, ref ValidationResult result)\r\n {\r\n if (action.TestData == "Error")\r\n result.AddError("ErrorName", "Name Cannot be Error");\r\n }\r\n}\n'})}),"\n",(0,r.jsxs)(n.h3,{id:"define-effect",children:[(0,r.jsx)(n.strong,{children:"Define Effect"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"\r\ninternal class ProfileCardDefineEffect : IEffect\r\n{\r\n\r\n public ProfileCardDefineEffect()\r\n {\r\n }\r\n public async Task EffectAsync(ProfileCardDefineAction action, IDispatcher dispatcher)\r\n {\r\n var random = new Random();\r\n int value = random.Next(100, 1001); // Upper bound is exclusive, so use 1001\r\n await Task.Delay(value);\r\n var myProfile = new UserResponse();\r\n await dispatcher.Prepare(() => new ProfileCardDefineResultAction(action.TestData ?? myProfile.Name, myProfile.Picture, myProfile.Id))\r\n .DispatchAsync();\r\n }\r\n\r\n}\r\n\r\n\n"})}),"\n",(0,r.jsxs)(n.h3,{id:"define-reducer",children:[(0,r.jsx)(n.strong,{children:"Define Reducer"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"internal class ProfileCardDefineResultReducer : IReducer\r\n{\r\n public Task ReduceAsync(ProfileCardState state, ProfileCardDefineResultAction action)\r\n => Task.FromResult(state with\r\n {\r\n LastUpdate = DateTime.UtcNow,\r\n ProfileId = action.Id,\r\n ProfileName = action.Name,\r\n ProfilePicture = action.Picture\r\n });\r\n}\n"})}),"\n",(0,r.jsxs)(n.h3,{id:"define-statefeature",children:[(0,r.jsx)(n.strong,{children:"Define StateFeature"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"public record ProfileCardState : IStateFeature\r\n{\r\n public string? ProfileName { get; set; }\r\n public string? ProfilePicture { get; set; }\r\n public string? ProfileId { get; set; }\r\n public DateTime LastUpdate { get; set; } = DateTime.UtcNow;\r\n}\n"})}),"\n",(0,r.jsxs)(n.h3,{id:"trigger-dispatch",children:[(0,r.jsx)(n.strong,{children:"Trigger Dispatch"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"var dispatcher = ServiceProvider.GetRequiredService();\r\nvar stateAccessor = ServiceProvider.GetRequiredService>();\r\nawait dispatcher.Prepare().With(p => p.TestData, name)\r\n .DispatchAsync();\r\n\r\n// You can Capture the validation in case of failure, only call if validators exist.\r\nValidationResult? validation = default;\r\nawait dispatcher.Prepare().With(p => p.TestData, name)\r\n .HandleActionValidation(p => validation = p)\r\n .DispatchAsync();\r\n\r\n// You can trigger synchronously... this will await the whole pipeline, otherwise you just await until action is send to dispatch pool.\r\nawait dispatcher.Prepare().With(p => p.TestData, name)\r\n .Sync()\r\n .DispatchAsync();\r\n\r\n// if the action is implementing ISafeState, the dispatch will always run asSafe=true but an action not implementing ISafeAction will\r\n// have the option to run asSafe or not...\r\nawait dispatcher.Prepare().With(p => p.TestData, name)\r\n .DispatchAsync(true);\n"})}),"\n",(0,r.jsx)(n.h3,{id:"important-notes",children:"Important Notes"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Rule of thumb is always await dispatch calls, avoiding to do so can cause inconsistency for safe dispatch mode.."}),"\n",(0,r.jsx)(n.li,{children:"ISafeAction implementations are always dispatched safely, ignoring unsafe flags."}),"\n",(0,r.jsx)(n.li,{children:"synchronous is an anti-pattern of statemanement use it sparingly; it is primarily for debugging or specific scenarios requiring full completion before continuation."}),"\n"]}),"\n",(0,r.jsxs)(n.h3,{id:"access-state",children:[(0,r.jsx)(n.strong,{children:"Access State"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"var stateAccessor = ServiceProvider.GetRequiredService>();\n"})}),"\n",(0,r.jsx)(n.h3,{id:"blazor-example-usage",children:"Blazor Example Usage"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"using StatePulse.Net;\r\n\r\npublic partial class CounterView : ComponentBase\r\n{\r\n\r\n // METHOD 1:\r\n [Inject] public IStatePulse PulseState { get; set; } = default!; // Handles State Accessor\r\n\r\n // This is for convienience always use this method or directly PulseState.StateOf(this).Value\r\n // Never assign State Instance variable as it will not update... \r\n // Never use lambda it will throw exception as WeakREference is fundamatally flawed and disposes of lambda even when its object is alive.\r\n private CounterState state => PulseState.StateOf(()=>this, OnUpdate);\r\n \r\n private async Task OnUpdate() => await InvokeAsync(StateHadChanged);\r\n\r\n // METHOD 2: \r\n // Inject direct state but injecting the state directly requires you to handle onchanged events by sub/unsub in lifecycle\r\n // Or to create a basecomponent system similar to other state management systems.\r\n [Inject] public IStateAccessor State { get; set; } = default!; \r\n\r\n \r\n}\n"})})]})}function u(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>s,x:()=>o});var i=t(6540);const r={},a=i.createContext(r);function s(e){const n=i.useContext(a);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),i.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[7778],{4661:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>s,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"Getting Started","title":"Get Started","description":"License: MIT","source":"@site/docs/Getting Started.md","sourceDirName":".","slug":"/","permalink":"/","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/Getting Started.md","tags":[],"version":"current","sidebarPosition":1,"frontMatter":{"slug":"/","title":"Get Started","sidebar_position":1},"sidebar":"tutorialSidebar","previous":{"title":"Updates","permalink":"/versions"},"next":{"title":"Setup Blazor Project","permalink":"/setup-blazor-project"}}');var r=t(4848),a=t(8453);const s={slug:"/",title:"Get Started",sidebar_position:1},o="StatePulse.NET",l={},c=[{value:"Official Documentation",id:"official-documentation",level:3},{value:"\u2728 Features",id:"-features",level:2},{value:"\ud83d\ude80 State Management with Zero Boilerplate and Zero Compromises",id:"-state-management-with-zero-boilerplate-and-zero-compromises",level:3},{value:"\ud83d\udce6 Installation & Setup",id:"-installation--setup",level:2},{value:"\ud83e\udded How It Works",id:"-how-it-works",level:2},{value:"Define Actions:",id:"define-actions",level:3},{value:"Define Actions Validator (Optional):",id:"define-actions-validator-optional",level:3},{value:"Define Effect:",id:"define-effect",level:3},{value:"Define Reducer:",id:"define-reducer",level:3},{value:"Define StateFeature:",id:"define-statefeature",level:3},{value:"Trigger Dispatch:",id:"trigger-dispatch",level:3},{value:"Important Notes",id:"important-notes",level:3},{value:"Access State:",id:"access-state",level:3},{value:"Blazor Example Usage",id:"blazor-example-usage",level:3}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.a,{href:"https://opensource.org/licenses/MIT",children:(0,r.jsx)(n.img,{src:"https://img.shields.io/badge/License-MIT-brightgreen.svg",alt:"License: MIT"})}),"\r\n",(0,r.jsx)(n.a,{href:"https://www.nuget.org/packages/StatePulse.NET",children:(0,r.jsx)(n.img,{src:"https://img.shields.io/nuget/v/StatePulse.Net",alt:"NuGet Version"})}),"\r\n",(0,r.jsx)(n.a,{href:"https://www.nuget.org/packages/StatePulse.NET",children:(0,r.jsx)(n.img,{src:"https://img.shields.io/nuget/dt/StatePulse.NET?label=Downloads",alt:""})})]}),"\n",(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"statepulsenet",children:"StatePulse.NET"})}),"\n",(0,r.jsx)(n.h3,{id:"official-documentation",children:(0,r.jsx)(n.a,{href:"https://statepulse.net/",children:"Official Documentation"})}),"\n",(0,r.jsx)(n.p,{children:"StatePulse.NET is a precision-tuned state and action management system that balances high-performance fire-and-forget operations with optional, internally controlled execution order when explicitly required.\r\nIt enables anti-duplication chaining for critical flows, preventing race conditions and ensuring consistent outcomes even under rapid user input or concurrent triggers.\r\nIts internal tracking infrastructure provides near-zero overhead cancellation and dispatch control, drastically reducing inconsistency.\r\nAt the same time, it preserves the flexibility of traditional untracked state management, letting developers selectively enforce order and reliability without compromising overall responsiveness or introducing global locks."}),"\n",(0,r.jsx)(n.h2,{id:"-features",children:"\u2728 Features"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\u26a1 ",(0,r.jsx)(n.strong,{children:"Fast Fire-and-Forget"})," \u2014 Executes actions immediately even tracked action are fire-and-forget."]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83d\udee1 ",(0,r.jsx)(n.strong,{children:"Anti-Duplicate Dispatching"})," \u2014 Prevents redundant or overlapping actions that can cause race condition state inconsistency."]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83d\udd0d ",(0,r.jsx)(n.strong,{children:"Effect Validator System"})," \u2014 Supports multiple effect validators for modular and reusable rule enforcement."]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83e\uddea ",(0,r.jsx)(n.strong,{children:"Synchronous Debug Mode"})," \u2014 Optional lockstep mode for testing, diagnostics, and ",(0,r.jsx)(n.code,{children:"Task.WhenAll"})," pipelines."]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83e\uddf5 ",(0,r.jsx)(n.strong,{children:"DispatchTracker"})," \u2014 High-performance cancellation and deduplication logic via optimized concurrent tracking."]}),"\n"]}),"\n",(0,r.jsxs)(n.h3,{id:"-state-management-with-zero-boilerplate-and-zero-compromises",children:["\ud83d\ude80 ",(0,r.jsx)(n.strong,{children:"State Management with Zero Boilerplate and Zero Compromises"})]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Lazy State Access Model:"})," Inject ",(0,r.jsx)(n.code,{children:"IStatePulse"})," directly into your Blazor component and call ",(0,r.jsx)(n.code,{children:"StateOf(()=>this, TaskMethod)"})," to get scoped state access."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Component-Scoped Event Listening:"})," Automatically registers event listeners only for that component, ensuring ",(0,r.jsx)(n.code,{children:"StateHasChanged()"})," is called exclusively on components subscribed to state changes."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"No Base Classes or Global Event Listeners:"})," Avoids global re-renders and boilerplate base class inheritance, giving you fine-grained control over component rendering and event subscription without forcing you into base classes."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Automatic Listener Disposal:"})," Event listeners are automatically tracked and disposed with the component lifecycle, preventing memory leaks and dangling references."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsxs)(n.strong,{children:["Transient ",(0,r.jsx)(n.code,{children:"IStatePulse"})," Service:"]})," Each component gets its own ",(0,r.jsx)(n.code,{children:"IStatePulse"})," instance, isolating event subscriptions and making state updates scoped and efficient."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"-installation--setup",children:"\ud83d\udce6 Installation & Setup"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"Install-Package StatePulse.Net\r\n\r\ndotnet add package StatePulse.Net\r\n\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"services.AddStatePulseServices(o =>\r\n {\r\n o.ScanAssemblies = new Type[] { typeof(Program) };\r\n });\n"})}),"\n",(0,r.jsx)(n.h2,{id:"-how-it-works",children:"\ud83e\udded How It Works"}),"\n",(0,r.jsxs)(n.h3,{id:"define-actions",children:[(0,r.jsx)(n.strong,{children:"Define Actions"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"\r\n// IAction { }\r\n// ISafeAction { } // Cannot be dispatched unsafely\r\n\r\npublic record ProfileCardDefineAction : IAction\r\n{\r\n public string? TestData { get; set; }\r\n}\r\n\n"})}),"\n",(0,r.jsxs)(n.h3,{id:"define-actions-validator-optional",children:[(0,r.jsx)(n.strong,{children:"Define Actions Validator"})," (Optional):"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:'/*\r\nYou are not required to create have an action validator but it is very useful when you have business logic that conditionally only contionally fires.\r\nWhen validation fails it ignores the dispatch and move on.\r\n*/\r\ninternal class ProfileCardDefineActionValidator : IActionValidator\r\n{\r\n public void Validate(ProfileCardDefineAction action, ref ValidationResult result)\r\n {\r\n if (action.TestData == "Error")\r\n result.AddError("ErrorName", "Name Cannot be Error");\r\n }\r\n}\n'})}),"\n",(0,r.jsxs)(n.h3,{id:"define-effect",children:[(0,r.jsx)(n.strong,{children:"Define Effect"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"\r\ninternal class ProfileCardDefineEffect : IEffect\r\n{\r\n\r\n public ProfileCardDefineEffect()\r\n {\r\n }\r\n public async Task EffectAsync(ProfileCardDefineAction action, IDispatcher dispatcher)\r\n {\r\n var random = new Random();\r\n int value = random.Next(100, 1001); // Upper bound is exclusive, so use 1001\r\n await Task.Delay(value);\r\n var myProfile = new UserResponse();\r\n await dispatcher.Prepare(() => new ProfileCardDefineResultAction(action.TestData ?? myProfile.Name, myProfile.Picture, myProfile.Id))\r\n .DispatchAsync();\r\n }\r\n\r\n}\r\n\r\n\n"})}),"\n",(0,r.jsxs)(n.h3,{id:"define-reducer",children:[(0,r.jsx)(n.strong,{children:"Define Reducer"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"internal class ProfileCardDefineResultReducer : IReducer\r\n{\r\n public Task ReduceAsync(ProfileCardState state, ProfileCardDefineResultAction action)\r\n => Task.FromResult(state with\r\n {\r\n LastUpdate = DateTime.UtcNow,\r\n ProfileId = action.Id,\r\n ProfileName = action.Name,\r\n ProfilePicture = action.Picture\r\n });\r\n}\n"})}),"\n",(0,r.jsxs)(n.h3,{id:"define-statefeature",children:[(0,r.jsx)(n.strong,{children:"Define StateFeature"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"public record ProfileCardState : IStateFeature\r\n{\r\n public string? ProfileName { get; set; }\r\n public string? ProfilePicture { get; set; }\r\n public string? ProfileId { get; set; }\r\n public DateTime LastUpdate { get; set; } = DateTime.UtcNow;\r\n}\n"})}),"\n",(0,r.jsxs)(n.h3,{id:"trigger-dispatch",children:[(0,r.jsx)(n.strong,{children:"Trigger Dispatch"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"var dispatcher = ServiceProvider.GetRequiredService();\r\nvar stateAccessor = ServiceProvider.GetRequiredService>();\r\nawait dispatcher.Prepare().With(p => p.TestData, name)\r\n .DispatchAsync();\r\n\r\n// You can Capture the validation in case of failure, only call if validators exist.\r\nValidationResult? validation = default;\r\nawait dispatcher.Prepare().With(p => p.TestData, name)\r\n .HandleActionValidation(p => validation = p)\r\n .DispatchAsync();\r\n\r\n// You can trigger synchronously... this will await the whole pipeline, otherwise you just await until action is send to dispatch pool.\r\nawait dispatcher.Prepare().With(p => p.TestData, name)\r\n .Sync()\r\n .DispatchAsync();\r\n\r\n// if the action is implementing ISafeState, the dispatch will always run asSafe=true but an action not implementing ISafeAction will\r\n// have the option to run asSafe or not...\r\nawait dispatcher.Prepare().With(p => p.TestData, name)\r\n .DispatchAsync(true);\n"})}),"\n",(0,r.jsx)(n.h3,{id:"important-notes",children:"Important Notes"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Rule of thumb is always await dispatch calls, avoiding to do so can cause inconsistency for safe dispatch mode.."}),"\n",(0,r.jsx)(n.li,{children:"ISafeAction implementations are always dispatched safely, ignoring unsafe flags."}),"\n",(0,r.jsx)(n.li,{children:"synchronous is an anti-pattern of statemanement use it sparingly; it is primarily for debugging or specific scenarios requiring full completion before continuation."}),"\n"]}),"\n",(0,r.jsxs)(n.h3,{id:"access-state",children:[(0,r.jsx)(n.strong,{children:"Access State"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"var stateAccessor = ServiceProvider.GetRequiredService>();\n"})}),"\n",(0,r.jsx)(n.h3,{id:"blazor-example-usage",children:"Blazor Example Usage"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"using StatePulse.Net;\r\n\r\npublic partial class CounterView : ComponentBase\r\n{\r\n\r\n // METHOD 1:\r\n [Inject] public IStatePulse PulseState { get; set; } = default!; // Handles State Accessor\r\n\r\n // This is for convienience always use this method or directly PulseState.StateOf(this).Value\r\n // Never assign State Instance variable as it will not update... \r\n // Never use lambda it will throw exception as WeakREference is fundamatally flawed and disposes of lambda even when its object is alive.\r\n private CounterState state => PulseState.StateOf(()=>this, OnUpdate);\r\n \r\n private async Task OnUpdate() => await InvokeAsync(StateHasChanged);\r\n\r\n // METHOD 2: \r\n // Inject direct state but injecting the state directly requires you to handle onchanged events by sub/unsub in lifecycle\r\n // Or to create a basecomponent system similar to other state management systems.\r\n [Inject] public IStateAccessor State { get; set; } = default!; \r\n\r\n \r\n}\n"})})]})}function u(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>s,x:()=>o});var i=t(6540);const r={},a=i.createContext(r);function s(e){const n=i.useContext(a);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),i.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/doc/statepulse-doc/build/assets/js/e925e243.eaa2c69c.js b/doc/build/assets/js/e925e243.eaa2c69c.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/e925e243.eaa2c69c.js rename to doc/build/assets/js/e925e243.eaa2c69c.js diff --git a/doc/statepulse-doc/build/assets/js/ef8b811a.724d7ea4.js b/doc/build/assets/js/ef8b811a.724d7ea4.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/ef8b811a.724d7ea4.js rename to doc/build/assets/js/ef8b811a.724d7ea4.js diff --git a/doc/build/assets/js/f179eaed.fef2718c.js b/doc/build/assets/js/f179eaed.fef2718c.js new file mode 100644 index 0000000..66df55c --- /dev/null +++ b/doc/build/assets/js/f179eaed.fef2718c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[4157],{2850:(e,r,s)=>{s.r(r),s.d(r,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>t,toc:()=>d});const t=JSON.parse('{"id":"Middlewares","title":"The Middlewares","description":"\u2699\ufe0f What are Middlewares?","source":"@site/docs/7.Middlewares.md","sourceDirName":".","slug":"/gs-the-middlewares","permalink":"/gs-the-middlewares","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/7.Middlewares.md","tags":[{"inline":true,"label":"blazor","permalink":"/tags/blazor"},{"inline":true,"label":"reducer","permalink":"/tags/reducer"},{"inline":true,"label":"state-management","permalink":"/tags/state-management"},{"inline":true,"label":"pure-functions","permalink":"/tags/pure-functions"},{"inline":true,"label":"async","permalink":"/tags/async"},{"inline":true,"label":"statepulse","permalink":"/tags/statepulse"},{"inline":true,"label":"csharp","permalink":"/tags/csharp"},{"inline":true,"label":".net","permalink":"/tags/net"}],"version":"current","sidebarPosition":7,"frontMatter":{"slug":"gs-the-middlewares","title":"The Middlewares","tags":["blazor","reducer","state-management","pure-functions","async","statepulse","csharp",".net"],"sidebar_position":7},"sidebar":"tutorialSidebar","previous":{"title":"The Dispatcher","permalink":"/gs-the-dispatcher"}}');var n=s(4848),l=s(8453);const i={slug:"gs-the-middlewares",title:"The Middlewares",tags:["blazor","reducer","state-management","pure-functions","async","statepulse","csharp",".net"],sidebar_position:7},a=void 0,c={},d=[{value:"\u2699\ufe0f What are Middlewares?",id:"\ufe0f-what-are-middlewares",level:2},{value:"\ud83e\udde9 Effect Middleware",id:"-effect-middleware",level:2},{value:"Available Hooks",id:"available-hooks",level:3},{value:"Example: Effect Middleware",id:"example-effect-middleware",level:3},{value:"\ud83d\udcd8 Other Middleware Types",id:"-other-middleware-types",level:2},{value:"\ud83e\uddfc Use Cases",id:"-use-cases",level:2}];function o(e){const r={blockquote:"blockquote",br:"br",code:"code",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,l.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(r.h2,{id:"\ufe0f-what-are-middlewares",children:"\u2699\ufe0f What are Middlewares?"}),"\n",(0,n.jsxs)(r.p,{children:["StatePulse uses ",(0,n.jsx)(r.strong,{children:"middleware interfaces"})," to tap into the lifecycle of ",(0,n.jsx)(r.strong,{children:"effects"}),", ",(0,n.jsx)(r.strong,{children:"reducers"}),", and ",(0,n.jsx)(r.strong,{children:"dispatches"}),".",(0,n.jsx)(r.br,{}),"\n","These middleware hooks are useful for ",(0,n.jsx)(r.strong,{children:"logging"}),", ",(0,n.jsx)(r.strong,{children:"metrics"}),", ",(0,n.jsx)(r.strong,{children:"analytics"}),", or ",(0,n.jsx)(r.strong,{children:"debugging"})," \u2014 but should ",(0,n.jsx)(r.strong,{children:"never alter behavior"})," or mutate state."]}),"\n",(0,n.jsxs)(r.blockquote,{children:["\n",(0,n.jsx)(r.p,{children:"\u2757 Middleware is observational only \u2014 do not use it to change logic or outcomes."}),"\n"]}),"\n",(0,n.jsx)(r.h2,{id:"-effect-middleware",children:"\ud83e\udde9 Effect Middleware"}),"\n",(0,n.jsxs)(r.p,{children:[(0,n.jsx)(r.code,{children:"IEffectMiddleware"})," allows you to hook into the execution of any effect."]}),"\n",(0,n.jsx)(r.h3,{id:"available-hooks",children:"Available Hooks"}),"\n",(0,n.jsxs)(r.ul,{children:["\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.code,{children:"BeforeEffect(object action)"})," \u2013 called ",(0,n.jsx)(r.strong,{children:"before"})," the effect runs"]}),"\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.code,{children:"AfterEffect(object action)"})," \u2013 called ",(0,n.jsx)(r.strong,{children:"after"})," the effect completes"]}),"\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.code,{children:"WhenEffectValidationFailed(object action, object effectValidator)"})," \u2013 called when a validator blocks execution"]}),"\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.code,{children:"WhenEffectValidationSucceed(object action, object effectValidator)"})," \u2013 called when a validator passes"]}),"\n"]}),"\n",(0,n.jsx)(r.h3,{id:"example-effect-middleware",children:"Example: Effect Middleware"}),"\n",(0,n.jsx)(r.pre,{children:(0,n.jsx)(r.code,{className:"language-csharp",metastring:'title="LoggingMiddleware.cs"',children:'internal class LoggingMiddleware : IEffectMiddleware\r\n{\r\n private readonly ILogger _logger;\r\n\r\n public LoggingMiddleware(ILogger logger)\r\n {\r\n _logger = logger;\r\n }\r\n public Task AfterEffect(object action)\r\n {\r\n string message = $"{action.GetType()} finished execution.";\r\n _logger.LogDebug(message);\r\n return Task.CompletedTask;\r\n }\r\n public Task BeforeEffect(object action) => Task.CompletedTask;\r\n public Task WhenEffectValidationFailed(object action, object effectValidator) => Task.CompletedTask;\r\n public Task WhenEffectValidationSucceed(object action, object effectValidator) => Task.CompletedTask;\r\n}\r\n\n'})}),"\n",(0,n.jsx)(r.h2,{id:"-other-middleware-types",children:"\ud83d\udcd8 Other Middleware Types"}),"\n",(0,n.jsx)(r.p,{children:"Additional interfaces are available to observe other parts of the StatePulse pipeline:"}),"\n",(0,n.jsxs)(r.ul,{children:["\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.code,{children:"IReducerMiddleware"})," \u2013 Observe ",(0,n.jsx)(r.strong,{children:"reducer"})," executions (before/after)"]}),"\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.code,{children:"IDispatcherMiddleware"})," \u2013 Observe all ",(0,n.jsx)(r.strong,{children:"dispatched actions"})," (before/after)"]}),"\n"]}),"\n",(0,n.jsxs)(r.p,{children:["These follow a similar structure to ",(0,n.jsx)(r.code,{children:"IEffectMiddleware"}),", offering lifecycle hooks such as:"]}),"\n",(0,n.jsxs)(r.ul,{children:["\n",(0,n.jsx)(r.li,{children:(0,n.jsx)(r.code,{children:"Before..."})}),"\n",(0,n.jsx)(r.li,{children:(0,n.jsx)(r.code,{children:"After..."})}),"\n"]}),"\n",(0,n.jsxs)(r.blockquote,{children:["\n",(0,n.jsxs)(r.p,{children:["\u26a0\ufe0f Just like with effects, these middleware interfaces are ",(0,n.jsx)(r.strong,{children:"observational only"})," \u2014 they should not alter state or behavior."]}),"\n"]}),"\n",(0,n.jsx)(r.h2,{id:"-use-cases",children:"\ud83e\uddfc Use Cases"}),"\n",(0,n.jsx)(r.p,{children:"Here are common use cases for StatePulse middleware:"}),"\n",(0,n.jsxs)(r.ul,{children:["\n",(0,n.jsxs)(r.li,{children:["\u2705 Logging effects, reducers, or dispatches for ",(0,n.jsx)(r.strong,{children:"debugging"})]}),"\n",(0,n.jsxs)(r.li,{children:["\ud83d\udcca Tracking ",(0,n.jsx)(r.strong,{children:"user behavior"})]}),"\n",(0,n.jsxs)(r.li,{children:["\u23f1\ufe0f Measuring ",(0,n.jsx)(r.strong,{children:"performance metrics"})]}),"\n",(0,n.jsxs)(r.li,{children:["\ud83d\udcc8 Collecting ",(0,n.jsx)(r.strong,{children:"analytics"})," without mutating state or logic"]}),"\n"]})]})}function h(e={}){const{wrapper:r}={...(0,l.R)(),...e.components};return r?(0,n.jsx)(r,{...e,children:(0,n.jsx)(o,{...e})}):o(e)}},8453:(e,r,s)=>{s.d(r,{R:()=>i,x:()=>a});var t=s(6540);const n={},l=t.createContext(n);function i(e){const r=t.useContext(l);return t.useMemo(function(){return"function"==typeof e?e(r):{...r,...e}},[r,e])}function a(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:i(e.components),t.createElement(l.Provider,{value:r},e.children)}}}]); \ No newline at end of file diff --git a/doc/statepulse-doc/build/assets/js/f2ace840.16526adf.js b/doc/build/assets/js/f2ace840.16526adf.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/f2ace840.16526adf.js rename to doc/build/assets/js/f2ace840.16526adf.js diff --git a/doc/statepulse-doc/build/assets/js/f552f37d.15137b77.js b/doc/build/assets/js/f552f37d.15137b77.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/f552f37d.15137b77.js rename to doc/build/assets/js/f552f37d.15137b77.js diff --git a/doc/statepulse-doc/build/assets/js/f6f0caca.6f80119e.js b/doc/build/assets/js/f6f0caca.6f80119e.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/f6f0caca.6f80119e.js rename to doc/build/assets/js/f6f0caca.6f80119e.js diff --git a/doc/statepulse-doc/build/assets/js/f81c1134.801b7b65.js b/doc/build/assets/js/f81c1134.801b7b65.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/f81c1134.801b7b65.js rename to doc/build/assets/js/f81c1134.801b7b65.js diff --git a/doc/statepulse-doc/build/assets/js/febfe999.614202d2.js b/doc/build/assets/js/febfe999.614202d2.js similarity index 100% rename from doc/statepulse-doc/build/assets/js/febfe999.614202d2.js rename to doc/build/assets/js/febfe999.614202d2.js diff --git a/doc/statepulse-doc/build/assets/js/main.16c181e8.js b/doc/build/assets/js/main.1e4c436b.js similarity index 98% rename from doc/statepulse-doc/build/assets/js/main.16c181e8.js rename to doc/build/assets/js/main.1e4c436b.js index 35d3e03..20ddf94 100644 --- a/doc/statepulse-doc/build/assets/js/main.16c181e8.js +++ b/doc/build/assets/js/main.1e4c436b.js @@ -1,2 +1,2 @@ -/*! For license information please see main.16c181e8.js.LICENSE.txt */ -(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[8792],{115:e=>{var t="undefined"!=typeof Element,n="function"==typeof Map,r="function"==typeof Set,a="function"==typeof ArrayBuffer&&!!ArrayBuffer.isView;function o(e,i){if(e===i)return!0;if(e&&i&&"object"==typeof e&&"object"==typeof i){if(e.constructor!==i.constructor)return!1;var l,s,u,c;if(Array.isArray(e)){if((l=e.length)!=i.length)return!1;for(s=l;0!==s--;)if(!o(e[s],i[s]))return!1;return!0}if(n&&e instanceof Map&&i instanceof Map){if(e.size!==i.size)return!1;for(c=e.entries();!(s=c.next()).done;)if(!i.has(s.value[0]))return!1;for(c=e.entries();!(s=c.next()).done;)if(!o(s.value[1],i.get(s.value[0])))return!1;return!0}if(r&&e instanceof Set&&i instanceof Set){if(e.size!==i.size)return!1;for(c=e.entries();!(s=c.next()).done;)if(!i.has(s.value[0]))return!1;return!0}if(a&&ArrayBuffer.isView(e)&&ArrayBuffer.isView(i)){if((l=e.length)!=i.length)return!1;for(s=l;0!==s--;)if(e[s]!==i[s])return!1;return!0}if(e.constructor===RegExp)return e.source===i.source&&e.flags===i.flags;if(e.valueOf!==Object.prototype.valueOf&&"function"==typeof e.valueOf&&"function"==typeof i.valueOf)return e.valueOf()===i.valueOf();if(e.toString!==Object.prototype.toString&&"function"==typeof e.toString&&"function"==typeof i.toString)return e.toString()===i.toString();if((l=(u=Object.keys(e)).length)!==Object.keys(i).length)return!1;for(s=l;0!==s--;)if(!Object.prototype.hasOwnProperty.call(i,u[s]))return!1;if(t&&e instanceof Element)return!1;for(s=l;0!==s--;)if(("_owner"!==u[s]&&"__v"!==u[s]&&"__o"!==u[s]||!e.$$typeof)&&!o(e[u[s]],i[u[s]]))return!1;return!0}return e!=e&&i!=i}e.exports=function(e,t){try{return o(e,t)}catch(n){if((n.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw n}}},119:(e,t,n)=>{"use strict";n.r(t)},205:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});var r=n(6540);const a=n(8193).A.canUseDOM?r.useLayoutEffect:r.useEffect},253:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=function e(t){if(t.cause)return[t,...e(t.cause)];return[t]}},311:e=>{"use strict";e.exports=function(e,t,n,r,a,o,i,l){if(!e){var s;if(void 0===t)s=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var u=[n,r,a,o,i,l],c=0;(s=new Error(t.replace(/%s/g,function(){return u[c++]}))).name="Invariant Violation"}throw s.framesToPop=1,s}}},418:(e,t,n)=>{"use strict";n.d(t,{A:()=>r});const r=()=>null},440:(e,t,n)=>{"use strict";t.rA=t.Ks=t.LU=void 0;const r=n(1635);t.LU="__blog-post-container";var a=n(2983);Object.defineProperty(t,"Ks",{enumerable:!0,get:function(){return r.__importDefault(a).default}});var o=n(2566);var i=n(253);Object.defineProperty(t,"rA",{enumerable:!0,get:function(){return i.getErrorCausalChain}})},545:(e,t,n)=>{"use strict";n.d(t,{mg:()=>J,vd:()=>W});var r=n(6540),a=n(5556),o=n.n(a),i=n(115),l=n.n(i),s=n(311),u=n.n(s),c=n(2833),d=n.n(c);function f(){return f=Object.assign||function(e){for(var t=1;t=0||(a[n]=e[n]);return a}var m={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title",FRAGMENT:"Symbol(react.fragment)"},y={rel:["amphtml","canonical","alternate"]},b={type:["application/ld+json"]},v={charset:"",name:["robots","description"],property:["og:type","og:title","og:url","og:image","og:image:alt","og:description","twitter:url","twitter:title","twitter:description","twitter:image","twitter:image:alt","twitter:card","twitter:site"]},w=Object.keys(m).map(function(e){return m[e]}),k={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"},x=Object.keys(k).reduce(function(e,t){return e[k[t]]=t,e},{}),S=function(e,t){for(var n=e.length-1;n>=0;n-=1){var r=e[n];if(Object.prototype.hasOwnProperty.call(r,t))return r[t]}return null},_=function(e){var t=S(e,m.TITLE),n=S(e,"titleTemplate");if(Array.isArray(t)&&(t=t.join("")),n&&t)return n.replace(/%s/g,function(){return t});var r=S(e,"defaultTitle");return t||r||void 0},E=function(e){return S(e,"onChangeClientState")||function(){}},C=function(e,t){return t.filter(function(t){return void 0!==t[e]}).map(function(t){return t[e]}).reduce(function(e,t){return f({},e,t)},{})},A=function(e,t){return t.filter(function(e){return void 0!==e[m.BASE]}).map(function(e){return e[m.BASE]}).reverse().reduce(function(t,n){if(!t.length)for(var r=Object.keys(n),a=0;a/g,">").replace(/"/g,""").replace(/'/g,"'")},F=function(e){return Object.keys(e).reduce(function(t,n){var r=void 0!==e[n]?n+'="'+e[n]+'"':""+n;return t?t+" "+r:r},"")},I=function(e,t){return void 0===t&&(t={}),Object.keys(e).reduce(function(t,n){return t[k[n]||n]=e[n],t},t)},D=function(e,t){return t.map(function(t,n){var a,o=((a={key:n})["data-rh"]=!0,a);return Object.keys(t).forEach(function(e){var n=k[e]||e;"innerHTML"===n||"cssText"===n?o.dangerouslySetInnerHTML={__html:t.innerHTML||t.cssText}:o[n]=t[e]}),r.createElement(e,o)})},M=function(e,t,n){switch(e){case m.TITLE:return{toComponent:function(){return n=t.titleAttributes,(a={key:e=t.title})["data-rh"]=!0,o=I(n,a),[r.createElement(m.TITLE,o,e)];var e,n,a,o},toString:function(){return function(e,t,n,r){var a=F(n),o=P(t);return a?"<"+e+' data-rh="true" '+a+">"+R(o,r)+"":"<"+e+' data-rh="true">'+R(o,r)+""}(e,t.title,t.titleAttributes,n)}};case"bodyAttributes":case"htmlAttributes":return{toComponent:function(){return I(t)},toString:function(){return F(t)}};default:return{toComponent:function(){return D(e,t)},toString:function(){return function(e,t,n){return t.reduce(function(t,r){var a=Object.keys(r).filter(function(e){return!("innerHTML"===e||"cssText"===e)}).reduce(function(e,t){var a=void 0===r[t]?t:t+'="'+R(r[t],n)+'"';return e?e+" "+a:a},""),o=r.innerHTML||r.cssText||"",i=-1===L.indexOf(e);return t+"<"+e+' data-rh="true" '+a+(i?"/>":">"+o+"")},"")}(e,t,n)}}}},z=function(e){var t=e.baseTag,n=e.bodyAttributes,r=e.encode,a=e.htmlAttributes,o=e.noscriptTags,i=e.styleTags,l=e.title,s=void 0===l?"":l,u=e.titleAttributes,c=e.linkTags,d=e.metaTags,f=e.scriptTags,p={toComponent:function(){},toString:function(){return""}};if(e.prioritizeSeoTags){var g=function(e){var t=e.linkTags,n=e.scriptTags,r=e.encode,a=N(e.metaTags,v),o=N(t,y),i=N(n,b);return{priorityMethods:{toComponent:function(){return[].concat(D(m.META,a.priority),D(m.LINK,o.priority),D(m.SCRIPT,i.priority))},toString:function(){return M(m.META,a.priority,r)+" "+M(m.LINK,o.priority,r)+" "+M(m.SCRIPT,i.priority,r)}},metaTags:a.default,linkTags:o.default,scriptTags:i.default}}(e);p=g.priorityMethods,c=g.linkTags,d=g.metaTags,f=g.scriptTags}return{priority:p,base:M(m.BASE,t,r),bodyAttributes:M("bodyAttributes",n,r),htmlAttributes:M("htmlAttributes",a,r),link:M(m.LINK,c,r),meta:M(m.META,d,r),noscript:M(m.NOSCRIPT,o,r),script:M(m.SCRIPT,f,r),style:M(m.STYLE,i,r),title:M(m.TITLE,{title:s,titleAttributes:u},r)}},B=[],$=function(e,t){var n=this;void 0===t&&(t="undefined"!=typeof document),this.instances=[],this.value={setHelmet:function(e){n.context.helmet=e},helmetInstances:{get:function(){return n.canUseDOM?B:n.instances},add:function(e){(n.canUseDOM?B:n.instances).push(e)},remove:function(e){var t=(n.canUseDOM?B:n.instances).indexOf(e);(n.canUseDOM?B:n.instances).splice(t,1)}}},this.context=e,this.canUseDOM=t,t||(e.helmet=z({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}}))},U=r.createContext({}),H=o().shape({setHelmet:o().func,helmetInstances:o().shape({get:o().func,add:o().func,remove:o().func})}),V="undefined"!=typeof document,W=function(e){function t(n){var r;return(r=e.call(this,n)||this).helmetData=new $(r.props.context,t.canUseDOM),r}return p(t,e),t.prototype.render=function(){return r.createElement(U.Provider,{value:this.helmetData.value},this.props.children)},t}(r.Component);W.canUseDOM=V,W.propTypes={context:o().shape({helmet:o().shape()}),children:o().node.isRequired},W.defaultProps={context:{}},W.displayName="HelmetProvider";var q=function(e,t){var n,r=document.head||document.querySelector(m.HEAD),a=r.querySelectorAll(e+"[data-rh]"),o=[].slice.call(a),i=[];return t&&t.length&&t.forEach(function(t){var r=document.createElement(e);for(var a in t)Object.prototype.hasOwnProperty.call(t,a)&&("innerHTML"===a?r.innerHTML=t.innerHTML:"cssText"===a?r.styleSheet?r.styleSheet.cssText=t.cssText:r.appendChild(document.createTextNode(t.cssText)):r.setAttribute(a,void 0===t[a]?"":t[a]));r.setAttribute("data-rh","true"),o.some(function(e,t){return n=t,r.isEqualNode(e)})?o.splice(n,1):i.push(r)}),o.forEach(function(e){return e.parentNode.removeChild(e)}),i.forEach(function(e){return r.appendChild(e)}),{oldTags:o,newTags:i}},G=function(e,t){var n=document.getElementsByTagName(e)[0];if(n){for(var r=n.getAttribute("data-rh"),a=r?r.split(","):[],o=[].concat(a),i=Object.keys(t),l=0;l=0;d-=1)n.removeAttribute(o[d]);a.length===o.length?n.removeAttribute("data-rh"):n.getAttribute("data-rh")!==i.join(",")&&n.setAttribute("data-rh",i.join(","))}},Y=function(e,t){var n=e.baseTag,r=e.htmlAttributes,a=e.linkTags,o=e.metaTags,i=e.noscriptTags,l=e.onChangeClientState,s=e.scriptTags,u=e.styleTags,c=e.title,d=e.titleAttributes;G(m.BODY,e.bodyAttributes),G(m.HTML,r),function(e,t){void 0!==e&&document.title!==e&&(document.title=P(e)),G(m.TITLE,t)}(c,d);var f={baseTag:q(m.BASE,n),linkTags:q(m.LINK,a),metaTags:q(m.META,o),noscriptTags:q(m.NOSCRIPT,i),scriptTags:q(m.SCRIPT,s),styleTags:q(m.STYLE,u)},p={},g={};Object.keys(f).forEach(function(e){var t=f[e],n=t.newTags,r=t.oldTags;n.length&&(p[e]=n),r.length&&(g[e]=f[e].oldTags)}),t&&t(),l(e,p,g)},K=null,Q=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),a=0;a elements are self-closing and can not contain children. Refer to our API for more information.")}},n.flattenArrayTypeChildren=function(e){var t,n=e.child,r=e.arrayTypeChildren;return f({},r,((t={})[n.type]=[].concat(r[n.type]||[],[f({},e.newChildProps,this.mapNestedChildrenToProps(n,e.nestedChildren))]),t))},n.mapObjectTypeChildren=function(e){var t,n,r=e.child,a=e.newProps,o=e.newChildProps,i=e.nestedChildren;switch(r.type){case m.TITLE:return f({},a,((t={})[r.type]=i,t.titleAttributes=f({},o),t));case m.BODY:return f({},a,{bodyAttributes:f({},o)});case m.HTML:return f({},a,{htmlAttributes:f({},o)});default:return f({},a,((n={})[r.type]=f({},o),n))}},n.mapArrayTypeChildrenToProps=function(e,t){var n=f({},t);return Object.keys(e).forEach(function(t){var r;n=f({},n,((r={})[t]=e[t],r))}),n},n.warnOnInvalidChildren=function(e,t){return u()(w.some(function(t){return e.type===t}),"function"==typeof e.type?"You may be attempting to nest components within each other, which is not allowed. Refer to our API for more information.":"Only elements types "+w.join(", ")+" are allowed. Helmet does not support rendering <"+e.type+"> elements. Refer to our API for more information."),u()(!t||"string"==typeof t||Array.isArray(t)&&!t.some(function(e){return"string"!=typeof e}),"Helmet expects a string as a child of <"+e.type+">. Did you forget to wrap your children in braces? ( <"+e.type+">{``} ) Refer to our API for more information."),!0},n.mapChildrenToProps=function(e,t){var n=this,a={};return r.Children.forEach(e,function(e){if(e&&e.props){var r=e.props,o=r.children,i=h(r,Z),l=Object.keys(i).reduce(function(e,t){return e[x[t]||t]=i[t],e},{}),s=e.type;switch("symbol"==typeof s?s=s.toString():n.warnOnInvalidChildren(e,o),s){case m.FRAGMENT:t=n.mapChildrenToProps(o,t);break;case m.LINK:case m.META:case m.NOSCRIPT:case m.SCRIPT:case m.STYLE:a=n.flattenArrayTypeChildren({child:e,arrayTypeChildren:a,newChildProps:l,nestedChildren:o});break;default:t=n.mapObjectTypeChildren({child:e,newProps:t,newChildProps:l,nestedChildren:o})}}}),this.mapArrayTypeChildrenToProps(a,t)},n.render=function(){var e=this.props,t=e.children,n=h(e,X),a=f({},n),o=n.helmetData;return t&&(a=this.mapChildrenToProps(t,a)),!o||o instanceof $||(o=new $(o.context,o.instances)),o?r.createElement(Q,f({},a,{context:o.value,helmetData:void 0})):r.createElement(U.Consumer,null,function(e){return r.createElement(Q,f({},a,{context:e}))})},t}(r.Component);J.propTypes={base:o().object,bodyAttributes:o().object,children:o().oneOfType([o().arrayOf(o().node),o().node]),defaultTitle:o().string,defer:o().bool,encodeSpecialCharacters:o().bool,htmlAttributes:o().object,link:o().arrayOf(o().object),meta:o().arrayOf(o().object),noscript:o().arrayOf(o().object),onChangeClientState:o().func,script:o().arrayOf(o().object),style:o().arrayOf(o().object),title:o().string,titleAttributes:o().object,titleTemplate:o().string,prioritizeSeoTags:o().bool,helmetData:o().object},J.defaultProps={defer:!0,encodeSpecialCharacters:!0,prioritizeSeoTags:!1},J.displayName="Helmet"},609:(e,t,n)=>{"use strict";n.d(t,{V:()=>s,t:()=>u});var r=n(6540),a=n(9532),o=n(4848);const i=Symbol("EmptyContext"),l=r.createContext(i);function s({children:e,name:t,items:n}){const a=(0,r.useMemo)(()=>t&&n?{name:t,items:n}:null,[t,n]);return(0,o.jsx)(l.Provider,{value:a,children:e})}function u(){const e=(0,r.useContext)(l);if(e===i)throw new a.dV("DocsSidebarProvider");return e}},679:(e,t,n)=>{"use strict";n.d(t,{Wf:()=>u});n(6540);const r=JSON.parse('{"N":"localStorage","M":""}'),a=r.N;function o({key:e,oldValue:t,newValue:n,storage:r}){if(t===n)return;const a=document.createEvent("StorageEvent");a.initStorageEvent("storage",!1,!1,e,t,n,window.location.href,r),window.dispatchEvent(a)}function i(e=a){if("undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,l||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),l=!0),null}var t}let l=!1;const s={get:()=>null,set:()=>{},del:()=>{},listen:()=>()=>{}};function u(e,t){const n=`${e}${r.M}`;if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t,listen:t}}(n);const a=i(t?.persistence);return null===a?s:{get:()=>{try{return a.getItem(n)}catch(e){return console.error(`Docusaurus storage error, can't get key=${n}`,e),null}},set:e=>{try{const t=a.getItem(n);a.setItem(n,e),o({key:n,oldValue:t,newValue:e,storage:a})}catch(t){console.error(`Docusaurus storage error, can't set ${n}=${e}`,t)}},del:()=>{try{const e=a.getItem(n);a.removeItem(n),o({key:n,oldValue:e,newValue:null,storage:a})}catch(e){console.error(`Docusaurus storage error, can't delete key=${n}`,e)}},listen:e=>{try{const t=t=>{t.storageArea===a&&t.key===n&&e(t)};return window.addEventListener("storage",t),()=>window.removeEventListener("storage",t)}catch(t){return console.error(`Docusaurus storage error, can't listen for changes of key=${n}`,t),()=>{}}}}}},961:(e,t,n)=>{"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}(),e.exports=n(6221)},1043:(e,t,n)=>{"use strict";n.r(t)},1107:(e,t,n)=>{"use strict";n.d(t,{A:()=>c});n(6540);var r=n(4164),a=n(1312),o=n(6342),i=n(8774),l=n(3427);const s={anchorWithStickyNavbar:"anchorWithStickyNavbar_LWe7",anchorWithHideOnScrollNavbar:"anchorWithHideOnScrollNavbar_WYt5"};var u=n(4848);function c({as:e,id:t,...n}){const c=(0,l.A)(),{navbar:{hideOnScroll:d}}=(0,o.p)();if("h1"===e||!t)return(0,u.jsx)(e,{...n,id:void 0});c.collectAnchor(t);const f=(0,a.T)({id:"theme.common.headingLinkTitle",message:"Direct link to {heading}",description:"Title for link to heading"},{heading:"string"==typeof n.children?n.children:t});return(0,u.jsxs)(e,{...n,className:(0,r.A)("anchor",d?s.anchorWithHideOnScrollNavbar:s.anchorWithStickyNavbar,n.className),id:t,children:[n.children,(0,u.jsx)(i.A,{className:"hash-link",to:`#${t}`,"aria-label":f,title:f,children:"\u200b"})]})}},1122:(e,t,n)=>{"use strict";n.d(t,{A:()=>c});var r=n(6540),a=n(4164),o=n(2303),i=n(5293);const l={themedComponent:"themedComponent_mlkZ","themedComponent--light":"themedComponent--light_NVdE","themedComponent--dark":"themedComponent--dark_xIcU"};var s=n(4848);function u({className:e,children:t}){const n=(0,o.A)(),{colorMode:u}=(0,i.G)();return(0,s.jsx)(s.Fragment,{children:(n?"dark"===u?["dark"]:["light"]:["light","dark"]).map(n=>{const o=t({theme:n,className:(0,a.A)(e,l.themedComponent,l[`themedComponent--${n}`])});return(0,s.jsx)(r.Fragment,{children:o},n)})})}function c(e){const{sources:t,className:n,alt:r,...a}=e;return(0,s.jsx)(u,{className:n,children:({theme:e,className:n})=>(0,s.jsx)("img",{src:t[e],alt:r,className:n,...a})})}},1247:(e,t,n)=>{"use strict";var r=n(9982),a=n(6540),o=n(961);function i(e){var t="https://react.dev/errors/"+e;if(1M||(e.current=D[M],D[M]=null,M--)}function $(e,t){M++,D[M]=e.current,e.current=t}var U=z(null),H=z(null),V=z(null),W=z(null);function q(e,t){switch($(V,t),$(H,e),$(U,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?ad(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)e=od(t=ad(t),e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}B(U),$(U,e)}function G(){B(U),B(H),B(V)}function Y(e){null!==e.memoizedState&&$(W,e);var t=U.current,n=od(t,e.type);t!==n&&($(H,e),$(U,n))}function K(e){H.current===e&&(B(U),B(H)),W.current===e&&(B(W),Yd._currentValue=I)}var Q=Object.prototype.hasOwnProperty,Z=r.unstable_scheduleCallback,X=r.unstable_cancelCallback,J=r.unstable_shouldYield,ee=r.unstable_requestPaint,te=r.unstable_now,ne=r.unstable_getCurrentPriorityLevel,re=r.unstable_ImmediatePriority,ae=r.unstable_UserBlockingPriority,oe=r.unstable_NormalPriority,ie=r.unstable_LowPriority,le=r.unstable_IdlePriority,se=r.log,ue=r.unstable_setDisableYieldValue,ce=null,de=null;function fe(e){if("function"==typeof se&&ue(e),de&&"function"==typeof de.setStrictMode)try{de.setStrictMode(ce,e)}catch(t){}}var pe=Math.clz32?Math.clz32:function(e){return 0===(e>>>=0)?32:31-(ge(e)/he|0)|0},ge=Math.log,he=Math.LN2;var me=256,ye=4194304;function be(e){var t=42&e;if(0!==t)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return 4194048&e;case 4194304:case 8388608:case 16777216:case 33554432:return 62914560&e;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function ve(e,t,n){var r=e.pendingLanes;if(0===r)return 0;var a=0,o=e.suspendedLanes,i=e.pingedLanes;e=e.warmLanes;var l=134217727&r;return 0!==l?0!==(r=l&~o)?a=be(r):0!==(i&=l)?a=be(i):n||0!==(n=l&~e)&&(a=be(n)):0!==(l=r&~o)?a=be(l):0!==i?a=be(i):n||0!==(n=r&~e)&&(a=be(n)),0===a?0:0!==t&&t!==a&&0===(t&o)&&((o=a&-a)>=(n=t&-t)||32===o&&4194048&n)?t:a}function we(e,t){return 0===(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)}function ke(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;default:return-1}}function xe(){var e=me;return!(4194048&(me<<=1))&&(me=256),e}function Se(){var e=ye;return!(62914560&(ye<<=1))&&(ye=4194304),e}function _e(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function Ee(e,t){e.pendingLanes|=t,268435456!==t&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Ce(e,t,n){e.pendingLanes|=t,e.suspendedLanes&=~t;var r=31-pe(t);e.entangledLanes|=t,e.entanglements[r]=1073741824|e.entanglements[r]|4194090&n}function Ae(e,t){var n=e.entangledLanes|=t;for(e=e.entanglements;n;){var r=31-pe(n),a=1<)":-1--a||s[r]!==u[a]){var c="\n"+s[r].replace(" at new "," at ");return e.displayName&&c.includes("")&&(c=c.replace("",e.displayName)),c}}while(1<=r&&0<=a);break}}}finally{ot=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:"")?at(n):""}function lt(e){switch(e.tag){case 26:case 27:case 5:return at(e.type);case 16:return at("Lazy");case 13:return at("Suspense");case 19:return at("SuspenseList");case 0:case 15:return it(e.type,!1);case 11:return it(e.type.render,!1);case 1:return it(e.type,!0);case 31:return at("Activity");default:return""}}function st(e){try{var t="";do{t+=lt(e),e=e.return}while(e);return t}catch(n){return"\nError generating stack: "+n.message+"\n"+n.stack}}function ut(e){switch(typeof e){case"bigint":case"boolean":case"number":case"string":case"undefined":case"object":return e;default:return""}}function ct(e){var t=e.type;return(e=e.nodeName)&&"input"===e.toLowerCase()&&("checkbox"===t||"radio"===t)}function dt(e){e._valueTracker||(e._valueTracker=function(e){var t=ct(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&void 0!==n&&"function"==typeof n.get&&"function"==typeof n.set){var a=n.get,o=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return a.call(this)},set:function(e){r=""+e,o.call(this,e)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(e){r=""+e},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}(e))}function ft(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=ct(e)?e.checked?"true":"false":e.value),(e=r)!==n&&(t.setValue(e),!0)}function pt(e){if(void 0===(e=e||("undefined"!=typeof document?document:void 0)))return null;try{return e.activeElement||e.body}catch(t){return e.body}}var gt=/[\n"\\]/g;function ht(e){return e.replace(gt,function(e){return"\\"+e.charCodeAt(0).toString(16)+" "})}function mt(e,t,n,r,a,o,i,l){e.name="",null!=i&&"function"!=typeof i&&"symbol"!=typeof i&&"boolean"!=typeof i?e.type=i:e.removeAttribute("type"),null!=t?"number"===i?(0===t&&""===e.value||e.value!=t)&&(e.value=""+ut(t)):e.value!==""+ut(t)&&(e.value=""+ut(t)):"submit"!==i&&"reset"!==i||e.removeAttribute("value"),null!=t?bt(e,i,ut(t)):null!=n?bt(e,i,ut(n)):null!=r&&e.removeAttribute("value"),null==a&&null!=o&&(e.defaultChecked=!!o),null!=a&&(e.checked=a&&"function"!=typeof a&&"symbol"!=typeof a),null!=l&&"function"!=typeof l&&"symbol"!=typeof l&&"boolean"!=typeof l?e.name=""+ut(l):e.removeAttribute("name")}function yt(e,t,n,r,a,o,i,l){if(null!=o&&"function"!=typeof o&&"symbol"!=typeof o&&"boolean"!=typeof o&&(e.type=o),null!=t||null!=n){if(("submit"===o||"reset"===o)&&null==t)return;n=null!=n?""+ut(n):"",t=null!=t?""+ut(t):n,l||t===e.value||(e.value=t),e.defaultValue=t}r="function"!=typeof(r=null!=r?r:a)&&"symbol"!=typeof r&&!!r,e.checked=l?e.checked:!!r,e.defaultChecked=!!r,null!=i&&"function"!=typeof i&&"symbol"!=typeof i&&"boolean"!=typeof i&&(e.name=i)}function bt(e,t,n){"number"===t&&pt(e.ownerDocument)===e||e.defaultValue===""+n||(e.defaultValue=""+n)}function vt(e,t,n,r){if(e=e.options,t){t={};for(var a=0;a=Sn),Cn=String.fromCharCode(32),An=!1;function Tn(e,t){switch(e){case"keyup":return-1!==kn.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function jn(e){return"object"==typeof(e=e.detail)&&"data"in e?e.data:null}var Pn=!1;var Nn={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};function On(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return"input"===t?!!Nn[e.type]:"textarea"===t}function Ln(e,t,n,r){Ot?Lt?Lt.push(r):Lt=[r]:Ot=r,0<(t=Vc(t,"onChange")).length&&(n=new Jt("onChange","change",null,n,r),e.push({event:n,listeners:t}))}var Rn=null,Fn=null;function In(e){Ic(e,0)}function Dn(e){if(ft(He(e)))return e}function Mn(e,t){if("change"===e)return t}var zn=!1;if(Mt){var Bn;if(Mt){var $n="oninput"in document;if(!$n){var Un=document.createElement("div");Un.setAttribute("oninput","return;"),$n="function"==typeof Un.oninput}Bn=$n}else Bn=!1;zn=Bn&&(!document.documentMode||9=t)return{node:r,offset:t-e};e=n}e:{for(;r;){if(r.nextSibling){r=r.nextSibling;break e}r=r.parentNode}r=void 0}r=Zn(r)}}function Jn(e,t){return!(!e||!t)&&(e===t||(!e||3!==e.nodeType)&&(t&&3===t.nodeType?Jn(e,t.parentNode):"contains"in e?e.contains(t):!!e.compareDocumentPosition&&!!(16&e.compareDocumentPosition(t))))}function er(e){for(var t=pt((e=null!=e&&null!=e.ownerDocument&&null!=e.ownerDocument.defaultView?e.ownerDocument.defaultView:window).document);t instanceof e.HTMLIFrameElement;){try{var n="string"==typeof t.contentWindow.location.href}catch(r){n=!1}if(!n)break;t=pt((e=t.contentWindow).document)}return t}function tr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&("text"===e.type||"search"===e.type||"tel"===e.type||"url"===e.type||"password"===e.type)||"textarea"===t||"true"===e.contentEditable)}var nr=Mt&&"documentMode"in document&&11>=document.documentMode,rr=null,ar=null,or=null,ir=!1;function lr(e,t,n){var r=n.window===n?n.document:9===n.nodeType?n:n.ownerDocument;ir||null==rr||rr!==pt(r)||("selectionStart"in(r=rr)&&tr(r)?r={start:r.selectionStart,end:r.selectionEnd}:r={anchorNode:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection()).anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset},or&&Qn(or,r)||(or=r,0<(r=Vc(ar,"onSelect")).length&&(t=new Jt("onSelect","select",null,t,n),e.push({event:t,listeners:r}),t.target=rr)))}function sr(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit"+e]="webkit"+t,n["Moz"+e]="moz"+t,n}var ur={animationend:sr("Animation","AnimationEnd"),animationiteration:sr("Animation","AnimationIteration"),animationstart:sr("Animation","AnimationStart"),transitionrun:sr("Transition","TransitionRun"),transitionstart:sr("Transition","TransitionStart"),transitioncancel:sr("Transition","TransitionCancel"),transitionend:sr("Transition","TransitionEnd")},cr={},dr={};function fr(e){if(cr[e])return cr[e];if(!ur[e])return e;var t,n=ur[e];for(t in n)if(n.hasOwnProperty(t)&&t in dr)return cr[e]=n[t];return e}Mt&&(dr=document.createElement("div").style,"AnimationEvent"in window||(delete ur.animationend.animation,delete ur.animationiteration.animation,delete ur.animationstart.animation),"TransitionEvent"in window||delete ur.transitionend.transition);var pr=fr("animationend"),gr=fr("animationiteration"),hr=fr("animationstart"),mr=fr("transitionrun"),yr=fr("transitionstart"),br=fr("transitioncancel"),vr=fr("transitionend"),wr=new Map,kr="abort auxClick beforeToggle cancel canPlay canPlayThrough click close contextMenu copy cut drag dragEnd dragEnter dragExit dragLeave dragOver dragStart drop durationChange emptied encrypted ended error gotPointerCapture input invalid keyDown keyPress keyUp load loadedData loadedMetadata loadStart lostPointerCapture mouseDown mouseMove mouseOut mouseOver mouseUp paste pause play playing pointerCancel pointerDown pointerMove pointerOut pointerOver pointerUp progress rateChange reset resize seeked seeking stalled submit suspend timeUpdate touchCancel touchEnd touchStart volumeChange scroll toggle touchMove waiting wheel".split(" ");function xr(e,t){wr.set(e,t),Ye(t,[e])}kr.push("scrollEnd");var Sr=new WeakMap;function _r(e,t){if("object"==typeof e&&null!==e){var n=Sr.get(e);return void 0!==n?n:(t={value:e,source:t,stack:st(t)},Sr.set(e,t),t)}return{value:e,source:t,stack:st(t)}}var Er=[],Cr=0,Ar=0;function Tr(){for(var e=Cr,t=Ar=Cr=0;t>=i,a-=i,Zr=1<<32-pe(t)+a|n<o?o:8;var i,l,s,u=R.T,c={};R.T=c,$i(e,!1,t,n);try{var d=a(),f=R.S;if(null!==f&&f(c,d),null!==d&&"object"==typeof d&&"function"==typeof d.then)Bi(e,t,(i=r,l=[],s={status:"pending",value:null,reason:null,then:function(e){l.push(e)}},d.then(function(){s.status="fulfilled",s.value=i;for(var e=0;eg?(h=d,d=null):h=d.sibling;var m=p(a,d,l[g],s);if(null===m){null===d&&(d=h);break}e&&d&&null===m.alternate&&t(a,d),i=o(m,i,g),null===c?u=m:c.sibling=m,c=m,d=h}if(g===l.length)return n(a,d),oa&&Jr(a,g),u;if(null===d){for(;gh?(m=g,g=null):m=g.sibling;var v=p(a,g,b.value,u);if(null===v){null===g&&(g=m);break}e&&g&&null===v.alternate&&t(a,g),l=o(v,l,h),null===d?c=v:d.sibling=v,d=v,g=m}if(b.done)return n(a,g),oa&&Jr(a,h),c;if(null===g){for(;!b.done;h++,b=s.next())null!==(b=f(a,b.value,u))&&(l=o(b,l,h),null===d?c=b:d.sibling=b,d=b);return oa&&Jr(a,h),c}for(g=r(g);!b.done;h++,b=s.next())null!==(b=y(g,a,h,b.value,u))&&(e&&null!==b.alternate&&g.delete(null===b.key?h:b.key),l=o(b,l,h),null===d?c=b:d.sibling=b,d=b);return e&&g.forEach(function(e){return t(a,e)}),oa&&Jr(a,h),c}(s,u,c=v.call(c),d)}if("function"==typeof c.then)return b(s,u,Zi(c),d);if(c.$$typeof===k)return b(s,u,Aa(s,c),d);Ji(s,c)}return"string"==typeof c&&""!==c||"number"==typeof c||"bigint"==typeof c?(c=""+c,null!==u&&6===u.tag?(n(s,u.sibling),(d=a(u,c)).return=s,s=d):(n(s,u),(d=Ur(c,s.mode,d)).return=s,s=d),l(s)):n(s,u)}return function(e,t,n,r){try{Qi=0;var a=b(e,t,n,r);return Ki=null,a}catch(i){if(i===Wa||i===Ga)throw i;var o=Ir(29,i,null,e.mode);return o.lanes=r,o.return=e,o}}}var nl=tl(!0),rl=tl(!1),al=z(null),ol=null;function il(e){var t=e.alternate;$(cl,1&cl.current),$(al,e),null===ol&&(null===t||null!==go.current||null!==t.memoizedState)&&(ol=e)}function ll(e){if(22===e.tag){if($(cl,cl.current),$(al,e),null===ol){var t=e.alternate;null!==t&&null!==t.memoizedState&&(ol=e)}}else sl()}function sl(){$(cl,cl.current),$(al,al.current)}function ul(e){B(al),ol===e&&(ol=null),B(cl)}var cl=z(0);function dl(e){for(var t=e;null!==t;){if(13===t.tag){var n=t.memoizedState;if(null!==n&&(null===(n=n.dehydrated)||"$?"===n.data||md(n)))return t}else if(19===t.tag&&void 0!==t.memoizedProps.revealOrder){if(128&t.flags)return t}else if(null!==t.child){t.child.return=t,t=t.child;continue}if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}function fl(e,t,n,r){n=null==(n=n(r,t=e.memoizedState))?t:f({},t,n),e.memoizedState=n,0===e.lanes&&(e.updateQueue.baseState=n)}var pl={enqueueSetState:function(e,t,n){e=e._reactInternals;var r=Ru(),a=ao(r);a.payload=t,null!=n&&(a.callback=n),null!==(t=oo(e,a,r))&&(Iu(t,e,r),io(t,e,r))},enqueueReplaceState:function(e,t,n){e=e._reactInternals;var r=Ru(),a=ao(r);a.tag=1,a.payload=t,null!=n&&(a.callback=n),null!==(t=oo(e,a,r))&&(Iu(t,e,r),io(t,e,r))},enqueueForceUpdate:function(e,t){e=e._reactInternals;var n=Ru(),r=ao(n);r.tag=2,null!=t&&(r.callback=t),null!==(t=oo(e,r,n))&&(Iu(t,e,n),io(t,e,n))}};function gl(e,t,n,r,a,o,i){return"function"==typeof(e=e.stateNode).shouldComponentUpdate?e.shouldComponentUpdate(r,o,i):!t.prototype||!t.prototype.isPureReactComponent||(!Qn(n,r)||!Qn(a,o))}function hl(e,t,n,r){e=t.state,"function"==typeof t.componentWillReceiveProps&&t.componentWillReceiveProps(n,r),"function"==typeof t.UNSAFE_componentWillReceiveProps&&t.UNSAFE_componentWillReceiveProps(n,r),t.state!==e&&pl.enqueueReplaceState(t,t.state,null)}function ml(e,t){var n=t;if("ref"in t)for(var r in n={},t)"ref"!==r&&(n[r]=t[r]);if(e=e.defaultProps)for(var a in n===t&&(n=f({},n)),e)void 0===n[a]&&(n[a]=e[a]);return n}var yl="function"==typeof reportError?reportError:function(e){if("object"==typeof window&&"function"==typeof window.ErrorEvent){var t=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:"object"==typeof e&&null!==e&&"string"==typeof e.message?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if("object"==typeof process&&"function"==typeof process.emit)return void process.emit("uncaughtException",e);console.error(e)};function bl(e){yl(e)}function vl(e){console.error(e)}function wl(e){yl(e)}function kl(e,t){try{(0,e.onUncaughtError)(t.value,{componentStack:t.stack})}catch(n){setTimeout(function(){throw n})}}function xl(e,t,n){try{(0,e.onCaughtError)(n.value,{componentStack:n.stack,errorBoundary:1===t.tag?t.stateNode:null})}catch(r){setTimeout(function(){throw r})}}function Sl(e,t,n){return(n=ao(n)).tag=3,n.payload={element:null},n.callback=function(){kl(e,t)},n}function _l(e){return(e=ao(e)).tag=3,e}function El(e,t,n,r){var a=n.type.getDerivedStateFromError;if("function"==typeof a){var o=r.value;e.payload=function(){return a(o)},e.callback=function(){xl(t,n,r)}}var i=n.stateNode;null!==i&&"function"==typeof i.componentDidCatch&&(e.callback=function(){xl(t,n,r),"function"!=typeof a&&(null===_u?_u=new Set([this]):_u.add(this));var e=r.stack;this.componentDidCatch(r.value,{componentStack:null!==e?e:""})})}var Cl=Error(i(461)),Al=!1;function Tl(e,t,n,r){t.child=null===e?rl(t,null,n,r):nl(t,e.child,n,r)}function jl(e,t,n,r,a){n=n.render;var o=t.ref;if("ref"in r){var i={};for(var l in r)"ref"!==l&&(i[l]=r[l])}else i=r;return Ea(t),r=Oo(e,t,n,i,o,a),l=Io(),null===e||Al?(oa&&l&&ta(t),t.flags|=1,Tl(e,t,r,a),t.child):(Do(e,t,a),Kl(e,t,a))}function Pl(e,t,n,r,a){if(null===e){var o=n.type;return"function"!=typeof o||Dr(o)||void 0!==o.defaultProps||null!==n.compare?((e=Br(n.type,null,r,t,t.mode,a)).ref=t.ref,e.return=t,t.child=e):(t.tag=15,t.type=o,Nl(e,t,o,r,a))}if(o=e.child,!Ql(e,a)){var i=o.memoizedProps;if((n=null!==(n=n.compare)?n:Qn)(i,r)&&e.ref===t.ref)return Kl(e,t,a)}return t.flags|=1,(e=Mr(o,r)).ref=t.ref,e.return=t,t.child=e}function Nl(e,t,n,r,a){if(null!==e){var o=e.memoizedProps;if(Qn(o,r)&&e.ref===t.ref){if(Al=!1,t.pendingProps=r=o,!Ql(e,a))return t.lanes=e.lanes,Kl(e,t,a);131072&e.flags&&(Al=!0)}}return Fl(e,t,n,r,a)}function Ol(e,t,n){var r=t.pendingProps,a=r.children,o=null!==e?e.memoizedState:null;if("hidden"===r.mode){if(128&t.flags){if(r=null!==o?o.baseLanes|n:n,null!==e){for(a=t.child=e.child,o=0;null!==a;)o=o|a.lanes|a.childLanes,a=a.sibling;t.childLanes=o&~r}else t.childLanes=0,t.child=null;return Ll(e,t,r,n)}if(!(536870912&n))return t.lanes=t.childLanes=536870912,Ll(e,t,null!==o?o.baseLanes|n:n,n);t.memoizedState={baseLanes:0,cachePool:null},null!==e&&Ha(0,null!==o?o.cachePool:null),null!==o?mo(t,o):yo(),ll(t)}else null!==o?(Ha(0,o.cachePool),mo(t,o),sl(),t.memoizedState=null):(null!==e&&Ha(0,null),yo(),sl());return Tl(e,t,a,n),t.child}function Ll(e,t,n,r){var a=Ua();return a=null===a?null:{parent:Oa._currentValue,pool:a},t.memoizedState={baseLanes:n,cachePool:a},null!==e&&Ha(0,null),yo(),ll(t),null!==e&&Sa(e,t,r,!0),null}function Rl(e,t){var n=t.ref;if(null===n)null!==e&&null!==e.ref&&(t.flags|=4194816);else{if("function"!=typeof n&&"object"!=typeof n)throw Error(i(284));null!==e&&e.ref===n||(t.flags|=4194816)}}function Fl(e,t,n,r,a){return Ea(t),n=Oo(e,t,n,r,void 0,a),r=Io(),null===e||Al?(oa&&r&&ta(t),t.flags|=1,Tl(e,t,n,a),t.child):(Do(e,t,a),Kl(e,t,a))}function Il(e,t,n,r,a,o){return Ea(t),t.updateQueue=null,n=Ro(t,r,n,a),Lo(e),r=Io(),null===e||Al?(oa&&r&&ta(t),t.flags|=1,Tl(e,t,n,o),t.child):(Do(e,t,o),Kl(e,t,o))}function Dl(e,t,n,r,a){if(Ea(t),null===t.stateNode){var o=Rr,i=n.contextType;"object"==typeof i&&null!==i&&(o=Ca(i)),o=new n(r,o),t.memoizedState=null!==o.state&&void 0!==o.state?o.state:null,o.updater=pl,t.stateNode=o,o._reactInternals=t,(o=t.stateNode).props=r,o.state=t.memoizedState,o.refs={},no(t),i=n.contextType,o.context="object"==typeof i&&null!==i?Ca(i):Rr,o.state=t.memoizedState,"function"==typeof(i=n.getDerivedStateFromProps)&&(fl(t,n,i,r),o.state=t.memoizedState),"function"==typeof n.getDerivedStateFromProps||"function"==typeof o.getSnapshotBeforeUpdate||"function"!=typeof o.UNSAFE_componentWillMount&&"function"!=typeof o.componentWillMount||(i=o.state,"function"==typeof o.componentWillMount&&o.componentWillMount(),"function"==typeof o.UNSAFE_componentWillMount&&o.UNSAFE_componentWillMount(),i!==o.state&&pl.enqueueReplaceState(o,o.state,null),co(t,r,o,a),uo(),o.state=t.memoizedState),"function"==typeof o.componentDidMount&&(t.flags|=4194308),r=!0}else if(null===e){o=t.stateNode;var l=t.memoizedProps,s=ml(n,l);o.props=s;var u=o.context,c=n.contextType;i=Rr,"object"==typeof c&&null!==c&&(i=Ca(c));var d=n.getDerivedStateFromProps;c="function"==typeof d||"function"==typeof o.getSnapshotBeforeUpdate,l=t.pendingProps!==l,c||"function"!=typeof o.UNSAFE_componentWillReceiveProps&&"function"!=typeof o.componentWillReceiveProps||(l||u!==i)&&hl(t,o,r,i),to=!1;var f=t.memoizedState;o.state=f,co(t,r,o,a),uo(),u=t.memoizedState,l||f!==u||to?("function"==typeof d&&(fl(t,n,d,r),u=t.memoizedState),(s=to||gl(t,n,s,r,f,u,i))?(c||"function"!=typeof o.UNSAFE_componentWillMount&&"function"!=typeof o.componentWillMount||("function"==typeof o.componentWillMount&&o.componentWillMount(),"function"==typeof o.UNSAFE_componentWillMount&&o.UNSAFE_componentWillMount()),"function"==typeof o.componentDidMount&&(t.flags|=4194308)):("function"==typeof o.componentDidMount&&(t.flags|=4194308),t.memoizedProps=r,t.memoizedState=u),o.props=r,o.state=u,o.context=i,r=s):("function"==typeof o.componentDidMount&&(t.flags|=4194308),r=!1)}else{o=t.stateNode,ro(e,t),c=ml(n,i=t.memoizedProps),o.props=c,d=t.pendingProps,f=o.context,u=n.contextType,s=Rr,"object"==typeof u&&null!==u&&(s=Ca(u)),(u="function"==typeof(l=n.getDerivedStateFromProps)||"function"==typeof o.getSnapshotBeforeUpdate)||"function"!=typeof o.UNSAFE_componentWillReceiveProps&&"function"!=typeof o.componentWillReceiveProps||(i!==d||f!==s)&&hl(t,o,r,s),to=!1,f=t.memoizedState,o.state=f,co(t,r,o,a),uo();var p=t.memoizedState;i!==d||f!==p||to||null!==e&&null!==e.dependencies&&_a(e.dependencies)?("function"==typeof l&&(fl(t,n,l,r),p=t.memoizedState),(c=to||gl(t,n,c,r,f,p,s)||null!==e&&null!==e.dependencies&&_a(e.dependencies))?(u||"function"!=typeof o.UNSAFE_componentWillUpdate&&"function"!=typeof o.componentWillUpdate||("function"==typeof o.componentWillUpdate&&o.componentWillUpdate(r,p,s),"function"==typeof o.UNSAFE_componentWillUpdate&&o.UNSAFE_componentWillUpdate(r,p,s)),"function"==typeof o.componentDidUpdate&&(t.flags|=4),"function"==typeof o.getSnapshotBeforeUpdate&&(t.flags|=1024)):("function"!=typeof o.componentDidUpdate||i===e.memoizedProps&&f===e.memoizedState||(t.flags|=4),"function"!=typeof o.getSnapshotBeforeUpdate||i===e.memoizedProps&&f===e.memoizedState||(t.flags|=1024),t.memoizedProps=r,t.memoizedState=p),o.props=r,o.state=p,o.context=s,r=c):("function"!=typeof o.componentDidUpdate||i===e.memoizedProps&&f===e.memoizedState||(t.flags|=4),"function"!=typeof o.getSnapshotBeforeUpdate||i===e.memoizedProps&&f===e.memoizedState||(t.flags|=1024),r=!1)}return o=r,Rl(e,t),r=!!(128&t.flags),o||r?(o=t.stateNode,n=r&&"function"!=typeof n.getDerivedStateFromError?null:o.render(),t.flags|=1,null!==e&&r?(t.child=nl(t,e.child,null,a),t.child=nl(t,null,n,a)):Tl(e,t,n,a),t.memoizedState=o.state,e=t.child):e=Kl(e,t,a),e}function Ml(e,t,n,r){return pa(),t.flags|=256,Tl(e,t,n,r),t.child}var zl={dehydrated:null,treeContext:null,retryLane:0,hydrationErrors:null};function Bl(e){return{baseLanes:e,cachePool:Va()}}function $l(e,t,n){return e=null!==e?e.childLanes&~n:0,t&&(e|=mu),e}function Ul(e,t,n){var r,a=t.pendingProps,o=!1,l=!!(128&t.flags);if((r=l)||(r=(null===e||null!==e.memoizedState)&&!!(2&cl.current)),r&&(o=!0,t.flags&=-129),r=!!(32&t.flags),t.flags&=-33,null===e){if(oa){if(o?il(t):sl(),oa){var s,u=aa;if(s=u){e:{for(s=u,u=la;8!==s.nodeType;){if(!u){u=null;break e}if(null===(s=yd(s.nextSibling))){u=null;break e}}u=s}null!==u?(t.memoizedState={dehydrated:u,treeContext:null!==Qr?{id:Zr,overflow:Xr}:null,retryLane:536870912,hydrationErrors:null},(s=Ir(18,null,null,0)).stateNode=u,s.return=t,t.child=s,ra=t,aa=null,s=!0):s=!1}s||ua(t)}if(null!==(u=t.memoizedState)&&null!==(u=u.dehydrated))return md(u)?t.lanes=32:t.lanes=536870912,null;ul(t)}return u=a.children,a=a.fallback,o?(sl(),u=Vl({mode:"hidden",children:u},o=t.mode),a=$r(a,o,n,null),u.return=t,a.return=t,u.sibling=a,t.child=u,(o=t.child).memoizedState=Bl(n),o.childLanes=$l(e,r,n),t.memoizedState=zl,a):(il(t),Hl(t,u))}if(null!==(s=e.memoizedState)&&null!==(u=s.dehydrated)){if(l)256&t.flags?(il(t),t.flags&=-257,t=Wl(e,t,n)):null!==t.memoizedState?(sl(),t.child=e.child,t.flags|=128,t=null):(sl(),o=a.fallback,u=t.mode,a=Vl({mode:"visible",children:a.children},u),(o=$r(o,u,n,null)).flags|=2,a.return=t,o.return=t,a.sibling=o,t.child=a,nl(t,e.child,null,n),(a=t.child).memoizedState=Bl(n),a.childLanes=$l(e,r,n),t.memoizedState=zl,t=o);else if(il(t),md(u)){if(r=u.nextSibling&&u.nextSibling.dataset)var c=r.dgst;r=c,(a=Error(i(419))).stack="",a.digest=r,ha({value:a,source:null,stack:null}),t=Wl(e,t,n)}else if(Al||Sa(e,t,n,!1),r=0!==(n&e.childLanes),Al||r){if(null!==(r=ru)&&(0!==(a=0!==((a=42&(a=n&-n)?1:Te(a))&(r.suspendedLanes|n))?0:a)&&a!==s.retryLane))throw s.retryLane=a,Nr(e,a),Iu(r,e,a),Cl;"$?"===u.data||Gu(),t=Wl(e,t,n)}else"$?"===u.data?(t.flags|=192,t.child=e.child,t=null):(e=s.treeContext,aa=yd(u.nextSibling),ra=t,oa=!0,ia=null,la=!1,null!==e&&(Yr[Kr++]=Zr,Yr[Kr++]=Xr,Yr[Kr++]=Qr,Zr=e.id,Xr=e.overflow,Qr=t),(t=Hl(t,a.children)).flags|=4096);return t}return o?(sl(),o=a.fallback,u=t.mode,c=(s=e.child).sibling,(a=Mr(s,{mode:"hidden",children:a.children})).subtreeFlags=65011712&s.subtreeFlags,null!==c?o=Mr(c,o):(o=$r(o,u,n,null)).flags|=2,o.return=t,a.return=t,a.sibling=o,t.child=a,a=o,o=t.child,null===(u=e.child.memoizedState)?u=Bl(n):(null!==(s=u.cachePool)?(c=Oa._currentValue,s=s.parent!==c?{parent:c,pool:c}:s):s=Va(),u={baseLanes:u.baseLanes|n,cachePool:s}),o.memoizedState=u,o.childLanes=$l(e,r,n),t.memoizedState=zl,a):(il(t),e=(n=e.child).sibling,(n=Mr(n,{mode:"visible",children:a.children})).return=t,n.sibling=null,null!==e&&(null===(r=t.deletions)?(t.deletions=[e],t.flags|=16):r.push(e)),t.child=n,t.memoizedState=null,n)}function Hl(e,t){return(t=Vl({mode:"visible",children:t},e.mode)).return=e,e.child=t}function Vl(e,t){return(e=Ir(22,e,null,t)).lanes=0,e.stateNode={_visibility:1,_pendingMarkers:null,_retryCache:null,_transitions:null},e}function Wl(e,t,n){return nl(t,e.child,null,n),(e=Hl(t,t.pendingProps.children)).flags|=2,t.memoizedState=null,e}function ql(e,t,n){e.lanes|=t;var r=e.alternate;null!==r&&(r.lanes|=t),ka(e.return,t,n)}function Gl(e,t,n,r,a){var o=e.memoizedState;null===o?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:r,tail:n,tailMode:a}:(o.isBackwards=t,o.rendering=null,o.renderingStartTime=0,o.last=r,o.tail=n,o.tailMode=a)}function Yl(e,t,n){var r=t.pendingProps,a=r.revealOrder,o=r.tail;if(Tl(e,t,r.children,n),2&(r=cl.current))r=1&r|2,t.flags|=128;else{if(null!==e&&128&e.flags)e:for(e=t.child;null!==e;){if(13===e.tag)null!==e.memoizedState&&ql(e,n,t);else if(19===e.tag)ql(e,n,t);else if(null!==e.child){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;null===e.sibling;){if(null===e.return||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}switch($(cl,r),a){case"forwards":for(n=t.child,a=null;null!==n;)null!==(e=n.alternate)&&null===dl(e)&&(a=n),n=n.sibling;null===(n=a)?(a=t.child,t.child=null):(a=n.sibling,n.sibling=null),Gl(t,!1,a,n,o);break;case"backwards":for(n=null,a=t.child,t.child=null;null!==a;){if(null!==(e=a.alternate)&&null===dl(e)){t.child=a;break}e=a.sibling,a.sibling=n,n=a,a=e}Gl(t,!0,n,null,o);break;case"together":Gl(t,!1,null,null,void 0);break;default:t.memoizedState=null}return t.child}function Kl(e,t,n){if(null!==e&&(t.dependencies=e.dependencies),pu|=t.lanes,0===(n&t.childLanes)){if(null===e)return null;if(Sa(e,t,n,!1),0===(n&t.childLanes))return null}if(null!==e&&t.child!==e.child)throw Error(i(153));if(null!==t.child){for(n=Mr(e=t.child,e.pendingProps),t.child=n,n.return=t;null!==e.sibling;)e=e.sibling,(n=n.sibling=Mr(e,e.pendingProps)).return=t;n.sibling=null}return t.child}function Ql(e,t){return 0!==(e.lanes&t)||!(null===(e=e.dependencies)||!_a(e))}function Zl(e,t,n){if(null!==e)if(e.memoizedProps!==t.pendingProps)Al=!0;else{if(!(Ql(e,n)||128&t.flags))return Al=!1,function(e,t,n){switch(t.tag){case 3:q(t,t.stateNode.containerInfo),va(0,Oa,e.memoizedState.cache),pa();break;case 27:case 5:Y(t);break;case 4:q(t,t.stateNode.containerInfo);break;case 10:va(0,t.type,t.memoizedProps.value);break;case 13:var r=t.memoizedState;if(null!==r)return null!==r.dehydrated?(il(t),t.flags|=128,null):0!==(n&t.child.childLanes)?Ul(e,t,n):(il(t),null!==(e=Kl(e,t,n))?e.sibling:null);il(t);break;case 19:var a=!!(128&e.flags);if((r=0!==(n&t.childLanes))||(Sa(e,t,n,!1),r=0!==(n&t.childLanes)),a){if(r)return Yl(e,t,n);t.flags|=128}if(null!==(a=t.memoizedState)&&(a.rendering=null,a.tail=null,a.lastEffect=null),$(cl,cl.current),r)break;return null;case 22:case 23:return t.lanes=0,Ol(e,t,n);case 24:va(0,Oa,e.memoizedState.cache)}return Kl(e,t,n)}(e,t,n);Al=!!(131072&e.flags)}else Al=!1,oa&&1048576&t.flags&&ea(t,Gr,t.index);switch(t.lanes=0,t.tag){case 16:e:{e=t.pendingProps;var r=t.elementType,a=r._init;if(r=a(r._payload),t.type=r,"function"!=typeof r){if(null!=r){if((a=r.$$typeof)===x){t.tag=11,t=jl(null,t,r,e,n);break e}if(a===E){t.tag=14,t=Pl(null,t,r,e,n);break e}}throw t=O(r)||r,Error(i(306,t,""))}Dr(r)?(e=ml(r,e),t.tag=1,t=Dl(null,t,r,e,n)):(t.tag=0,t=Fl(null,t,r,e,n))}return t;case 0:return Fl(e,t,t.type,t.pendingProps,n);case 1:return Dl(e,t,r=t.type,a=ml(r,t.pendingProps),n);case 3:e:{if(q(t,t.stateNode.containerInfo),null===e)throw Error(i(387));r=t.pendingProps;var o=t.memoizedState;a=o.element,ro(e,t),co(t,r,null,n);var l=t.memoizedState;if(r=l.cache,va(0,Oa,r),r!==o.cache&&xa(t,[Oa],n,!0),uo(),r=l.element,o.isDehydrated){if(o={element:r,isDehydrated:!1,cache:l.cache},t.updateQueue.baseState=o,t.memoizedState=o,256&t.flags){t=Ml(e,t,r,n);break e}if(r!==a){ha(a=_r(Error(i(424)),t)),t=Ml(e,t,r,n);break e}if(9===(e=t.stateNode.containerInfo).nodeType)e=e.body;else e="HTML"===e.nodeName?e.ownerDocument.body:e;for(aa=yd(e.firstChild),ra=t,oa=!0,ia=null,la=!0,n=rl(t,null,r,n),t.child=n;n;)n.flags=-3&n.flags|4096,n=n.sibling}else{if(pa(),r===a){t=Kl(e,t,n);break e}Tl(e,t,r,n)}t=t.child}return t;case 26:return Rl(e,t),null===e?(n=Td(t.type,null,t.pendingProps,null))?t.memoizedState=n:oa||(n=t.type,e=t.pendingProps,(r=rd(V.current).createElement(n))[Oe]=t,r[Le]=e,ed(r,n,e),We(r),t.stateNode=r):t.memoizedState=Td(t.type,e.memoizedProps,t.pendingProps,e.memoizedState),null;case 27:return Y(t),null===e&&oa&&(r=t.stateNode=wd(t.type,t.pendingProps,V.current),ra=t,la=!0,a=aa,pd(t.type)?(bd=a,aa=yd(r.firstChild)):aa=a),Tl(e,t,t.pendingProps.children,n),Rl(e,t),null===e&&(t.flags|=4194304),t.child;case 5:return null===e&&oa&&((a=r=aa)&&(null!==(r=function(e,t,n,r){for(;1===e.nodeType;){var a=n;if(e.nodeName.toLowerCase()!==t.toLowerCase()){if(!r&&("INPUT"!==e.nodeName||"hidden"!==e.type))break}else if(r){if(!e[ze])switch(t){case"meta":if(!e.hasAttribute("itemprop"))break;return e;case"link":if("stylesheet"===(o=e.getAttribute("rel"))&&e.hasAttribute("data-precedence"))break;if(o!==a.rel||e.getAttribute("href")!==(null==a.href||""===a.href?null:a.href)||e.getAttribute("crossorigin")!==(null==a.crossOrigin?null:a.crossOrigin)||e.getAttribute("title")!==(null==a.title?null:a.title))break;return e;case"style":if(e.hasAttribute("data-precedence"))break;return e;case"script":if(((o=e.getAttribute("src"))!==(null==a.src?null:a.src)||e.getAttribute("type")!==(null==a.type?null:a.type)||e.getAttribute("crossorigin")!==(null==a.crossOrigin?null:a.crossOrigin))&&o&&e.hasAttribute("async")&&!e.hasAttribute("itemprop"))break;return e;default:return e}}else{if("input"!==t||"hidden"!==e.type)return e;var o=null==a.name?null:""+a.name;if("hidden"===a.type&&e.getAttribute("name")===o)return e}if(null===(e=yd(e.nextSibling)))break}return null}(r,t.type,t.pendingProps,la))?(t.stateNode=r,ra=t,aa=yd(r.firstChild),la=!1,a=!0):a=!1),a||ua(t)),Y(t),a=t.type,o=t.pendingProps,l=null!==e?e.memoizedProps:null,r=o.children,id(a,o)?r=null:null!==l&&id(a,l)&&(t.flags|=32),null!==t.memoizedState&&(a=Oo(e,t,Fo,null,null,n),Yd._currentValue=a),Rl(e,t),Tl(e,t,r,n),t.child;case 6:return null===e&&oa&&((e=n=aa)&&(null!==(n=function(e,t,n){if(""===t)return null;for(;3!==e.nodeType;){if((1!==e.nodeType||"INPUT"!==e.nodeName||"hidden"!==e.type)&&!n)return null;if(null===(e=yd(e.nextSibling)))return null}return e}(n,t.pendingProps,la))?(t.stateNode=n,ra=t,aa=null,e=!0):e=!1),e||ua(t)),null;case 13:return Ul(e,t,n);case 4:return q(t,t.stateNode.containerInfo),r=t.pendingProps,null===e?t.child=nl(t,null,r,n):Tl(e,t,r,n),t.child;case 11:return jl(e,t,t.type,t.pendingProps,n);case 7:return Tl(e,t,t.pendingProps,n),t.child;case 8:case 12:return Tl(e,t,t.pendingProps.children,n),t.child;case 10:return r=t.pendingProps,va(0,t.type,r.value),Tl(e,t,r.children,n),t.child;case 9:return a=t.type._context,r=t.pendingProps.children,Ea(t),r=r(a=Ca(a)),t.flags|=1,Tl(e,t,r,n),t.child;case 14:return Pl(e,t,t.type,t.pendingProps,n);case 15:return Nl(e,t,t.type,t.pendingProps,n);case 19:return Yl(e,t,n);case 31:return r=t.pendingProps,n=t.mode,r={mode:r.mode,children:r.children},null===e?((n=Vl(r,n)).ref=t.ref,t.child=n,n.return=t,t=n):((n=Mr(e.child,r)).ref=t.ref,t.child=n,n.return=t,t=n),t;case 22:return Ol(e,t,n);case 24:return Ea(t),r=Ca(Oa),null===e?(null===(a=Ua())&&(a=ru,o=La(),a.pooledCache=o,o.refCount++,null!==o&&(a.pooledCacheLanes|=n),a=o),t.memoizedState={parent:r,cache:a},no(t),va(0,Oa,a)):(0!==(e.lanes&n)&&(ro(e,t),co(t,null,null,n),uo()),a=e.memoizedState,o=t.memoizedState,a.parent!==r?(a={parent:r,cache:r},t.memoizedState=a,0===t.lanes&&(t.memoizedState=t.updateQueue.baseState=a),va(0,Oa,r)):(r=o.cache,va(0,Oa,r),r!==a.cache&&xa(t,[Oa],n,!0))),Tl(e,t,t.pendingProps.children,n),t.child;case 29:throw t.pendingProps}throw Error(i(156,t.tag))}function Xl(e){e.flags|=4}function Jl(e,t){if("stylesheet"!==t.type||4&t.state.loading)e.flags&=-16777217;else if(e.flags|=16777216,!$d(t)){if(null!==(t=al.current)&&((4194048&ou)===ou?null!==ol:(62914560&ou)!==ou&&!(536870912&ou)||t!==ol))throw Xa=Ya,qa;e.flags|=8192}}function es(e,t){null!==t&&(e.flags|=4),16384&e.flags&&(t=22!==e.tag?Se():536870912,e.lanes|=t,yu|=t)}function ts(e,t){if(!oa)switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;null!==t;)null!==t.alternate&&(n=t),t=t.sibling;null===n?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var r=null;null!==n;)null!==n.alternate&&(r=n),n=n.sibling;null===r?t||null===e.tail?e.tail=null:e.tail.sibling=null:r.sibling=null}}function ns(e){var t=null!==e.alternate&&e.alternate.child===e.child,n=0,r=0;if(t)for(var a=e.child;null!==a;)n|=a.lanes|a.childLanes,r|=65011712&a.subtreeFlags,r|=65011712&a.flags,a.return=e,a=a.sibling;else for(a=e.child;null!==a;)n|=a.lanes|a.childLanes,r|=a.subtreeFlags,r|=a.flags,a.return=e,a=a.sibling;return e.subtreeFlags|=r,e.childLanes=n,t}function rs(e,t,n){var r=t.pendingProps;switch(na(t),t.tag){case 31:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:case 1:return ns(t),null;case 3:return n=t.stateNode,r=null,null!==e&&(r=e.memoizedState.cache),t.memoizedState.cache!==r&&(t.flags|=2048),wa(Oa),G(),n.pendingContext&&(n.context=n.pendingContext,n.pendingContext=null),null!==e&&null!==e.child||(fa(t)?Xl(t):null===e||e.memoizedState.isDehydrated&&!(256&t.flags)||(t.flags|=1024,ga())),ns(t),null;case 26:return n=t.memoizedState,null===e?(Xl(t),null!==n?(ns(t),Jl(t,n)):(ns(t),t.flags&=-16777217)):n?n!==e.memoizedState?(Xl(t),ns(t),Jl(t,n)):(ns(t),t.flags&=-16777217):(e.memoizedProps!==r&&Xl(t),ns(t),t.flags&=-16777217),null;case 27:K(t),n=V.current;var a=t.type;if(null!==e&&null!=t.stateNode)e.memoizedProps!==r&&Xl(t);else{if(!r){if(null===t.stateNode)throw Error(i(166));return ns(t),null}e=U.current,fa(t)?ca(t):(e=wd(a,r,n),t.stateNode=e,Xl(t))}return ns(t),null;case 5:if(K(t),n=t.type,null!==e&&null!=t.stateNode)e.memoizedProps!==r&&Xl(t);else{if(!r){if(null===t.stateNode)throw Error(i(166));return ns(t),null}if(e=U.current,fa(t))ca(t);else{switch(a=rd(V.current),e){case 1:e=a.createElementNS("http://www.w3.org/2000/svg",n);break;case 2:e=a.createElementNS("http://www.w3.org/1998/Math/MathML",n);break;default:switch(n){case"svg":e=a.createElementNS("http://www.w3.org/2000/svg",n);break;case"math":e=a.createElementNS("http://www.w3.org/1998/Math/MathML",n);break;case"script":(e=a.createElement("div")).innerHTML=" - + + diff --git a/doc/statepulse-doc/build/blog/atom.css b/doc/build/blog/atom.css similarity index 100% rename from doc/statepulse-doc/build/blog/atom.css rename to doc/build/blog/atom.css diff --git a/doc/statepulse-doc/build/blog/atom.xml b/doc/build/blog/atom.xml similarity index 100% rename from doc/statepulse-doc/build/blog/atom.xml rename to doc/build/blog/atom.xml diff --git a/doc/statepulse-doc/build/blog/atom.xsl b/doc/build/blog/atom.xsl similarity index 100% rename from doc/statepulse-doc/build/blog/atom.xsl rename to doc/build/blog/atom.xsl diff --git a/doc/statepulse-doc/build/blog/authors/index.html b/doc/build/blog/authors/index.html similarity index 98% rename from doc/statepulse-doc/build/blog/authors/index.html rename to doc/build/blog/authors/index.html index 0be024b..87fc766 100644 --- a/doc/statepulse-doc/build/blog/authors/index.html +++ b/doc/build/blog/authors/index.html @@ -5,8 +5,8 @@ Authors | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/blog/authors/mshimshon/index.html b/doc/build/blog/authors/mshimshon/index.html similarity index 99% rename from doc/statepulse-doc/build/blog/authors/mshimshon/index.html rename to doc/build/blog/authors/mshimshon/index.html index 419ea29..87e829d 100644 --- a/doc/statepulse-doc/build/blog/authors/mshimshon/index.html +++ b/doc/build/blog/authors/mshimshon/index.html @@ -5,8 +5,8 @@ Maksim Shimshon - One post | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/blog/first-blog-post/index.html b/doc/build/blog/first-blog-post/index.html similarity index 99% rename from doc/statepulse-doc/build/blog/first-blog-post/index.html rename to doc/build/blog/first-blog-post/index.html index 069d0f4..2cb4cc7 100644 --- a/doc/statepulse-doc/build/blog/first-blog-post/index.html +++ b/doc/build/blog/first-blog-post/index.html @@ -5,8 +5,8 @@ First Blog Post | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/blog/index.html b/doc/build/blog/index.html similarity index 99% rename from doc/statepulse-doc/build/blog/index.html rename to doc/build/blog/index.html index f4c5fc4..473bc0d 100644 --- a/doc/statepulse-doc/build/blog/index.html +++ b/doc/build/blog/index.html @@ -5,8 +5,8 @@ Blog | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/blog/rss.css b/doc/build/blog/rss.css similarity index 100% rename from doc/statepulse-doc/build/blog/rss.css rename to doc/build/blog/rss.css diff --git a/doc/statepulse-doc/build/blog/rss.xml b/doc/build/blog/rss.xml similarity index 100% rename from doc/statepulse-doc/build/blog/rss.xml rename to doc/build/blog/rss.xml diff --git a/doc/statepulse-doc/build/blog/rss.xsl b/doc/build/blog/rss.xsl similarity index 100% rename from doc/statepulse-doc/build/blog/rss.xsl rename to doc/build/blog/rss.xsl diff --git a/doc/statepulse-doc/build/blog/tags/docusaurus/index.html b/doc/build/blog/tags/docusaurus/index.html similarity index 99% rename from doc/statepulse-doc/build/blog/tags/docusaurus/index.html rename to doc/build/blog/tags/docusaurus/index.html index 5e78df5..c2c7609 100644 --- a/doc/statepulse-doc/build/blog/tags/docusaurus/index.html +++ b/doc/build/blog/tags/docusaurus/index.html @@ -5,8 +5,8 @@ One post tagged with "Docusaurus" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/blog/tags/hola/index.html b/doc/build/blog/tags/hola/index.html similarity index 99% rename from doc/statepulse-doc/build/blog/tags/hola/index.html rename to doc/build/blog/tags/hola/index.html index 693a9e6..8d11261 100644 --- a/doc/statepulse-doc/build/blog/tags/hola/index.html +++ b/doc/build/blog/tags/hola/index.html @@ -5,8 +5,8 @@ One post tagged with "Hola" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/blog/tags/index.html b/doc/build/blog/tags/index.html similarity index 98% rename from doc/statepulse-doc/build/blog/tags/index.html rename to doc/build/blog/tags/index.html index b6a0616..0c1753c 100644 --- a/doc/statepulse-doc/build/blog/tags/index.html +++ b/doc/build/blog/tags/index.html @@ -5,8 +5,8 @@ Tags | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/gs-state/index.html b/doc/build/gs-state/index.html similarity index 99% rename from doc/statepulse-doc/build/gs-state/index.html rename to doc/build/gs-state/index.html index d55f3dc..77922e2 100644 --- a/doc/statepulse-doc/build/gs-state/index.html +++ b/doc/build/gs-state/index.html @@ -5,8 +5,8 @@ The States | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/gs-the-action/index.html b/doc/build/gs-the-action/index.html similarity index 99% rename from doc/statepulse-doc/build/gs-the-action/index.html rename to doc/build/gs-the-action/index.html index 8b4a294..65117e2 100644 --- a/doc/statepulse-doc/build/gs-the-action/index.html +++ b/doc/build/gs-the-action/index.html @@ -5,8 +5,8 @@ The Actions | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/gs-the-dispatcher/index.html b/doc/build/gs-the-dispatcher/index.html similarity index 99% rename from doc/statepulse-doc/build/gs-the-dispatcher/index.html rename to doc/build/gs-the-dispatcher/index.html index 5c31378..5249f85 100644 --- a/doc/statepulse-doc/build/gs-the-dispatcher/index.html +++ b/doc/build/gs-the-dispatcher/index.html @@ -5,8 +5,8 @@ The Dispatcher | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/gs-the-effect/index.html b/doc/build/gs-the-effect/index.html similarity index 99% rename from doc/statepulse-doc/build/gs-the-effect/index.html rename to doc/build/gs-the-effect/index.html index 76de1e0..eaa193e 100644 --- a/doc/statepulse-doc/build/gs-the-effect/index.html +++ b/doc/build/gs-the-effect/index.html @@ -5,8 +5,8 @@ The Effects | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/gs-the-middlewares/index.html b/doc/build/gs-the-middlewares/index.html similarity index 92% rename from doc/statepulse-doc/build/gs-the-middlewares/index.html rename to doc/build/gs-the-middlewares/index.html index d8a6fea..e6e7b5a 100644 --- a/doc/statepulse-doc/build/gs-the-middlewares/index.html +++ b/doc/build/gs-the-middlewares/index.html @@ -5,8 +5,8 @@ The Middlewares | StatePulse.NET - - + + @@ -50,6 +50,6 @@

🧼 Use CasesπŸ“Š Tracking user behavior
  • ⏱️ Measuring performance metrics
  • πŸ“ˆ Collecting analytics without mutating state or logic
  • -
    +
    \ No newline at end of file diff --git a/doc/statepulse-doc/build/gs-the-reducer/index.html b/doc/build/gs-the-reducer/index.html similarity index 99% rename from doc/statepulse-doc/build/gs-the-reducer/index.html rename to doc/build/gs-the-reducer/index.html index 3392955..e25b822 100644 --- a/doc/statepulse-doc/build/gs-the-reducer/index.html +++ b/doc/build/gs-the-reducer/index.html @@ -5,8 +5,8 @@ The Reducers | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/img/docusaurus-social-card.jpg b/doc/build/img/docusaurus-social-card.jpg similarity index 100% rename from doc/statepulse-doc/build/img/docusaurus-social-card.jpg rename to doc/build/img/docusaurus-social-card.jpg diff --git a/doc/statepulse-doc/build/img/docusaurus.png b/doc/build/img/docusaurus.png similarity index 100% rename from doc/statepulse-doc/build/img/docusaurus.png rename to doc/build/img/docusaurus.png diff --git a/doc/statepulse-doc/build/img/favicon.ico b/doc/build/img/favicon.ico similarity index 100% rename from doc/statepulse-doc/build/img/favicon.ico rename to doc/build/img/favicon.ico diff --git a/doc/statepulse-doc/build/img/icon.png b/doc/build/img/icon.png similarity index 100% rename from doc/statepulse-doc/build/img/icon.png rename to doc/build/img/icon.png diff --git a/doc/statepulse-doc/build/img/logo.svg b/doc/build/img/logo.svg similarity index 100% rename from doc/statepulse-doc/build/img/logo.svg rename to doc/build/img/logo.svg diff --git a/doc/statepulse-doc/build/img/nuget-logo.png b/doc/build/img/nuget-logo.png similarity index 100% rename from doc/statepulse-doc/build/img/nuget-logo.png rename to doc/build/img/nuget-logo.png diff --git a/doc/statepulse-doc/build/img/undraw_docusaurus_mountain.svg b/doc/build/img/undraw_docusaurus_mountain.svg similarity index 100% rename from doc/statepulse-doc/build/img/undraw_docusaurus_mountain.svg rename to doc/build/img/undraw_docusaurus_mountain.svg diff --git a/doc/statepulse-doc/build/img/undraw_docusaurus_react.svg b/doc/build/img/undraw_docusaurus_react.svg similarity index 100% rename from doc/statepulse-doc/build/img/undraw_docusaurus_react.svg rename to doc/build/img/undraw_docusaurus_react.svg diff --git a/doc/statepulse-doc/build/img/undraw_docusaurus_tree.svg b/doc/build/img/undraw_docusaurus_tree.svg similarity index 100% rename from doc/statepulse-doc/build/img/undraw_docusaurus_tree.svg rename to doc/build/img/undraw_docusaurus_tree.svg diff --git a/doc/statepulse-doc/build/index.html b/doc/build/index.html similarity index 99% rename from doc/statepulse-doc/build/index.html rename to doc/build/index.html index dcb6a11..c4c1f2f 100644 --- a/doc/statepulse-doc/build/index.html +++ b/doc/build/index.html @@ -5,8 +5,8 @@ Get Started | StatePulse.NET - - + + @@ -62,6 +62,6 @@

    Important No

    Access State:​

    var stateAccessor = ServiceProvider.GetRequiredService<IStateAccessor<ProfileCardState>>();

    Blazor Example Usage​

    -
    using StatePulse.Net;

    public partial class CounterView : ComponentBase
    {

    // METHOD 1:
    [Inject] public IStatePulse PulseState { get; set; } = default!; // Handles State Accessor

    // This is for convienience always use this method or directly PulseState.StateOf<CounterState>(this).Value
    // Never assign State Instance variable as it will not update...
    // Never use lambda it will throw exception as WeakREference is fundamatally flawed and disposes of lambda even when its object is alive.
    private CounterState state => PulseState.StateOf<CounterState>(()=>this, OnUpdate);

    private async Task OnUpdate() => await InvokeAsync(StateHadChanged);

    // METHOD 2:
    // Inject direct state but injecting the state directly requires you to handle onchanged events by sub/unsub in lifecycle
    // Or to create a basecomponent system similar to other state management systems.
    [Inject] public IStateAccessor<CounterState> State { get; set; } = default!;


    }
    +
    using StatePulse.Net;

    public partial class CounterView : ComponentBase
    {

    // METHOD 1:
    [Inject] public IStatePulse PulseState { get; set; } = default!; // Handles State Accessor

    // This is for convienience always use this method or directly PulseState.StateOf<CounterState>(this).Value
    // Never assign State Instance variable as it will not update...
    // Never use lambda it will throw exception as WeakREference is fundamatally flawed and disposes of lambda even when its object is alive.
    private CounterState state => PulseState.StateOf<CounterState>(()=>this, OnUpdate);

    private async Task OnUpdate() => await InvokeAsync(StateHasChanged);

    // METHOD 2:
    // Inject direct state but injecting the state directly requires you to handle onchanged events by sub/unsub in lifecycle
    // Or to create a basecomponent system similar to other state management systems.
    [Inject] public IStateAccessor<CounterState> State { get; set; } = default!;


    }
    \ No newline at end of file diff --git a/doc/statepulse-doc/build/markdown-page/index.html b/doc/build/markdown-page/index.html similarity index 98% rename from doc/statepulse-doc/build/markdown-page/index.html rename to doc/build/markdown-page/index.html index d7cd7d1..56f57d7 100644 --- a/doc/statepulse-doc/build/markdown-page/index.html +++ b/doc/build/markdown-page/index.html @@ -5,8 +5,8 @@ Markdown page example | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/setup-blazor-project/index.html b/doc/build/setup-blazor-project/index.html similarity index 99% rename from doc/statepulse-doc/build/setup-blazor-project/index.html rename to doc/build/setup-blazor-project/index.html index c058e51..714f104 100644 --- a/doc/statepulse-doc/build/setup-blazor-project/index.html +++ b/doc/build/setup-blazor-project/index.html @@ -5,8 +5,8 @@ Setup Blazor Project | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/sitemap.xml b/doc/build/sitemap.xml similarity index 100% rename from doc/statepulse-doc/build/sitemap.xml rename to doc/build/sitemap.xml diff --git a/doc/statepulse-doc/build/tags/actions/index.html b/doc/build/tags/actions/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/actions/index.html rename to doc/build/tags/actions/index.html index b7aab30..2e85ee2 100644 --- a/doc/statepulse-doc/build/tags/actions/index.html +++ b/doc/build/tags/actions/index.html @@ -5,8 +5,8 @@ 2 docs tagged with "actions" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/async/index.html b/doc/build/tags/async/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/async/index.html rename to doc/build/tags/async/index.html index c6ef48f..d0c2976 100644 --- a/doc/statepulse-doc/build/tags/async/index.html +++ b/doc/build/tags/async/index.html @@ -5,8 +5,8 @@ 4 docs tagged with "async" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/await/index.html b/doc/build/tags/await/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/await/index.html rename to doc/build/tags/await/index.html index 37162e4..aa56b72 100644 --- a/doc/statepulse-doc/build/tags/await/index.html +++ b/doc/build/tags/await/index.html @@ -5,8 +5,8 @@ One doc tagged with "await" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/blazor/index.html b/doc/build/tags/blazor/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/blazor/index.html rename to doc/build/tags/blazor/index.html index cf756e4..feb8eed 100644 --- a/doc/statepulse-doc/build/tags/blazor/index.html +++ b/doc/build/tags/blazor/index.html @@ -5,8 +5,8 @@ 7 docs tagged with "blazor" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/csharp/index.html b/doc/build/tags/csharp/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/csharp/index.html rename to doc/build/tags/csharp/index.html index 9795090..52ed44d 100644 --- a/doc/statepulse-doc/build/tags/csharp/index.html +++ b/doc/build/tags/csharp/index.html @@ -5,8 +5,8 @@ 6 docs tagged with "csharp" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/dependency-injection/index.html b/doc/build/tags/dependency-injection/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/dependency-injection/index.html rename to doc/build/tags/dependency-injection/index.html index 4653b48..1b216d0 100644 --- a/doc/statepulse-doc/build/tags/dependency-injection/index.html +++ b/doc/build/tags/dependency-injection/index.html @@ -5,8 +5,8 @@ One doc tagged with "dependency-injection" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/dispatcher/index.html b/doc/build/tags/dispatcher/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/dispatcher/index.html rename to doc/build/tags/dispatcher/index.html index fbc4a94..8595a98 100644 --- a/doc/statepulse-doc/build/tags/dispatcher/index.html +++ b/doc/build/tags/dispatcher/index.html @@ -5,8 +5,8 @@ One doc tagged with "dispatcher" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/effects/index.html b/doc/build/tags/effects/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/effects/index.html rename to doc/build/tags/effects/index.html index 2e90da4..a0b99f1 100644 --- a/doc/statepulse-doc/build/tags/effects/index.html +++ b/doc/build/tags/effects/index.html @@ -5,8 +5,8 @@ One doc tagged with "effects" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/immutable/index.html b/doc/build/tags/immutable/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/immutable/index.html rename to doc/build/tags/immutable/index.html index c5cfd62..9470a8d 100644 --- a/doc/statepulse-doc/build/tags/immutable/index.html +++ b/doc/build/tags/immutable/index.html @@ -5,8 +5,8 @@ One doc tagged with "immutable" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/index.html b/doc/build/tags/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/index.html rename to doc/build/tags/index.html index 04d92f7..32fe97c 100644 --- a/doc/statepulse-doc/build/tags/index.html +++ b/doc/build/tags/index.html @@ -5,8 +5,8 @@ Tags | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/installation/index.html b/doc/build/tags/installation/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/installation/index.html rename to doc/build/tags/installation/index.html index 804dd2f..209bb9c 100644 --- a/doc/statepulse-doc/build/tags/installation/index.html +++ b/doc/build/tags/installation/index.html @@ -5,8 +5,8 @@ One doc tagged with "installation" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/isafeaction/index.html b/doc/build/tags/isafeaction/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/isafeaction/index.html rename to doc/build/tags/isafeaction/index.html index f32a295..5df359d 100644 --- a/doc/statepulse-doc/build/tags/isafeaction/index.html +++ b/doc/build/tags/isafeaction/index.html @@ -5,8 +5,8 @@ One doc tagged with "isafeaction" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/net/index.html b/doc/build/tags/net/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/net/index.html rename to doc/build/tags/net/index.html index b067fca..7323be1 100644 --- a/doc/statepulse-doc/build/tags/net/index.html +++ b/doc/build/tags/net/index.html @@ -5,8 +5,8 @@ 6 docs tagged with ".net" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/performance/index.html b/doc/build/tags/performance/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/performance/index.html rename to doc/build/tags/performance/index.html index 9d62bb2..372b181 100644 --- a/doc/statepulse-doc/build/tags/performance/index.html +++ b/doc/build/tags/performance/index.html @@ -5,8 +5,8 @@ 2 docs tagged with "performance" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/pure-functions/index.html b/doc/build/tags/pure-functions/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/pure-functions/index.html rename to doc/build/tags/pure-functions/index.html index 1447fff..2b5703f 100644 --- a/doc/statepulse-doc/build/tags/pure-functions/index.html +++ b/doc/build/tags/pure-functions/index.html @@ -5,8 +5,8 @@ 2 docs tagged with "pure-functions" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/reducer/index.html b/doc/build/tags/reducer/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/reducer/index.html rename to doc/build/tags/reducer/index.html index 5a034d3..30c51ec 100644 --- a/doc/statepulse-doc/build/tags/reducer/index.html +++ b/doc/build/tags/reducer/index.html @@ -5,8 +5,8 @@ 2 docs tagged with "reducer" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/redux/index.html b/doc/build/tags/redux/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/redux/index.html rename to doc/build/tags/redux/index.html index 41fe74e..84ad310 100644 --- a/doc/statepulse-doc/build/tags/redux/index.html +++ b/doc/build/tags/redux/index.html @@ -5,8 +5,8 @@ One doc tagged with "redux" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/safedispatch/index.html b/doc/build/tags/safedispatch/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/safedispatch/index.html rename to doc/build/tags/safedispatch/index.html index 499b001..099015f 100644 --- a/doc/statepulse-doc/build/tags/safedispatch/index.html +++ b/doc/build/tags/safedispatch/index.html @@ -5,8 +5,8 @@ One doc tagged with "safedispatch" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/setup/index.html b/doc/build/tags/setup/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/setup/index.html rename to doc/build/tags/setup/index.html index 024923a..1a37dd2 100644 --- a/doc/statepulse-doc/build/tags/setup/index.html +++ b/doc/build/tags/setup/index.html @@ -5,8 +5,8 @@ One doc tagged with "setup" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/side-effects/index.html b/doc/build/tags/side-effects/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/side-effects/index.html rename to doc/build/tags/side-effects/index.html index feb1b95..509ce46 100644 --- a/doc/statepulse-doc/build/tags/side-effects/index.html +++ b/doc/build/tags/side-effects/index.html @@ -5,8 +5,8 @@ One doc tagged with "side-effects" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/state-management/index.html b/doc/build/tags/state-management/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/state-management/index.html rename to doc/build/tags/state-management/index.html index 3c6f842..c477572 100644 --- a/doc/statepulse-doc/build/tags/state-management/index.html +++ b/doc/build/tags/state-management/index.html @@ -5,8 +5,8 @@ 6 docs tagged with "state-management" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/state/index.html b/doc/build/tags/state/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/state/index.html rename to doc/build/tags/state/index.html index 6a6aa52..a57410b 100644 --- a/doc/statepulse-doc/build/tags/state/index.html +++ b/doc/build/tags/state/index.html @@ -5,8 +5,8 @@ One doc tagged with "state" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/tags/statepulse/index.html b/doc/build/tags/statepulse/index.html similarity index 98% rename from doc/statepulse-doc/build/tags/statepulse/index.html rename to doc/build/tags/statepulse/index.html index 5402baa..b601ca9 100644 --- a/doc/statepulse-doc/build/tags/statepulse/index.html +++ b/doc/build/tags/statepulse/index.html @@ -5,8 +5,8 @@ 7 docs tagged with "statepulse" | StatePulse.NET - - + + diff --git a/doc/statepulse-doc/build/versions/index.html b/doc/build/versions/index.html similarity index 75% rename from doc/statepulse-doc/build/versions/index.html rename to doc/build/versions/index.html index 2279586..b69f626 100644 --- a/doc/statepulse-doc/build/versions/index.html +++ b/doc/build/versions/index.html @@ -3,16 +3,45 @@ -Updates | StatePulse.NET +Updates | StatePulse.NET - - + + -

    Updates

    πŸ“¦ v1.1.0​

    +

    Updates

    πŸ“¦ v2.0.0​

    +

    ✨ BREAKING CHANGES​

    +
      +
    • The signature of interfaces changed so any plugin-based system could potentially break if core updates and plugins don't unless plugin isolation is respected.
    • +
    • The REDUCERS now run before the effects! so any pipelines relying on post-effect reducers should configure StatePulse to execute reducers post effect (simple config flip) Configure.DispatchOrderBehavior = DispatchOrdering.EffectsFirst;.
    • +
    +

    ✨ New Features​

    +
      +
    • βš™οΈ Enhanced Configuration Options - New global configuration properties: +
        +
      • DispatchOrderBehavior - Set default ordering (EffectsFirst/ReducersFirst)
      • +
      • DispatchEffectExecutionBehavior - Set default execution mode (YieldAndFire/FireAndForget)
      • +
      +
    • +
    • πŸŽ›οΈ Configurable Dispatch Ordering - Choose between EffectsFirst (default) or ReducersFirst execution order globally or per-dispatch
    • +
    • ⚑ True Fire-and-Forget Execution Mode - New DispatchEffectExecutionBehavior.FireAndForget for true background execution without yielding and awaiting effects
    • +
    • πŸ”§ Per-Dispatch Execution Control - Override global settings per dispatch with fluent API: +
        +
      • .ExecFireAndForget() - Fully detached background execution
      • +
      • .ExecYieldAndFire() - Yield to caller but await until all effects are done to move down the pipeline
      • +
      • .EffectsFirst() - Run effects before reducers
      • +
      • .ReducersFirst() - Run reducers before effects
      • +
      • .SequentialEffects() - Force effects to run in sequence
      • +
      • .ParallelEffects() - Force effects to run in parallel
      • +
      +
    • +
    • πŸ›‘οΈ Invalid Configuration Detection - New InvalidDispatchCombinationException thrown at dispatch time for incompatible configuration combinations (Plan to generate compiler errors later)
    • +
    • ♻️ Recursive Dispatch Support - Fire-and-forget mode enables safe recursive dispatch patterns without deadlocks
    • +
    +

    πŸ“¦ v1.1.0​

    ✨ Minor Change​

    • Upgraded to .NET 10
    • @@ -28,7 +57,7 @@

      ✨ Minor Ch
    • Splited Abstractions into StatePulse.Net.Abstractions (Will not break anything Namespace is the same)

    πŸ“¦ v1.0.0​

    -

    ✨ New Features​

    +

    ✨ New Features​

    • βœ… Action Effect Validator: Allows effects to run conditionally by validating them before execution.
    • 🧩 Middleware Support: @@ -56,7 +85,7 @@

      ✨ New Featur

    -

    πŸ’₯ Breaking Changes​

    +

    πŸ’₯ Breaking Changes​

    • ❌ Removed Action Validator – validating action data is not the responsibility of the state management layer.
    • πŸ”„ Renamed: @@ -102,6 +131,6 @@

      v0.9.2
      • Deprecated now part of StatePulse regular since we have removed the dependencies to blazor component. ... that was quick!
      • -

    +
    \ No newline at end of file diff --git a/doc/statepulse-doc/docs/0.Versions.md b/doc/docs/0.Versions.md similarity index 59% rename from doc/statepulse-doc/docs/0.Versions.md rename to doc/docs/0.Versions.md index 7a73a1e..b23a3df 100644 --- a/doc/statepulse-doc/docs/0.Versions.md +++ b/doc/docs/0.Versions.md @@ -4,6 +4,28 @@ title: Updates sidebar_position: 0 --- +## πŸ“¦ v2.0.0 +### ✨ BREAKING CHANGES +- The signature of interfaces changed so any plugin-based system could potentially break if core updates and plugins don't unless plugin isolation is respected. +- The REDUCERS now run before the effects! so any pipelines relying on post-effect reducers should configure StatePulse to execute reducers post effect (simple config flip) `Configure.DispatchOrderBehavior = DispatchOrdering.EffectsFirst;`. + +### ✨ New Features +- **βš™οΈ Enhanced Configuration Options** - New global configuration properties: + - `DispatchOrderBehavior` - Set default ordering (EffectsFirst/ReducersFirst) + - `DispatchEffectExecutionBehavior` - Set default execution mode (YieldAndFire/FireAndForget) +- **πŸŽ›οΈ Configurable Dispatch Ordering** - Choose between `EffectsFirst` (default) or `ReducersFirst` execution order globally or per-dispatch +- **⚑ True Fire-and-Forget Execution Mode** - New `DispatchEffectExecutionBehavior.FireAndForget` for true background execution without yielding and awaiting effects +- **πŸ”§ Per-Dispatch Execution Control** - Override global settings per dispatch with fluent API: + - `.ExecFireAndForget()` - Fully detached background execution + - `.ExecYieldAndFire()` - Yield to caller but await until all effects are done to move down the pipeline + - `.EffectsFirst()` - Run effects before reducers + - `.ReducersFirst()` - Run reducers before effects + - `.SequentialEffects()` - Force effects to run in sequence + - `.ParallelEffects()` - Force effects to run in parallel +- **πŸ›‘οΈ Invalid Configuration Detection** - New `InvalidDispatchCombinationException` thrown at dispatch time for incompatible configuration combinations (Plan to generate compiler errors later) +- **♻️ Recursive Dispatch Support** - Fire-and-forget mode enables safe recursive dispatch patterns without deadlocks + + ## πŸ“¦ v1.1.0 ### ✨ Minor Change - Upgraded to .NET 10 diff --git a/doc/statepulse-doc/docs/1. Setup Blazor Project.md b/doc/docs/1. Setup Blazor Project.md similarity index 100% rename from doc/statepulse-doc/docs/1. Setup Blazor Project.md rename to doc/docs/1. Setup Blazor Project.md diff --git a/doc/statepulse-doc/docs/2. Creating Actions.md b/doc/docs/2. Creating Actions.md similarity index 100% rename from doc/statepulse-doc/docs/2. Creating Actions.md rename to doc/docs/2. Creating Actions.md diff --git a/doc/statepulse-doc/docs/3.Create State.md b/doc/docs/3.Create State.md similarity index 100% rename from doc/statepulse-doc/docs/3.Create State.md rename to doc/docs/3.Create State.md diff --git a/doc/statepulse-doc/docs/4 Create Effects.md b/doc/docs/4 Create Effects.md similarity index 100% rename from doc/statepulse-doc/docs/4 Create Effects.md rename to doc/docs/4 Create Effects.md diff --git a/doc/statepulse-doc/docs/5.Create Reducer.md b/doc/docs/5.Create Reducer.md similarity index 100% rename from doc/statepulse-doc/docs/5.Create Reducer.md rename to doc/docs/5.Create Reducer.md diff --git a/doc/statepulse-doc/docs/6.Inject Dispatcher.md b/doc/docs/6.Inject Dispatcher.md similarity index 100% rename from doc/statepulse-doc/docs/6.Inject Dispatcher.md rename to doc/docs/6.Inject Dispatcher.md diff --git a/doc/statepulse-doc/docs/Middlewares.md b/doc/docs/7.Middlewares.md similarity index 100% rename from doc/statepulse-doc/docs/Middlewares.md rename to doc/docs/7.Middlewares.md diff --git a/doc/statepulse-doc/docs/Getting Started.md b/doc/docs/Getting Started.md similarity index 99% rename from doc/statepulse-doc/docs/Getting Started.md rename to doc/docs/Getting Started.md index eaee874..46bd8ec 100644 --- a/doc/statepulse-doc/docs/Getting Started.md +++ b/doc/docs/Getting Started.md @@ -192,7 +192,7 @@ public partial class CounterView : ComponentBase // Never use lambda it will throw exception as WeakREference is fundamatally flawed and disposes of lambda even when its object is alive. private CounterState state => PulseState.StateOf(()=>this, OnUpdate); - private async Task OnUpdate() => await InvokeAsync(StateHadChanged); + private async Task OnUpdate() => await InvokeAsync(StateHasChanged); // METHOD 2: // Inject direct state but injecting the state directly requires you to handle onchanged events by sub/unsub in lifecycle diff --git a/doc/statepulse-doc/docusaurus.config.ts b/doc/docusaurus.config.ts similarity index 100% rename from doc/statepulse-doc/docusaurus.config.ts rename to doc/docusaurus.config.ts diff --git a/doc/statepulse-doc/package-lock.json b/doc/package-lock.json similarity index 100% rename from doc/statepulse-doc/package-lock.json rename to doc/package-lock.json diff --git a/doc/statepulse-doc/package.json b/doc/package.json similarity index 100% rename from doc/statepulse-doc/package.json rename to doc/package.json diff --git a/doc/statepulse-doc/sidebars.ts b/doc/sidebars.ts similarity index 100% rename from doc/statepulse-doc/sidebars.ts rename to doc/sidebars.ts diff --git a/doc/statepulse-doc/src/css/custom.css b/doc/src/css/custom.css similarity index 100% rename from doc/statepulse-doc/src/css/custom.css rename to doc/src/css/custom.css diff --git a/doc/statepulse-doc/src/pages/markdown-page.md b/doc/src/pages/markdown-page.md similarity index 100% rename from doc/statepulse-doc/src/pages/markdown-page.md rename to doc/src/pages/markdown-page.md diff --git a/doc/statepulse-doc/build/assets/js/6638fef1.00b4e006.js b/doc/statepulse-doc/build/assets/js/6638fef1.00b4e006.js deleted file mode 100644 index ace88bf..0000000 --- a/doc/statepulse-doc/build/assets/js/6638fef1.00b4e006.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[4074],{5652:(e,r,s)=>{s.r(r),s.d(r,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>t,toc:()=>d});const t=JSON.parse('{"id":"Middlewares","title":"The Middlewares","description":"\u2699\ufe0f What are Middlewares?","source":"@site/docs/Middlewares.md","sourceDirName":".","slug":"/gs-the-middlewares","permalink":"/gs-the-middlewares","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/Middlewares.md","tags":[{"inline":true,"label":"blazor","permalink":"/tags/blazor"},{"inline":true,"label":"reducer","permalink":"/tags/reducer"},{"inline":true,"label":"state-management","permalink":"/tags/state-management"},{"inline":true,"label":"pure-functions","permalink":"/tags/pure-functions"},{"inline":true,"label":"async","permalink":"/tags/async"},{"inline":true,"label":"statepulse","permalink":"/tags/statepulse"},{"inline":true,"label":"csharp","permalink":"/tags/csharp"},{"inline":true,"label":".net","permalink":"/tags/net"}],"version":"current","sidebarPosition":7,"frontMatter":{"slug":"gs-the-middlewares","title":"The Middlewares","tags":["blazor","reducer","state-management","pure-functions","async","statepulse","csharp",".net"],"sidebar_position":7},"sidebar":"tutorialSidebar","previous":{"title":"The Dispatcher","permalink":"/gs-the-dispatcher"}}');var n=s(4848),l=s(8453);const i={slug:"gs-the-middlewares",title:"The Middlewares",tags:["blazor","reducer","state-management","pure-functions","async","statepulse","csharp",".net"],sidebar_position:7},a=void 0,c={},d=[{value:"\u2699\ufe0f What are Middlewares?",id:"\ufe0f-what-are-middlewares",level:2},{value:"\ud83e\udde9 Effect Middleware",id:"-effect-middleware",level:2},{value:"Available Hooks",id:"available-hooks",level:3},{value:"Example: Effect Middleware",id:"example-effect-middleware",level:3},{value:"\ud83d\udcd8 Other Middleware Types",id:"-other-middleware-types",level:2},{value:"\ud83e\uddfc Use Cases",id:"-use-cases",level:2}];function o(e){const r={blockquote:"blockquote",br:"br",code:"code",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,l.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(r.h2,{id:"\ufe0f-what-are-middlewares",children:"\u2699\ufe0f What are Middlewares?"}),"\n",(0,n.jsxs)(r.p,{children:["StatePulse uses ",(0,n.jsx)(r.strong,{children:"middleware interfaces"})," to tap into the lifecycle of ",(0,n.jsx)(r.strong,{children:"effects"}),", ",(0,n.jsx)(r.strong,{children:"reducers"}),", and ",(0,n.jsx)(r.strong,{children:"dispatches"}),".",(0,n.jsx)(r.br,{}),"\n","These middleware hooks are useful for ",(0,n.jsx)(r.strong,{children:"logging"}),", ",(0,n.jsx)(r.strong,{children:"metrics"}),", ",(0,n.jsx)(r.strong,{children:"analytics"}),", or ",(0,n.jsx)(r.strong,{children:"debugging"})," \u2014 but should ",(0,n.jsx)(r.strong,{children:"never alter behavior"})," or mutate state."]}),"\n",(0,n.jsxs)(r.blockquote,{children:["\n",(0,n.jsx)(r.p,{children:"\u2757 Middleware is observational only \u2014 do not use it to change logic or outcomes."}),"\n"]}),"\n",(0,n.jsx)(r.h2,{id:"-effect-middleware",children:"\ud83e\udde9 Effect Middleware"}),"\n",(0,n.jsxs)(r.p,{children:[(0,n.jsx)(r.code,{children:"IEffectMiddleware"})," allows you to hook into the execution of any effect."]}),"\n",(0,n.jsx)(r.h3,{id:"available-hooks",children:"Available Hooks"}),"\n",(0,n.jsxs)(r.ul,{children:["\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.code,{children:"BeforeEffect(object action)"})," \u2013 called ",(0,n.jsx)(r.strong,{children:"before"})," the effect runs"]}),"\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.code,{children:"AfterEffect(object action)"})," \u2013 called ",(0,n.jsx)(r.strong,{children:"after"})," the effect completes"]}),"\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.code,{children:"WhenEffectValidationFailed(object action, object effectValidator)"})," \u2013 called when a validator blocks execution"]}),"\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.code,{children:"WhenEffectValidationSucceed(object action, object effectValidator)"})," \u2013 called when a validator passes"]}),"\n"]}),"\n",(0,n.jsx)(r.h3,{id:"example-effect-middleware",children:"Example: Effect Middleware"}),"\n",(0,n.jsx)(r.pre,{children:(0,n.jsx)(r.code,{className:"language-csharp",metastring:'title="LoggingMiddleware.cs"',children:'internal class LoggingMiddleware : IEffectMiddleware\r\n{\r\n private readonly ILogger _logger;\r\n\r\n public LoggingMiddleware(ILogger logger)\r\n {\r\n _logger = logger;\r\n }\r\n public Task AfterEffect(object action)\r\n {\r\n string message = $"{action.GetType()} finished execution.";\r\n _logger.LogDebug(message);\r\n return Task.CompletedTask;\r\n }\r\n public Task BeforeEffect(object action) => Task.CompletedTask;\r\n public Task WhenEffectValidationFailed(object action, object effectValidator) => Task.CompletedTask;\r\n public Task WhenEffectValidationSucceed(object action, object effectValidator) => Task.CompletedTask;\r\n}\r\n\n'})}),"\n",(0,n.jsx)(r.h2,{id:"-other-middleware-types",children:"\ud83d\udcd8 Other Middleware Types"}),"\n",(0,n.jsx)(r.p,{children:"Additional interfaces are available to observe other parts of the StatePulse pipeline:"}),"\n",(0,n.jsxs)(r.ul,{children:["\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.code,{children:"IReducerMiddleware"})," \u2013 Observe ",(0,n.jsx)(r.strong,{children:"reducer"})," executions (before/after)"]}),"\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.code,{children:"IDispatcherMiddleware"})," \u2013 Observe all ",(0,n.jsx)(r.strong,{children:"dispatched actions"})," (before/after)"]}),"\n"]}),"\n",(0,n.jsxs)(r.p,{children:["These follow a similar structure to ",(0,n.jsx)(r.code,{children:"IEffectMiddleware"}),", offering lifecycle hooks such as:"]}),"\n",(0,n.jsxs)(r.ul,{children:["\n",(0,n.jsx)(r.li,{children:(0,n.jsx)(r.code,{children:"Before..."})}),"\n",(0,n.jsx)(r.li,{children:(0,n.jsx)(r.code,{children:"After..."})}),"\n"]}),"\n",(0,n.jsxs)(r.blockquote,{children:["\n",(0,n.jsxs)(r.p,{children:["\u26a0\ufe0f Just like with effects, these middleware interfaces are ",(0,n.jsx)(r.strong,{children:"observational only"})," \u2014 they should not alter state or behavior."]}),"\n"]}),"\n",(0,n.jsx)(r.h2,{id:"-use-cases",children:"\ud83e\uddfc Use Cases"}),"\n",(0,n.jsx)(r.p,{children:"Here are common use cases for StatePulse middleware:"}),"\n",(0,n.jsxs)(r.ul,{children:["\n",(0,n.jsxs)(r.li,{children:["\u2705 Logging effects, reducers, or dispatches for ",(0,n.jsx)(r.strong,{children:"debugging"})]}),"\n",(0,n.jsxs)(r.li,{children:["\ud83d\udcca Tracking ",(0,n.jsx)(r.strong,{children:"user behavior"})]}),"\n",(0,n.jsxs)(r.li,{children:["\u23f1\ufe0f Measuring ",(0,n.jsx)(r.strong,{children:"performance metrics"})]}),"\n",(0,n.jsxs)(r.li,{children:["\ud83d\udcc8 Collecting ",(0,n.jsx)(r.strong,{children:"analytics"})," without mutating state or logic"]}),"\n"]})]})}function h(e={}){const{wrapper:r}={...(0,l.R)(),...e.components};return r?(0,n.jsx)(r,{...e,children:(0,n.jsx)(o,{...e})}):o(e)}},8453:(e,r,s)=>{s.d(r,{R:()=>i,x:()=>a});var t=s(6540);const n={},l=t.createContext(n);function i(e){const r=t.useContext(l);return t.useMemo(function(){return"function"==typeof e?e(r):{...r,...e}},[r,e])}function a(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:i(e.components),t.createElement(l.Provider,{value:r},e.children)}}}]); \ No newline at end of file diff --git a/doc/statepulse-doc/build/assets/js/94cf9043.d09cd2bd.js b/doc/statepulse-doc/build/assets/js/94cf9043.d09cd2bd.js deleted file mode 100644 index d0091f3..0000000 --- a/doc/statepulse-doc/build/assets/js/94cf9043.d09cd2bd.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[6683],{8453:(e,n,i)=>{i.d(n,{R:()=>d,x:()=>t});var s=i(6540);const l={},r=s.createContext(l);function d(e){const n=s.useContext(r);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function t(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(l):e.components||l:d(e.components),s.createElement(r.Provider,{value:n},e.children)}},8886:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>t,default:()=>h,frontMatter:()=>d,metadata:()=>s,toc:()=>a});const s=JSON.parse('{"id":"Versions","title":"Updates","description":"\ud83d\udce6 v1.1.0","source":"@site/docs/0.Versions.md","sourceDirName":".","slug":"/versions","permalink":"/versions","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/0.Versions.md","tags":[],"version":"current","sidebarPosition":0,"frontMatter":{"slug":"versions","title":"Updates","sidebar_position":0},"sidebar":"tutorialSidebar","next":{"title":"Get Started","permalink":"/"}}');var l=i(4848),r=i(8453);const d={slug:"versions",title:"Updates",sidebar_position:0},t=void 0,c={},a=[{value:"\ud83d\udce6 v1.1.0",id:"-v110",level:2},{value:"\u2728 Minor Change",id:"-minor-change",level:3},{value:"\ud83d\udce6 v1.0.2",id:"-v102",level:2},{value:"\ud83d\udc1e Fixes",id:"-fixes",level:3},{value:"\ud83d\udce6 v1.0.1",id:"-v101",level:2},{value:"\u2728 Minor Change",id:"-minor-change-1",level:3},{value:"\ud83d\udce6 v1.0.0",id:"-v100",level:2},{value:"\u2728 New Features",id:"-new-features",level:3},{value:"\ud83d\udca5 Breaking Changes",id:"-breaking-changes",level:3},{value:"\ud83d\ude80 Performance Improvements",id:"-performance-improvements",level:3},{value:"\ud83e\uddfc Clean Code Improvements",id:"-clean-code-improvements",level:3},{value:"\ud83d\udc1e Fixes",id:"-fixes-1",level:3},{value:"v0.9.41",id:"v0941",level:2},{value:"v0.9.4",id:"v094",level:2},{value:"v0.9.21",id:"v0921",level:2},{value:"v0.9.2 (Blazor Packages)",id:"v092-blazor-packages",level:2}];function o(e){const n={code:"code",h2:"h2",h3:"h3",li:"li",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(n.h2,{id:"-v110",children:"\ud83d\udce6 v1.1.0"}),"\n",(0,l.jsx)(n.h3,{id:"-minor-change",children:"\u2728 Minor Change"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Upgraded to .NET 10"}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"-v102",children:"\ud83d\udce6 v1.0.2"}),"\n",(0,l.jsx)(n.h3,{id:"-fixes",children:"\ud83d\udc1e Fixes"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Added StatePulse.Net.Abstractions package reference instead of project reference to fix IL trimming issues."}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"-v101",children:"\ud83d\udce6 v1.0.1"}),"\n",(0,l.jsx)(n.h3,{id:"-minor-change-1",children:"\u2728 Minor Change"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Splited Abstractions into StatePulse.Net.Abstractions (Will not break anything Namespace is the same)"}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"-v100",children:"\ud83d\udce6 v1.0.0"}),"\n",(0,l.jsx)(n.h3,{id:"-new-features",children:"\u2728 New Features"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["\u2705 ",(0,l.jsx)(n.strong,{children:"Action Effect Validator"}),": Allows effects to run conditionally by validating them before execution."]}),"\n",(0,l.jsxs)(n.li,{children:["\ud83e\udde9 ",(0,l.jsx)(n.strong,{children:"Middleware Support"}),":","\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"IEffectMiddleware"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"IReducerMiddleware"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"IDispatchMiddleware"})}),"\n"]}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["\u2699\ufe0f ",(0,l.jsx)(n.strong,{children:"Behavior Configuration"}),": You can configure execution behaviors via:","\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"DispatchEffectBehavior"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"MiddlewareEffectBehavior"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"MiddlewareTaskBehavior"})}),"\n"]}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["\ud83d\udee0\ufe0f ",(0,l.jsx)(n.strong,{children:"Strict Manual Registration"}),": Manual service registration ",(0,l.jsx)(n.strong,{children:"must use"})," extension methods:","\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"AddStatePulse()"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"AddStatePulseEffect<>()"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"AddStatePulseAction<>()"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"AddStatePulseReducer<>()"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"AddStatePulseStateFeature<>()"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"AddStatePulseEffectValidator<>()"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"-breaking-changes",children:"\ud83d\udca5 Breaking Changes"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["\u274c Removed ",(0,l.jsx)(n.strong,{children:"Action Validator"})," \u2013 validating action data is not the responsibility of the state management layer."]}),"\n",(0,l.jsxs)(n.li,{children:["\ud83d\udd04 Renamed:","\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"IStateAccessor<>.StateChanged"})," \u2192 ",(0,l.jsx)(n.code,{children:"OnStateChanged"})]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"UsingSynchronousMode"})," \u2192 ",(0,l.jsx)(n.strong,{children:"Removed"})]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"Sync()"})," \u2192 ",(0,l.jsx)(n.code,{children:"Await()"})," for clarity and accuracy"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"-performance-improvements",children:"\ud83d\ude80 Performance Improvements"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["\ud83e\udde0 Improved ",(0,l.jsx)(n.strong,{children:"dispatcher caching"})]}),"\n",(0,l.jsxs)(n.li,{children:["\u26a1 Enhanced ",(0,l.jsx)(n.strong,{children:"type cache"})," in ",(0,l.jsx)(n.code,{children:"StatePulseRegistry"})]}),"\n",(0,l.jsxs)(n.li,{children:["\ud83e\uddec Replaced reflection with ",(0,l.jsx)(n.strong,{children:"dynamic method caching"})," for faster dispatching"]}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"-clean-code-improvements",children:"\ud83e\uddfc Clean Code Improvements"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["\ud83e\uddf9 Refactored ",(0,l.jsx)(n.code,{children:"DispatchPrepper"})," for cleaner and lighter internal logic"]}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"-fixes-1",children:"\ud83d\udc1e Fixes"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["\ud83d\udee0\ufe0f Resolved several ",(0,l.jsx)(n.strong,{children:"null reference warnings"})]}),"\n",(0,l.jsxs)(n.li,{children:["\ud83e\uddfd Removed leftover ",(0,l.jsx)(n.strong,{children:"internal artifacts"})]}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"v0941",children:"v0.9.41"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Fix: Added Anti-Service duplication to avoid double triggers."}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"v094",children:"v0.9.4"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Breaking Change, StateOf no longer accept lambda will throw exception you must define a Task directly... this was necessary due to Garbage Collector and tracking behavior."}),"\n",(0,l.jsx)(n.li,{children:"Deprecated UsingSynchronousMode() instead use Sync()."}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"v0921",children:"v0.9.21"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Implement the Blazor Package and removed dependencies to Blazor ComponentBase which is no longer required..."}),"\n",(0,l.jsx)(n.li,{children:"Any objects within .NET can now use IStatePulse and benefit from state management without extra implementations."}),"\n",(0,l.jsx)(n.li,{children:"Renamed IPulse to IStatePulse"}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"using IStatePulse.StateOf(()=>this, () => InvokeAsync(StateHasChanged));"})}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"v092-blazor-packages",children:"v0.9.2 (Blazor Packages)"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Deprecated now part of StatePulse regular since we have removed the dependencies to blazor component.\r\n... that was quick!"}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,l.jsx)(n,{...e,children:(0,l.jsx)(o,{...e})}):o(e)}}}]); \ No newline at end of file diff --git a/doc/statepulse-doc/static/.nojekyll b/doc/static/.nojekyll similarity index 100% rename from doc/statepulse-doc/static/.nojekyll rename to doc/static/.nojekyll diff --git a/doc/statepulse-doc/static/img/docusaurus-social-card.jpg b/doc/static/img/docusaurus-social-card.jpg similarity index 100% rename from doc/statepulse-doc/static/img/docusaurus-social-card.jpg rename to doc/static/img/docusaurus-social-card.jpg diff --git a/doc/statepulse-doc/static/img/docusaurus.png b/doc/static/img/docusaurus.png similarity index 100% rename from doc/statepulse-doc/static/img/docusaurus.png rename to doc/static/img/docusaurus.png diff --git a/doc/statepulse-doc/static/img/favicon.ico b/doc/static/img/favicon.ico similarity index 100% rename from doc/statepulse-doc/static/img/favicon.ico rename to doc/static/img/favicon.ico diff --git a/doc/statepulse-doc/static/img/icon.png b/doc/static/img/icon.png similarity index 100% rename from doc/statepulse-doc/static/img/icon.png rename to doc/static/img/icon.png diff --git a/doc/statepulse-doc/static/img/logo.svg b/doc/static/img/logo.svg similarity index 100% rename from doc/statepulse-doc/static/img/logo.svg rename to doc/static/img/logo.svg diff --git a/doc/statepulse-doc/static/img/nuget-logo.png b/doc/static/img/nuget-logo.png similarity index 100% rename from doc/statepulse-doc/static/img/nuget-logo.png rename to doc/static/img/nuget-logo.png diff --git a/doc/statepulse-doc/static/img/undraw_docusaurus_mountain.svg b/doc/static/img/undraw_docusaurus_mountain.svg similarity index 100% rename from doc/statepulse-doc/static/img/undraw_docusaurus_mountain.svg rename to doc/static/img/undraw_docusaurus_mountain.svg diff --git a/doc/statepulse-doc/static/img/undraw_docusaurus_react.svg b/doc/static/img/undraw_docusaurus_react.svg similarity index 100% rename from doc/statepulse-doc/static/img/undraw_docusaurus_react.svg rename to doc/static/img/undraw_docusaurus_react.svg diff --git a/doc/statepulse-doc/static/img/undraw_docusaurus_tree.svg b/doc/static/img/undraw_docusaurus_tree.svg similarity index 100% rename from doc/statepulse-doc/static/img/undraw_docusaurus_tree.svg rename to doc/static/img/undraw_docusaurus_tree.svg diff --git a/doc/statepulse-doc/tsconfig.json b/doc/tsconfig.json similarity index 100% rename from doc/statepulse-doc/tsconfig.json rename to doc/tsconfig.json diff --git a/src/StatePulse.NET.sln b/src/StatePulse.NET.sln index fbcd5ea..e6b2919 100644 --- a/src/StatePulse.NET.sln +++ b/src/StatePulse.NET.sln @@ -1,11 +1,12 @@ ο»Ώ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.13.35931.197 +# Visual Studio Version 18 +VisualStudioVersion = 18.0.11222.15 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig + ..\README.md = ..\README.md EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatePulse.NET.Tests", "..\tests\StatPulse.NET.Tests\StatePulse.NET.Tests.csproj", "{07ED17B2-BD3A-94F4-FA85-43E768FAF9F0}" diff --git a/src/StatePulse.NET/Configuration/ConfigureOptions.cs b/src/StatePulse.NET/Configuration/ConfigureOptions.cs index 03acde2..947d1d3 100644 --- a/src/StatePulse.NET/Configuration/ConfigureOptions.cs +++ b/src/StatePulse.NET/Configuration/ConfigureOptions.cs @@ -1,4 +1,6 @@ -ο»Ώnamespace StatePulse.Net.Configuration; +ο»Ώusing StatePulse.Net.Engine.Exceptions; + +namespace StatePulse.Net.Configuration; public class ConfigureOptions { /// @@ -8,5 +10,20 @@ public class ConfigureOptions public MiddlewareEffectBehavior MiddlewareEffectBehavior { get; internal set; } = MiddlewareEffectBehavior.PerGroupEffects; public MiddlewareTaskBehavior MiddlewareTaskBehavior { get; internal set; } = MiddlewareTaskBehavior.DoNotAwait; public DispatchEffectBehavior DispatchEffectBehavior { get; internal set; } = DispatchEffectBehavior.Parallel; + public DispatchEffectExecutionBehavior DispatchEffectExecutionBehavior { get; internal set; } = DispatchEffectExecutionBehavior.YieldAndFire; + public DispatchOrdering DispatchOrderBehavior { get; internal set; } = DispatchOrdering.ReducersFirst; public Type[] ScanAssemblies { get; set; } = new Type[] { }; + + public void ValidateConfiguration() + { + // FireAndForget can't be Sequential + if (DispatchEffectExecutionBehavior == DispatchEffectExecutionBehavior.FireAndForget + && DispatchEffectBehavior == DispatchEffectBehavior.Sequential) + { + throw new InvalidDispatchCombinationException( + "DispatchEffectExecutionBehavior.FireAndForget execution cannot be combined with DispatchEffectBehavior.Sequential. " + + "FireAndForget doesn't await effects, so ordering cannot be guaranteed. " + + "Use DispatchEffectExecutionBehavior.YieldAndFire with DispatchEffectBehavior.Sequential/DispatchEffectBehavior.Parallel or DispatchEffectExecutionBehavior.FireAndForget and DispatchEffectBehavior.Parallel"); + } + } } diff --git a/src/StatePulse.NET/Configuration/DispatchEffectExecutionBehavior.cs b/src/StatePulse.NET/Configuration/DispatchEffectExecutionBehavior.cs new file mode 100644 index 0000000..8a0fce5 --- /dev/null +++ b/src/StatePulse.NET/Configuration/DispatchEffectExecutionBehavior.cs @@ -0,0 +1,19 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StatePulse.Net.Configuration; + +public enum DispatchEffectExecutionBehavior +{ + /// + /// (Default): Like fire and forget but the statepulse engine still awaits all the effects before calling the middlewares. + /// + YieldAndFire, + /// + /// Nothing is awaited, effects runs as they want and after effect middleware have not garantuees the effect actually ran. (This will disable DispatchEffectBehavior.Sequential) + /// + FireAndForget +} diff --git a/src/StatePulse.NET/Configuration/DispatchOrdering.cs b/src/StatePulse.NET/Configuration/DispatchOrdering.cs new file mode 100644 index 0000000..21f08d6 --- /dev/null +++ b/src/StatePulse.NET/Configuration/DispatchOrdering.cs @@ -0,0 +1,19 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StatePulse.Net.Configuration; + +public enum DispatchOrdering +{ + /// + /// Run and Await Reducers then Run Effects. + /// + ReducersFirst, + /// + /// (Default) Run the effects then run and await the reducers + /// + EffectsFirst +} diff --git a/src/StatePulse.NET/Engine/Exceptions/InvalidDispatchCombinationException.cs b/src/StatePulse.NET/Engine/Exceptions/InvalidDispatchCombinationException.cs new file mode 100644 index 0000000..1483761 --- /dev/null +++ b/src/StatePulse.NET/Engine/Exceptions/InvalidDispatchCombinationException.cs @@ -0,0 +1,14 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StatePulse.Net.Engine.Exceptions; + +public class InvalidDispatchCombinationException : Exception +{ + public InvalidDispatchCombinationException(string? message) : base(message) + { + } +} diff --git a/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs b/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs index cca8874..8c50645 100644 --- a/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs +++ b/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs @@ -4,11 +4,10 @@ using System.Collections.Concurrent; using System.Reflection; namespace StatePulse.Net.Engine.Implementations; -internal class DispatcherPrepper : IDispatcherPrepper +internal partial class DispatcherPrepper : IDispatcherPrepper where TAction : IAction where TActionChain : IAction { - private bool _forceSyncronous; private readonly TAction _action; private readonly IServiceProvider _serviceProvider; private readonly IStatePulseRegistry _statePulseRegistry; @@ -76,6 +75,7 @@ protected async Task ProcessDispatch(bool entryPoint, Guid nextId) { dispatchMiddlewareTasks.Add(item.BeforeDispatch(_action)); } + await Task.WhenAll(dispatchMiddlewareTasks); // we are tracking next chain key only when there is an entry point to avoid tracker during fast dispatch. // by default it will be null otherwise chain should be passed down the next calls. @@ -95,9 +95,20 @@ protected async Task ProcessDispatch(bool entryPoint, Guid nextId) var dispatcherService = _serviceProvider.GetRequiredService(); if (nextChain != default) await dispatcherService.DispatchHandler.MaintainChainKey(nextChain); + if (_dispatchOrdering == DispatchOrdering.ReducersFirst) + await RunReducer(nextChain); - await RunEffects(nextChain, dispatcherService); - await RunReducer(nextChain); + if (_dispatchEffectExecutionBehavior == DispatchEffectExecutionBehavior.FireAndForget) + { + _ = RunEffects(nextChain, dispatcherService); + } + else + { + await RunEffects(nextChain, dispatcherService); + } + + if (_dispatchOrdering == DispatchOrdering.EffectsFirst) + await RunReducer(nextChain); } catch @@ -120,14 +131,10 @@ protected async Task ProcessDispatch(bool entryPoint, Guid nextId) #pragma warning restore S2737 // "catch" clauses should do more than rethrow } - - public IDispatcherPrepper Await() - { - _forceSyncronous = true; - return this; - } public async Task DispatchAsync(bool asSafe = false) { + + ValidateConfiguration(); if ((_action is ISafeAction) || asSafe) return await DispatchSafeAsync(); await DispatchFastAsync(); @@ -136,7 +143,7 @@ public async Task DispatchAsync(bool asSafe = false) private Task RunMiddlewareEffect(IEnumerable middlewares, Func func, Func conditionBehavior) { - if (!conditionBehavior(ServiceRegisterExt._configureOptions.MiddlewareEffectBehavior)) + if (!conditionBehavior(ServiceRegisterExt.ConfigureOptions.MiddlewareEffectBehavior)) return Task.CompletedTask; var effectMiddlewaresTasks = new List(); @@ -168,7 +175,7 @@ private async Task RunEffects(DispatchTrackingIdentity? nextChain, IDispatchFact var effectMiddlewares = _serviceProvider.GetServices(); var effectMiddlewareTasks = RunMiddlewareEffect(effectMiddlewares, p => p.BeforeEffect(_action), p => p == MiddlewareEffectBehavior.PerGroupEffects); - if (ServiceRegisterExt._configureOptions.MiddlewareTaskBehavior == Configuration.MiddlewareTaskBehavior.Await) + if (ServiceRegisterExt.ConfigureOptions.MiddlewareTaskBehavior == Configuration.MiddlewareTaskBehavior.Await) await effectMiddlewareTasks; foreach (var effectService in effectServices) @@ -177,7 +184,7 @@ private async Task RunEffects(DispatchTrackingIdentity? nextChain, IDispatchFact break; effectMiddlewareTasks = RunMiddlewareEffect(effectMiddlewares, p => p.BeforeEffect(_action), p => p == MiddlewareEffectBehavior.PerIndividualEffect); - if (ServiceRegisterExt._configureOptions.MiddlewareTaskBehavior == Configuration.MiddlewareTaskBehavior.Await) + if (ServiceRegisterExt.ConfigureOptions.MiddlewareTaskBehavior == Configuration.MiddlewareTaskBehavior.Await) await effectMiddlewareTasks; bool validationPassed = await RunEffectValidators(effectService!.GetType(), effectMiddlewares); @@ -192,19 +199,40 @@ private async Task RunEffects(DispatchTrackingIdentity? nextChain, IDispatchFact if (del(_action, dispatcherService.Dispatcher) is Task effectTask) { effects.Add(effectTask); - if (ServiceRegisterExt._configureOptions.DispatchEffectBehavior == DispatchEffectBehavior.Sequential) + if (_dispatchEffectBehavior == DispatchEffectBehavior.Parallel || _dispatchEffectExecutionBehavior == DispatchEffectExecutionBehavior.FireAndForget) + _ = effectTask; + else await effectTask; } - if (ServiceRegisterExt._configureOptions.MiddlewareEffectBehavior == MiddlewareEffectBehavior.PerIndividualEffect) - await effectMiddlewareTasks; + + if (ServiceRegisterExt.ConfigureOptions.MiddlewareEffectBehavior == MiddlewareEffectBehavior.PerIndividualEffect) + { + if (_dispatchEffectExecutionBehavior == DispatchEffectExecutionBehavior.FireAndForget) + _ = effectMiddlewareTasks; + else + await effectMiddlewareTasks; + } + + var effectMiddlewareAfterTasks = RunMiddlewareEffect(effectMiddlewares, p => p.AfterEffect(_action), p => p == MiddlewareEffectBehavior.PerIndividualEffect); - if (ServiceRegisterExt._configureOptions.MiddlewareTaskBehavior == Configuration.MiddlewareTaskBehavior.Await) - await effectMiddlewareAfterTasks; + if (ServiceRegisterExt.ConfigureOptions.MiddlewareTaskBehavior == Configuration.MiddlewareTaskBehavior.Await) + if (_dispatchEffectExecutionBehavior == DispatchEffectExecutionBehavior.FireAndForget) + _ = effectMiddlewareAfterTasks; + else + await effectMiddlewareAfterTasks; + + } + if (_dispatchEffectExecutionBehavior == DispatchEffectExecutionBehavior.FireAndForget) + { + _ = Task.WhenAll(effects); + _ = effectMiddlewareTasks; + }else + { + await Task.WhenAll(effects); + await effectMiddlewareTasks; } - await Task.WhenAll(effects); - await effectMiddlewareTasks; - _ = RunMiddlewareEffect(effectMiddlewares, p => p.AfterEffect(_action), p => p == MiddlewareEffectBehavior.PerGroupEffects); + _ = RunMiddlewareEffect(effectMiddlewares, p => p.AfterEffect(_action), p => p == MiddlewareEffectBehavior.PerGroupEffects); } private async Task RunEffectValidators(Type effectService, IEnumerable effectMiddlewares) { @@ -256,7 +284,7 @@ private async Task RunReducer(DispatchTrackingIdentity? nextChain) var currentState = _statePulseRegistry.KnownStateAccessorsStateGetter[stateAccessorType](stateService)!; var middlewareTasks = RunMiddlewareReducer(middlewares, p => p.BeforeReducing(currentState, _action)); - if (ServiceRegisterExt._configureOptions.MiddlewareTaskBehavior == Configuration.MiddlewareTaskBehavior.Await) + if (ServiceRegisterExt.ConfigureOptions.MiddlewareTaskBehavior == Configuration.MiddlewareTaskBehavior.Await) await middlewareTasks; var reduceTask = (Task)_statePulseRegistry.KnownReducersReduceMethod[reducerType](reducerService, @@ -273,11 +301,12 @@ private async Task RunReducer(DispatchTrackingIdentity? nextChain) _statePulseRegistry.KnownStateAccessorsStateSetter[stateAccessorType](stateService, newState); middlewareTasks = RunMiddlewareReducer(middlewares, p => p.AfterReducing(newState, _action)); - if (ServiceRegisterExt._configureOptions.MiddlewareTaskBehavior == Configuration.MiddlewareTaskBehavior.Await) + if (ServiceRegisterExt.ConfigureOptions.MiddlewareTaskBehavior == Configuration.MiddlewareTaskBehavior.Await) await middlewareTasks; } } } + } diff --git a/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper_Flags.cs b/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper_Flags.cs new file mode 100644 index 0000000..b2e80ca --- /dev/null +++ b/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper_Flags.cs @@ -0,0 +1,88 @@ +ο»Ώ +using Microsoft.Extensions.DependencyInjection; +using StatePulse.Net.Configuration; +using StatePulse.Net.Engine.Exceptions; +using System.Collections.Concurrent; +using System.Reflection; +namespace StatePulse.Net.Engine.Implementations; +internal partial class DispatcherPrepper : IDispatcherPrepper + where TAction : IAction + where TActionChain : IAction +{ + + private DispatchEffectBehavior _dispatchEffectBehavior = ServiceRegisterExt.ConfigureOptions.DispatchEffectBehavior; + private DispatchEffectExecutionBehavior _dispatchEffectExecutionBehavior = ServiceRegisterExt.ConfigureOptions.DispatchEffectExecutionBehavior; + private DispatchOrdering _dispatchOrdering = ServiceRegisterExt.ConfigureOptions.DispatchOrderBehavior; + private bool _forceSyncronous; + + + public IDispatcherPrepper Await() + { + _forceSyncronous = true; + return this; + } + + public IDispatcherPrepper EffectsFirst() { + _dispatchOrdering = DispatchOrdering.EffectsFirst; + return this; + } + + public IDispatcherPrepper ReducersFirst() + { + _dispatchOrdering = DispatchOrdering.ReducersFirst; + return this; + } + + public IDispatcherPrepper ExecFireAndForget() + { + _dispatchEffectExecutionBehavior = DispatchEffectExecutionBehavior.FireAndForget; + return this; + } + + public IDispatcherPrepper ExecYieldAndFire() + { + _dispatchEffectExecutionBehavior = DispatchEffectExecutionBehavior.YieldAndFire; + return this; + } + + public IDispatcherPrepper SequentialEffects() + { + _dispatchEffectBehavior = DispatchEffectBehavior.Sequential; + return this; + } + public IDispatcherPrepper ParallelEffects() { + _dispatchEffectBehavior = DispatchEffectBehavior.Parallel; + return this; + } + + + private void ValidateConfiguration() + { + // FireAndForget can't be Sequential + if (_dispatchEffectExecutionBehavior == DispatchEffectExecutionBehavior.FireAndForget + && _dispatchEffectBehavior == DispatchEffectBehavior.Sequential) + { + throw new InvalidDispatchCombinationException( + "FireAndForget execution cannot be combined with Sequential effects. " + + "FireAndForget doesn't await effects, so ordering cannot be guaranteed. " + + "Use ExecYieldAndFire().SequentialEffects() or ExecFireAndForget().ParallelEffects()"); + } + + // Await() is locked to YieldAndFire + Sequential + if (_forceSyncronous) + { + if (_dispatchEffectExecutionBehavior != DispatchEffectExecutionBehavior.YieldAndFire) + { + throw new InvalidDispatchCombinationException( + "Await() requires YieldAndFire execution. Cannot use ExecFireAndForget() with Await()"); + } + // REMOVED IT WOULD BREAK EXISTING PROJECTS + //if (_dispatchEffectBehavior != DispatchEffectBehavior.Sequential) + //{ + // throw new InvalidDispatchCombinationException( + // "Await() requires Sequential effects. Cannot use ParallelEffects() with Await()"); + //} + } + } +} + diff --git a/src/StatePulse.NET/IDispatchPrepperExt.cs b/src/StatePulse.NET/IDispatchPrepperExt.cs index 6d57082..9b348e0 100644 --- a/src/StatePulse.NET/IDispatchPrepperExt.cs +++ b/src/StatePulse.NET/IDispatchPrepperExt.cs @@ -18,4 +18,5 @@ public static IDispatcherPrepper With(this IDispatcher return prep; } + } diff --git a/src/StatePulse.NET/README.md b/src/StatePulse.NET/README.md deleted file mode 100644 index e261b1a..0000000 --- a/src/StatePulse.NET/README.md +++ /dev/null @@ -1,201 +0,0 @@ -ο»Ώ -[![License: MIT](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT) -[![NuGet Version](https://img.shields.io/nuget/v/StatePulse.Net)](https://www.nuget.org/packages/StatePulse.NET) -[![](https://img.shields.io/nuget/dt/StatePulse.NET?label=Downloads)](https://www.nuget.org/packages/StatePulse.NET) - - - -# StatePulse.NET - -### [Official Documentation](https://statepulse.net/) - -StatePulse.NET is a precision-tuned state and action management system that balances high-performance fire-and-forget operations with optional, internally controlled execution order when explicitly required. -It enables anti-duplication chaining for critical flows, preventing race conditions and ensuring consistent outcomes even under rapid user input or concurrent triggers. -Its internal tracking infrastructure provides near-zero overhead cancellation and dispatch control, drastically reducing inconsistency. -At the same time, it preserves the flexibility of traditional untracked state management, letting developers selectively enforce order and reliability without compromising overall responsiveness or introducing global locks. - - -## ✨ Features -- ⚑ **Fast Fire-and-Forget** β€” Executes actions immediately even tracked action are fire-and-forget. -- πŸ›‘ **Anti-Duplicate Dispatching** β€” Prevents redundant or overlapping actions that can cause race condition state inconsistency. -- πŸ” **Validator System** β€” Supports multiple action validators for modular and reusable rule enforcement. -- πŸ§ͺ **Synchronous Debug Mode** β€” Optional lockstep mode for testing, diagnostics, and `Task.WhenAll` pipelines. -- 🧡 **DispatchTracker** β€” High-performance cancellation and deduplication logic via optimized concurrent tracking. - -### πŸš€ **State Management with Zero Boilerplate and Zero Compromises** - -- **Lazy State Access Model:** Inject `IStatePulse` directly into your Blazor component and call `StateOf(()=>this, TaskMethod)` to get scoped state access. -- **Component-Scoped Event Listening:** Automatically registers event listeners only for that component, ensuring `StateHasChanged()` is called exclusively on components subscribed to state changes. -- **No Base Classes or Global Event Listeners:** Avoids global re-renders and boilerplate base class inheritance, giving you fine-grained control over component rendering and event subscription without forcing you into base classes. -- **Automatic Listener Disposal:** Event listeners are automatically tracked and disposed with the component lifecycle, preventing memory leaks and dangling references. -- **Transient `IStatePulse` Service:** Each component gets its own `IStatePulse` instance, isolating event subscriptions and making state updates scoped and efficient. - - -## πŸ“¦ Installation & Setup - - -``` -Install-Package StatePulse.Net - -dotnet add package StatePulse.Net - -``` - -```csharp -services.AddStatePulseServices(o => - { - o.ScanAssemblies = new Type[] { typeof(Program) }; - }); -``` - -## 🧭 How It Works - - - -### **Define Actions**: - -```csharp - -// IAction { } -// ISafeAction { } // Cannot be dispatched unsafely - -public record ProfileCardDefineAction : IAction -{ - public string? TestData { get; set; } -} - -``` - -### **Define Actions Validator** (Optional): - -```csharp -/* -You are not required to create have an action validator but it is very useful when you have business logic that conditionally only contionally fires. -When validation fails it ignores the dispatch and move on. -*/ -internal class ProfileCardDefineActionValidator : IActionValidator -{ - public void Validate(ProfileCardDefineAction action, ref ValidationResult result) - { - if (action.TestData == "Error") - result.AddError("ErrorName", "Name Cannot be Error"); - } -} -``` - -### **Define Effect**: - -```csharp - -internal class ProfileCardDefineEffect : IEffect -{ - - public ProfileCardDefineEffect() - { - } - public async Task EffectAsync(ProfileCardDefineAction action, IDispatcher dispatcher) - { - var random = new Random(); - int value = random.Next(100, 1001); // Upper bound is exclusive, so use 1001 - await Task.Delay(value); - var myProfile = new UserResponse(); - await dispatcher.Prepare(() => new ProfileCardDefineResultAction(action.TestData ?? myProfile.Name, myProfile.Picture, myProfile.Id)) - .DispatchAsync(); - } - -} - - -``` - -### **Define Reducer**: - -```csharp -internal class ProfileCardDefineResultReducer : IReducer -{ - public Task ReduceAsync(ProfileCardState state, ProfileCardDefineResultAction action) - => Task.FromResult(state with - { - LastUpdate = DateTime.UtcNow, - ProfileId = action.Id, - ProfileName = action.Name, - ProfilePicture = action.Picture - }); -} -``` - -### **Define StateFeature**: - -```csharp -public record ProfileCardState : IStateFeature -{ - public string? ProfileName { get; set; } - public string? ProfilePicture { get; set; } - public string? ProfileId { get; set; } - public DateTime LastUpdate { get; set; } = DateTime.UtcNow; -} -``` - -### **Trigger Dispatch**: - -```csharp -var dispatcher = ServiceProvider.GetRequiredService(); -var stateAccessor = ServiceProvider.GetRequiredService>(); -await dispatcher.Prepare().With(p => p.TestData, name) - .DispatchAsync(); - -// You can Capture the validation in case of failure, only call if validators exist. -ValidationResult? validation = default; -await dispatcher.Prepare().With(p => p.TestData, name) - .HandleActionValidation(p => validation = p) - .DispatchAsync(); - -// You can trigger synchronously... this will await the whole pipeline, otherwise you just await until action is send to dispatch pool. -await dispatcher.Prepare().With(p => p.TestData, name) - .Sync() - .DispatchAsync(); - -// if the action is implementing ISafeState, the dispatch will always run asSafe=true but an action not implementing ISafeAction will -// have the option to run asSafe or not... -await dispatcher.Prepare().With(p => p.TestData, name) - .DispatchAsync(true); -``` - - -### Important Notes -- Rule of thumb is always await dispatch calls, avoiding to do so can cause inconsistency for safe dispatch mode.. -- ISafeAction implementations are always dispatched safely, ignoring unsafe flags. -- synchronous is an anti-pattern of statemanement use it sparingly; it is primarily for debugging or specific scenarios requiring full completion before continuation. - -### **Access State**: - -```csharp -var stateAccessor = ServiceProvider.GetRequiredService>(); -``` - -### Blazor Example Usage - -```csharp -using StatePulse.Net; - -public partial class CounterView : ComponentBase -{ - - // METHOD 1: - [Inject] public IStatePulse PulseState { get; set; } = default!; // Handles State Accessor - - // This is for convienience always use this method or directly PulseState.StateOf(this).Value - // Never assign State Instance variable as it will not update... - // Never use lambda it will throw exception as WeakREference is fundamatally flawed and disposes of lambda even when its object is alive. - private CounterState state => PulseState.StateOf(()=>this, OnUpdate); - - private async Task OnUpdate() => await InvokeAsync(StateHadChanged); - - // METHOD 2: - // Inject direct state but injecting the state directly requires you to handle onchanged events by sub/unsub in lifecycle - // Or to create a basecomponent system similar to other state management systems. - [Inject] public IStateAccessor State { get; set; } = default!; - - -} -``` \ No newline at end of file diff --git a/src/StatePulse.NET/ServiceRegisterExt.cs b/src/StatePulse.NET/ServiceRegisterExt.cs index 9917ded..45d3ab6 100644 --- a/src/StatePulse.NET/ServiceRegisterExt.cs +++ b/src/StatePulse.NET/ServiceRegisterExt.cs @@ -7,20 +7,18 @@ namespace StatePulse.Net; public static class ServiceRegisterExt { private static bool _scanned; - public static ConfigureOptions _configureOptions = new ConfigureOptions(); + public static ConfigureOptions ConfigureOptions { get; set; } = new ConfigureOptions(); private static StatePulseRegistry Registry = new StatePulseRegistry(); - /// - /// Also call AddStatePulseScan otherwise you will have to manually register all Effects, Reducers, StateAccessors and also register them inside IStatePulseRegistry. - /// - /// + + public static IServiceCollection AddStatePulseServices(this IServiceCollection services, Action configure) { // TODO: Create IDispatchFactory to bind IDispatcher and IDispatchHAndler services.AddTransient(); services.AddTransient(); - configure(_configureOptions); - - if (_configureOptions.ServiceLifetime == Lifetime.Scoped) + configure(ConfigureOptions); + ConfigureOptions.ValidateConfiguration(); + if (ConfigureOptions.ServiceLifetime == Lifetime.Scoped) services.AddScoped(); else services.AddSingleton(); @@ -28,8 +26,8 @@ public static IServiceCollection AddStatePulseServices(this IServiceCollection s services.AddTransient(); services.AddTransient(); services.AddSingleton(Registry); - if (_configureOptions.ScanAssemblies.Count() > 0) - services.ScanStatePulseAssemblies(_configureOptions.ScanAssemblies); + if (ConfigureOptions.ScanAssemblies.Count() > 0) + services.ScanStatePulseAssemblies(ConfigureOptions.ScanAssemblies); return services; } @@ -83,7 +81,7 @@ private static IServiceCollection AddStatePulseStateFeature(this IServiceCollect var accessorImplementationType = typeof(StateAccessor<>).MakeGenericType(implementation); if (services.IsStateAccessorRegistered(accessorImplementationType)) return services; - if (_configureOptions.ServiceLifetime == Lifetime.Scoped) + if (ConfigureOptions.ServiceLifetime == Lifetime.Scoped) services.AddScoped(accessorType, accessorImplementationType); else services.AddSingleton(accessorType, accessorImplementationType); @@ -122,7 +120,7 @@ private static IServiceCollection AddStatePulseAction(this IServiceCollection se var dispatchTracker = typeof(DispatchTracker<>).MakeGenericType(implementation); if (services.IsDispatchTrackerRegistered(dispatchTracker)) return services; Registry.RegisterAction(implementation); - if (_configureOptions.ServiceLifetime == Lifetime.Scoped) + if (ConfigureOptions.ServiceLifetime == Lifetime.Scoped) services.AddScoped(dispatchTrackerIface, dispatchTracker); else services.AddSingleton(dispatchTrackerIface, dispatchTracker); diff --git a/src/StatePulse.NET/StatePulse.NET.csproj b/src/StatePulse.NET/StatePulse.NET.csproj index 86e72e8..2d02d95 100644 --- a/src/StatePulse.NET/StatePulse.NET.csproj +++ b/src/StatePulse.NET/StatePulse.NET.csproj @@ -1,7 +1,7 @@ ο»Ώ - net6.0;net8.0;net9.0;net10.0 + net8.0;net10.0 12.0 enable enable @@ -15,7 +15,7 @@ StatePulse.NET Maksim Shimshon - 1.1.0 + 2.0.0 LICENSE True StatePulse.NET enables fast, consistent state/action dispatch with optional tracking and anti-duplicate flow control. It supports ordered chaining when needed, while maintaining high-performance fire-and-forget behavior for general use cases. @@ -37,10 +37,6 @@ - - - - @@ -58,16 +54,16 @@ - - - + - - - False - - + + + False + + diff --git a/src/StatePulse.Net.Abstractions/IDispatcherPrepper.cs b/src/StatePulse.Net.Abstractions/IDispatcherPrepper.cs index 3ecc221..cfd1d3d 100644 --- a/src/StatePulse.Net.Abstractions/IDispatcherPrepper.cs +++ b/src/StatePulse.Net.Abstractions/IDispatcherPrepper.cs @@ -4,5 +4,11 @@ public interface IDispatcherPrepper where TAction : IAction TAction ActionInstance { get; } IDispatcherPrepper Await(); Task DispatchAsync(bool asSafe = false); + IDispatcherPrepper EffectsFirst(); + IDispatcherPrepper ReducersFirst(); + IDispatcherPrepper ExecFireAndForget(); + IDispatcherPrepper ExecYieldAndFire(); + IDispatcherPrepper SequentialEffects(); + IDispatcherPrepper ParallelEffects(); } diff --git a/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj b/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj index 2e4a794..f04f87e 100644 --- a/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj +++ b/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj @@ -1,7 +1,7 @@ ο»Ώ - net6.0;net8.0;net9.0;net10.0 + net8.0;net10.0 12.0 enable enable @@ -15,7 +15,7 @@ StatePulse.Net.Abstractions Maksim Shimshon - 1.1.0 + 2.0.0 LICENSE True StatePulse.NET enables fast, consistent state/action dispatch with optional tracking and anti-duplicate flow control. It supports ordered chaining when needed, while maintaining high-performance fire-and-forget behavior for general use cases. @@ -40,11 +40,6 @@ \ - - - - - diff --git a/tests/StatPulse.NET.Tests/TestBase.cs b/tests/StatPulse.NET.Tests/TestBase.cs index 0f801e1..f1a5e25 100644 --- a/tests/StatPulse.NET.Tests/TestBase.cs +++ b/tests/StatPulse.NET.Tests/TestBase.cs @@ -14,37 +14,39 @@ namespace StatePulse.NET.Tests; public abstract class TestBase : IDisposable { - protected readonly IServiceProvider ServiceProvider; - + protected IServiceProvider ServiceProvider { get; set; } + protected IServiceCollection ServiceCollection { get; set; } protected TestBase() { - IServiceCollection services = new ServiceCollection(); + ServiceCollection = new ServiceCollection(); // TOOD: Remove Scan Add Manual for Tests which is best policy would most lekily avoid inconsistent // service exceptions du to thread safe on bulk testing. - services.AddStatePulseServices(o => { }); - services.AddStatePulseAction(); - services.AddStatePulseAction(); - services.AddStatePulseAction(); - services.AddStatePulseAction(); - services.AddStatePulseAction(); - services.AddStatePulseAction(); - services.AddStatePulseAction(); - services.AddStatePulseAction(); - services.AddStatePulseAction(); - services.AddStatePulseEffect(); - services.AddStatePulseEffect(); - services.AddStatePulseEffect(); - services.AddStatePulseEffectValidator(); - services.AddStatePulseEffectValidator(); - services.AddStatePulseReducer(); - services.AddStatePulseReducer(); - services.AddStatePulseReducer(); - services.AddStatePulseReducer(); - services.AddStatePulseReducer(); - services.AddStatePulseStateFeature(); - services.AddStatePulseStateFeature(); + ServiceCollection.AddStatePulseServices(o => { + + }); + ServiceCollection.AddStatePulseAction(); + ServiceCollection.AddStatePulseAction(); + ServiceCollection.AddStatePulseAction(); + ServiceCollection.AddStatePulseAction(); + ServiceCollection.AddStatePulseAction(); + ServiceCollection.AddStatePulseAction(); + ServiceCollection.AddStatePulseAction(); + ServiceCollection.AddStatePulseAction(); + ServiceCollection.AddStatePulseAction(); + ServiceCollection.AddStatePulseEffect(); + ServiceCollection.AddStatePulseEffect(); + ServiceCollection.AddStatePulseEffect(); + ServiceCollection.AddStatePulseEffectValidator(); + ServiceCollection.AddStatePulseEffectValidator(); + ServiceCollection.AddStatePulseReducer(); + ServiceCollection.AddStatePulseReducer(); + ServiceCollection.AddStatePulseReducer(); + ServiceCollection.AddStatePulseReducer(); + ServiceCollection.AddStatePulseReducer(); + ServiceCollection.AddStatePulseStateFeature(); + ServiceCollection.AddStatePulseStateFeature(); // Register your services - ServiceProvider = services.BuildServiceProvider(); + ServiceProvider = ServiceCollection.BuildServiceProvider(); } public void Dispose() { diff --git a/tests/StatPulse.NET.Tests/TestCases/InitializerTests/StatePulseInitTests.cs b/tests/StatPulse.NET.Tests/TestCases/InitializerTests/StatePulseInitTests.cs index 404acc9..f6a39c0 100644 --- a/tests/StatPulse.NET.Tests/TestCases/InitializerTests/StatePulseInitTests.cs +++ b/tests/StatPulse.NET.Tests/TestCases/InitializerTests/StatePulseInitTests.cs @@ -52,7 +52,7 @@ public async Task DispatchingEffectShouldCorrectlyTriggerActions() [Theory] [InlineData("Test")] [InlineData("Error")] - public async Task DispatchingEffectShouldCorrectlyFailActionValidator(string name) + public async Task DispatchingEffectShouldCorrectlyFailEffectValidator(string name) { var dispatcher = ServiceProvider.GetRequiredService(); var stateAccessor = ServiceProvider.GetRequiredService>(); diff --git a/tests/StatPulse.NET.Tests/TestCases/Pulsars/Profile/Effects/Validators/ProfileCardDefineActionValidator.cs b/tests/StatPulse.NET.Tests/TestCases/Pulsars/Profile/Effects/Validators/ProfileCardDefineActionValidator.cs index 0501b8b..93eee83 100644 --- a/tests/StatPulse.NET.Tests/TestCases/Pulsars/Profile/Effects/Validators/ProfileCardDefineActionValidator.cs +++ b/tests/StatPulse.NET.Tests/TestCases/Pulsars/Profile/Effects/Validators/ProfileCardDefineActionValidator.cs @@ -2,6 +2,10 @@ using StatePulse.NET.Tests.TestCases.Pulsars.Profile.Actions; namespace StatePulse.NET.Tests.TestCases.Pulsars.Profile.Effects.Validators; +/* +* This is the best way to define clean conditional effects, it either run or not... this is not meant for triggering errors. +* This is meant for optional/condition effects to either run or not base on the action settings... +*/ internal class ProfileCardDefineActionValidator : IEffectValidator { public Task Validate(ProfileCardDefineAction action) From 09a4238d13c0fe5c16772c6adae015e8399ce4c1 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Sun, 21 Dec 2025 12:36:26 +0200 Subject: [PATCH 02/27] wip --- doc/docs/0.Versions.md | 23 +- src/StatePulse.NET.sln | 22 +- .../Configuration/ConfigureOptions.cs | 11 +- .../Configuration/GlobalTrackingLifetime.cs | 15 + .../Configuration/MiddlewareEffectBehavior.cs | 1 - .../Configuration/PulseTrackingModel.cs | 15 + .../Implementations/DispatcherPrepper.cs | 21 - .../Implementations/PulseGlobalTracker.cs | 3 + .../Engine/PulseLazyStateBase.cs | 1 - src/StatePulse.NET/ServiceRegisterExt.cs | 46 +- src/StatePulse.NET/StatePulse.NET.csproj | 2 +- .../IPulseGlobalTracker.cs | 9 +- .../IStateFeatureSingleton.cs | 11 + .../IStatePulseRegistry.cs | 12 +- .../StatePulse.Net.Abstractions.csproj | 2 +- .../Pages/Counter.razor | 26 + .../Pages/Counter.razor.cs | 38 + .../Program.cs | 6 + .../Counter/Action/CounterIncreaseAction.cs | 4 + .../Action/CounterSingletonIncreaseAction.cs | 4 + .../Reducers/CounterIncreaseReducer.cs | 9 + .../CounterSingletonIncreaseReducer.cs | 9 + .../Counter/Stores/CounterSingletonState.cs | 5 + .../Pulses/Counter/Stores/CounterState.cs | 5 + ...tePulse.Net.BlazorServerTest.Client.csproj | 26 + .../_Imports.razor | 9 + .../wwwroot/appsettings.Development.json | 8 + .../wwwroot/appsettings.json | 8 + .../Components/App.razor | 23 + .../Components/Layout/MainLayout.razor | 23 + .../Components/Layout/MainLayout.razor.css | 98 + .../Components/Layout/NavMenu.razor | 30 + .../Components/Layout/NavMenu.razor.css | 105 + .../Components/Layout/ReconnectModal.razor | 31 + .../Layout/ReconnectModal.razor.css | 157 + .../Components/Layout/ReconnectModal.razor.js | 63 + .../Components/Pages/Error.razor | 36 + .../Components/Pages/Home.razor | 7 + .../Components/Pages/NotFound.razor | 5 + .../Components/Pages/Weather.razor | 64 + .../Components/Routes.razor | 6 + .../Components/_Imports.razor | 12 + .../Program.cs | 43 + .../Properties/launchSettings.json | 25 + .../StatePulse.Net.BlazorServerTest.csproj | 16 + .../appsettings.Development.json | 8 + .../appsettings.json | 9 + .../wwwroot/app.css | 60 + .../wwwroot/favicon.png | Bin 0 -> 1148 bytes .../lib/bootstrap/dist/css/bootstrap-grid.css | 4085 ++++++ .../bootstrap/dist/css/bootstrap-grid.css.map | 1 + .../bootstrap/dist/css/bootstrap-grid.min.css | 6 + .../dist/css/bootstrap-grid.min.css.map | 1 + .../bootstrap/dist/css/bootstrap-grid.rtl.css | 4084 ++++++ .../dist/css/bootstrap-grid.rtl.css.map | 1 + .../dist/css/bootstrap-grid.rtl.min.css | 6 + .../dist/css/bootstrap-grid.rtl.min.css.map | 1 + .../bootstrap/dist/css/bootstrap-reboot.css | 597 + .../dist/css/bootstrap-reboot.css.map | 1 + .../dist/css/bootstrap-reboot.min.css | 6 + .../dist/css/bootstrap-reboot.min.css.map | 1 + .../dist/css/bootstrap-reboot.rtl.css | 594 + .../dist/css/bootstrap-reboot.rtl.css.map | 1 + .../dist/css/bootstrap-reboot.rtl.min.css | 6 + .../dist/css/bootstrap-reboot.rtl.min.css.map | 1 + .../dist/css/bootstrap-utilities.css | 5402 +++++++ .../dist/css/bootstrap-utilities.css.map | 1 + .../dist/css/bootstrap-utilities.min.css | 6 + .../dist/css/bootstrap-utilities.min.css.map | 1 + .../dist/css/bootstrap-utilities.rtl.css | 5393 +++++++ .../dist/css/bootstrap-utilities.rtl.css.map | 1 + .../dist/css/bootstrap-utilities.rtl.min.css | 6 + .../css/bootstrap-utilities.rtl.min.css.map | 1 + .../lib/bootstrap/dist/css/bootstrap.css | 12057 ++++++++++++++++ .../lib/bootstrap/dist/css/bootstrap.css.map | 1 + .../lib/bootstrap/dist/css/bootstrap.min.css | 6 + .../bootstrap/dist/css/bootstrap.min.css.map | 1 + .../lib/bootstrap/dist/css/bootstrap.rtl.css | 12030 +++++++++++++++ .../bootstrap/dist/css/bootstrap.rtl.css.map | 1 + .../bootstrap/dist/css/bootstrap.rtl.min.css | 6 + .../dist/css/bootstrap.rtl.min.css.map | 1 + .../lib/bootstrap/dist/js/bootstrap.bundle.js | 6314 ++++++++ .../bootstrap/dist/js/bootstrap.bundle.js.map | 1 + .../bootstrap/dist/js/bootstrap.bundle.min.js | 7 + .../dist/js/bootstrap.bundle.min.js.map | 1 + .../lib/bootstrap/dist/js/bootstrap.esm.js | 4447 ++++++ .../bootstrap/dist/js/bootstrap.esm.js.map | 1 + .../bootstrap/dist/js/bootstrap.esm.min.js | 7 + .../dist/js/bootstrap.esm.min.js.map | 1 + .../lib/bootstrap/dist/js/bootstrap.js | 4494 ++++++ .../lib/bootstrap/dist/js/bootstrap.js.map | 1 + .../lib/bootstrap/dist/js/bootstrap.min.js | 7 + .../bootstrap/dist/js/bootstrap.min.js.map | 1 + tests/StatPulse.NET.Tests/TestBase.cs | 9 + .../InitializerTests/StatePulseInitTests.cs | 94 +- .../Counter/Actions/UpdateCounterAction.cs | 14 + .../Counter/Reducers/UpdateCounterReducer.cs | 16 + .../Pulsars/Counter/States/CounterState.cs | 13 + .../Action/CounterSingletonIncreaseAction.cs | 4 + .../CounterSingletonIncreaseReducer.cs | 9 + .../Counter/Stores/CounterSingletonState.cs | 5 + 101 files changed, 60859 insertions(+), 65 deletions(-) create mode 100644 src/StatePulse.NET/Configuration/GlobalTrackingLifetime.cs create mode 100644 src/StatePulse.NET/Configuration/PulseTrackingModel.cs create mode 100644 src/StatePulse.Net.Abstractions/IStateFeatureSingleton.cs create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pages/Counter.razor create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pages/Counter.razor.cs create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Program.cs create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Action/CounterIncreaseAction.cs create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Action/CounterSingletonIncreaseAction.cs create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Reducers/CounterIncreaseReducer.cs create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Reducers/CounterSingletonIncreaseReducer.cs create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Stores/CounterSingletonState.cs create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Stores/CounterState.cs create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/StatePulse.Net.BlazorServerTest.Client.csproj create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/_Imports.razor create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/wwwroot/appsettings.Development.json create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/wwwroot/appsettings.json create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/App.razor create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/MainLayout.razor create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/MainLayout.razor.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/NavMenu.razor create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/NavMenu.razor.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/ReconnectModal.razor create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/ReconnectModal.razor.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/ReconnectModal.razor.js create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Pages/Error.razor create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Pages/Home.razor create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Pages/NotFound.razor create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Pages/Weather.razor create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Routes.razor create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/_Imports.razor create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Program.cs create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Properties/launchSettings.json create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.csproj create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/appsettings.Development.json create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/appsettings.json create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/app.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/favicon.png create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap.css.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/js/bootstrap.js create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/js/bootstrap.js.map create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js create mode 100644 src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js.map create mode 100644 tests/StatPulse.NET.Tests/TestCases/Pulsars/Counter/Actions/UpdateCounterAction.cs create mode 100644 tests/StatPulse.NET.Tests/TestCases/Pulsars/Counter/Reducers/UpdateCounterReducer.cs create mode 100644 tests/StatPulse.NET.Tests/TestCases/Pulsars/Counter/States/CounterState.cs create mode 100644 tests/StatePulse.Net.Tests.App/Pulsars/Counter/Action/CounterSingletonIncreaseAction.cs create mode 100644 tests/StatePulse.Net.Tests.App/Pulsars/Counter/Reducers/CounterSingletonIncreaseReducer.cs create mode 100644 tests/StatePulse.Net.Tests.App/Pulsars/Counter/Stores/CounterSingletonState.cs diff --git a/doc/docs/0.Versions.md b/doc/docs/0.Versions.md index b23a3df..2a52abc 100644 --- a/doc/docs/0.Versions.md +++ b/doc/docs/0.Versions.md @@ -6,8 +6,20 @@ sidebar_position: 0 ## πŸ“¦ v2.0.0 ### ✨ BREAKING CHANGES -- The signature of interfaces changed so any plugin-based system could potentially break if core updates and plugins don't unless plugin isolation is respected. -- The REDUCERS now run before the effects! so any pipelines relying on post-effect reducers should configure StatePulse to execute reducers post effect (simple config flip) `Configure.DispatchOrderBehavior = DispatchOrdering.EffectsFirst;`. +### ✨ BREAKING CHANGES + +- **Interface signatures have changed.** + Core interface updates may break plugin‑based systems if the core updates while plugins do not. + This is only safe when proper plugin isolation is respected. + +- **Reducers now run before effects.** + The default dispatch order has changed. + Pipelines that rely on reducers running after effects must update their configuration to restore the previous behavior. + +- **Middleware between individual effects has been removed.** + Per‑effect middleware proved unreliable and is no longer supported. + All effects now run as a batch, followed by a single AfterEffect phase. + Middleware can still be awaited before the BeforeEffect phase and after the AfterEffect phase. ### ✨ New Features - **βš™οΈ Enhanced Configuration Options** - New global configuration properties: @@ -24,6 +36,13 @@ sidebar_position: 0 - `.ParallelEffects()` - Force effects to run in parallel - **πŸ›‘οΈ Invalid Configuration Detection** - New `InvalidDispatchCombinationException` thrown at dispatch time for incompatible configuration combinations (Plan to generate compiler errors later) - **♻️ Recursive Dispatch Support** - Fire-and-forget mode enables safe recursive dispatch patterns without deadlocks +- `PulseTrackingModel` - Clear option for the tracking model! Either Thread-Safe (`Default`) or Single Threaded Fast Application... WASM/Blazor Server. +- `GlobalTrackerLifetime` - Define clearly lifetime scope for the Global Tracker singleton or scoped. `BlazorServer`, `WASM`, `Scoped` (Default) or `Singleton`. +- `IStateFeatureSingleton` - Define a singleton state across your app... not useful in WASM but very useful in Blazor Server... where one can share the state across client each client run their own action but the state update spread across all circuits. + +### 🐞 Fixes +- Fixed Various Warnings +- Fixed All Configure Internal... ## πŸ“¦ v1.1.0 diff --git a/src/StatePulse.NET.sln b/src/StatePulse.NET.sln index e6b2919..7cc9d2c 100644 --- a/src/StatePulse.NET.sln +++ b/src/StatePulse.NET.sln @@ -1,7 +1,7 @@ ο»Ώ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 18 -VisualStudioVersion = 18.0.11222.15 d18.0 +VisualStudioVersion = 18.0.11222.15 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}" ProjectSection(SolutionItems) = preProject @@ -13,12 +13,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatePulse.NET.Tests", "..\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatePulse.NET", "StatePulse.NET\StatePulse.NET.csproj", "{001E330A-2F3E-D401-1119-2C5AEC9243AA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatePulse.Net.Tests.App", "..\tests\StatePulse.Net.Tests.App\StatePulse.Net.Tests.App.csproj", "{2C1CC5ED-698A-41D9-9436-629115326499}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatePulse.Net.Analyzers", "StatePulse.Net.Analyzers\StatePulse.Net.Analyzers.csproj", "{62E34523-4C01-492E-9957-A14F70799C71}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatePulse.Net.Abstractions", "StatePulse.Net.Abstractions\StatePulse.Net.Abstractions.csproj", "{EEC112B4-18B6-414F-BC15-F525B2C90AEF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatePulse.Net.BlazorServerTest", "StatePulse.Net.BlazorServerTest\StatePulse.Net.BlazorServerTest\StatePulse.Net.BlazorServerTest.csproj", "{91D39E25-8E38-45A0-A0BD-E59AC72EA507}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatePulse.Net.BlazorServerTest.Client", "StatePulse.Net.BlazorServerTest\StatePulse.Net.BlazorServerTest.Client\StatePulse.Net.BlazorServerTest.Client.csproj", "{DCB8495F-3B22-4797-A027-C61850527E2B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,12 +35,6 @@ Global {001E330A-2F3E-D401-1119-2C5AEC9243AA}.Debug|Any CPU.Build.0 = Debug|Any CPU {001E330A-2F3E-D401-1119-2C5AEC9243AA}.Release|Any CPU.ActiveCfg = Release|Any CPU {001E330A-2F3E-D401-1119-2C5AEC9243AA}.Release|Any CPU.Build.0 = Release|Any CPU - {2C1CC5ED-698A-41D9-9436-629115326499}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2C1CC5ED-698A-41D9-9436-629115326499}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2C1CC5ED-698A-41D9-9436-629115326499}.Debug|Any CPU.Deploy.0 = Debug|Any CPU - {2C1CC5ED-698A-41D9-9436-629115326499}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2C1CC5ED-698A-41D9-9436-629115326499}.Release|Any CPU.Build.0 = Release|Any CPU - {2C1CC5ED-698A-41D9-9436-629115326499}.Release|Any CPU.Deploy.0 = Release|Any CPU {62E34523-4C01-492E-9957-A14F70799C71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {62E34523-4C01-492E-9957-A14F70799C71}.Debug|Any CPU.Build.0 = Debug|Any CPU {62E34523-4C01-492E-9957-A14F70799C71}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -47,6 +43,14 @@ Global {EEC112B4-18B6-414F-BC15-F525B2C90AEF}.Debug|Any CPU.Build.0 = Debug|Any CPU {EEC112B4-18B6-414F-BC15-F525B2C90AEF}.Release|Any CPU.ActiveCfg = Release|Any CPU {EEC112B4-18B6-414F-BC15-F525B2C90AEF}.Release|Any CPU.Build.0 = Release|Any CPU + {91D39E25-8E38-45A0-A0BD-E59AC72EA507}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {91D39E25-8E38-45A0-A0BD-E59AC72EA507}.Debug|Any CPU.Build.0 = Debug|Any CPU + {91D39E25-8E38-45A0-A0BD-E59AC72EA507}.Release|Any CPU.ActiveCfg = Release|Any CPU + {91D39E25-8E38-45A0-A0BD-E59AC72EA507}.Release|Any CPU.Build.0 = Release|Any CPU + {DCB8495F-3B22-4797-A027-C61850527E2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DCB8495F-3B22-4797-A027-C61850527E2B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DCB8495F-3B22-4797-A027-C61850527E2B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DCB8495F-3B22-4797-A027-C61850527E2B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/StatePulse.NET/Configuration/ConfigureOptions.cs b/src/StatePulse.NET/Configuration/ConfigureOptions.cs index 947d1d3..b416ef5 100644 --- a/src/StatePulse.NET/Configuration/ConfigureOptions.cs +++ b/src/StatePulse.NET/Configuration/ConfigureOptions.cs @@ -7,11 +7,12 @@ public class ConfigureOptions /// Scoped on WASM = Singleton, Singleton on Blazor Server = Chaos Data Leakage /// public Lifetime ServiceLifetime { get; set; } = Lifetime.Scoped; - public MiddlewareEffectBehavior MiddlewareEffectBehavior { get; internal set; } = MiddlewareEffectBehavior.PerGroupEffects; - public MiddlewareTaskBehavior MiddlewareTaskBehavior { get; internal set; } = MiddlewareTaskBehavior.DoNotAwait; - public DispatchEffectBehavior DispatchEffectBehavior { get; internal set; } = DispatchEffectBehavior.Parallel; - public DispatchEffectExecutionBehavior DispatchEffectExecutionBehavior { get; internal set; } = DispatchEffectExecutionBehavior.YieldAndFire; - public DispatchOrdering DispatchOrderBehavior { get; internal set; } = DispatchOrdering.ReducersFirst; + public MiddlewareEffectBehavior MiddlewareEffectBehavior { get; set; } = MiddlewareEffectBehavior.PerGroupEffects; + public MiddlewareTaskBehavior MiddlewareTaskBehavior { get; set; } = MiddlewareTaskBehavior.DoNotAwait; + public DispatchEffectBehavior DispatchEffectBehavior { get; set; } = DispatchEffectBehavior.Parallel; + public DispatchEffectExecutionBehavior DispatchEffectExecutionBehavior { get; set; } = DispatchEffectExecutionBehavior.YieldAndFire; + public DispatchOrdering DispatchOrderBehavior { get; set; } = DispatchOrdering.ReducersFirst; + public PulseTrackingModel PulseTrackingPerformance { get; set; } = PulseTrackingModel.ThreadSafe; public Type[] ScanAssemblies { get; set; } = new Type[] { }; public void ValidateConfiguration() diff --git a/src/StatePulse.NET/Configuration/GlobalTrackingLifetime.cs b/src/StatePulse.NET/Configuration/GlobalTrackingLifetime.cs new file mode 100644 index 0000000..e00a42d --- /dev/null +++ b/src/StatePulse.NET/Configuration/GlobalTrackingLifetime.cs @@ -0,0 +1,15 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StatePulse.Net.Configuration; + +public enum GlobalTrackingLifetime +{ + Singleton, + Scoped, + BlazorServer, + BlazorWebAssembly, +} diff --git a/src/StatePulse.NET/Configuration/MiddlewareEffectBehavior.cs b/src/StatePulse.NET/Configuration/MiddlewareEffectBehavior.cs index 675bc89..fc4124a 100644 --- a/src/StatePulse.NET/Configuration/MiddlewareEffectBehavior.cs +++ b/src/StatePulse.NET/Configuration/MiddlewareEffectBehavior.cs @@ -1,6 +1,5 @@ ο»Ώnamespace StatePulse.Net.Configuration; public enum MiddlewareEffectBehavior { - PerIndividualEffect, PerGroupEffects } diff --git a/src/StatePulse.NET/Configuration/PulseTrackingModel.cs b/src/StatePulse.NET/Configuration/PulseTrackingModel.cs new file mode 100644 index 0000000..d8c8c0d --- /dev/null +++ b/src/StatePulse.NET/Configuration/PulseTrackingModel.cs @@ -0,0 +1,15 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StatePulse.Net.Configuration; + +public enum PulseTrackingModel +{ + ThreadSafe, + SingleThreadFast, + BlazorServerSafe, + BlazorWebAssemblyFast, +} diff --git a/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs b/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs index 8c50645..9aa13d3 100644 --- a/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs +++ b/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs @@ -182,10 +182,6 @@ private async Task RunEffects(DispatchTrackingIdentity? nextChain, IDispatchFact { if (nextChain != default && _tracker.IsCancelled(nextChain.Id)) break; - effectMiddlewareTasks = RunMiddlewareEffect(effectMiddlewares, p => p.BeforeEffect(_action), p => p == MiddlewareEffectBehavior.PerIndividualEffect); - - if (ServiceRegisterExt.ConfigureOptions.MiddlewareTaskBehavior == Configuration.MiddlewareTaskBehavior.Await) - await effectMiddlewareTasks; bool validationPassed = await RunEffectValidators(effectService!.GetType(), effectMiddlewares); if (!validationPassed) @@ -204,23 +200,6 @@ private async Task RunEffects(DispatchTrackingIdentity? nextChain, IDispatchFact else await effectTask; } - - if (ServiceRegisterExt.ConfigureOptions.MiddlewareEffectBehavior == MiddlewareEffectBehavior.PerIndividualEffect) - { - if (_dispatchEffectExecutionBehavior == DispatchEffectExecutionBehavior.FireAndForget) - _ = effectMiddlewareTasks; - else - await effectMiddlewareTasks; - } - - - var effectMiddlewareAfterTasks = RunMiddlewareEffect(effectMiddlewares, p => p.AfterEffect(_action), p => p == MiddlewareEffectBehavior.PerIndividualEffect); - if (ServiceRegisterExt.ConfigureOptions.MiddlewareTaskBehavior == Configuration.MiddlewareTaskBehavior.Await) - if (_dispatchEffectExecutionBehavior == DispatchEffectExecutionBehavior.FireAndForget) - _ = effectMiddlewareAfterTasks; - else - await effectMiddlewareAfterTasks; - } if (_dispatchEffectExecutionBehavior == DispatchEffectExecutionBehavior.FireAndForget) { diff --git a/src/StatePulse.NET/Engine/Implementations/PulseGlobalTracker.cs b/src/StatePulse.NET/Engine/Implementations/PulseGlobalTracker.cs index bb4d8c8..4deae93 100644 --- a/src/StatePulse.NET/Engine/Implementations/PulseGlobalTracker.cs +++ b/src/StatePulse.NET/Engine/Implementations/PulseGlobalTracker.cs @@ -14,6 +14,9 @@ private IReadOnlyList _readRegistry return _registry.ToList(); } } + + public IReadOnlyCollection Registered => _registry; + private readonly Timer _timer; public event EventHandler? onAfterCleanUp; diff --git a/src/StatePulse.NET/Engine/PulseLazyStateBase.cs b/src/StatePulse.NET/Engine/PulseLazyStateBase.cs index a9f8a41..00dc005 100644 --- a/src/StatePulse.NET/Engine/PulseLazyStateBase.cs +++ b/src/StatePulse.NET/Engine/PulseLazyStateBase.cs @@ -54,7 +54,6 @@ public void SelfDisposeCheck() return; } } - // Placeholder method for event handler private void OnStateChanged(object? sender, EventArgs Args) { if (!_instance.TryGetTarget(out var target)) diff --git a/src/StatePulse.NET/ServiceRegisterExt.cs b/src/StatePulse.NET/ServiceRegisterExt.cs index 45d3ab6..cb8cb24 100644 --- a/src/StatePulse.NET/ServiceRegisterExt.cs +++ b/src/StatePulse.NET/ServiceRegisterExt.cs @@ -4,29 +4,30 @@ using StatePulse.Net.Engine.Implementations; namespace StatePulse.Net; + public static class ServiceRegisterExt { private static bool _scanned; - public static ConfigureOptions ConfigureOptions { get; set; } = new ConfigureOptions(); + public static ConfigureOptions ConfigureOptions { get; set; } = new ConfigureOptions(); private static StatePulseRegistry Registry = new StatePulseRegistry(); public static IServiceCollection AddStatePulseServices(this IServiceCollection services, Action configure) { - // TODO: Create IDispatchFactory to bind IDispatcher and IDispatchHAndler services.AddTransient(); services.AddTransient(); configure(ConfigureOptions); ConfigureOptions.ValidateConfiguration(); - if (ConfigureOptions.ServiceLifetime == Lifetime.Scoped) - services.AddScoped(); + services.AddSingleton(); + + bool isSingleThreadModel = ConfigureOptions.PulseTrackingPerformance == PulseTrackingModel.SingleThreadFast || ConfigureOptions.PulseTrackingPerformance == PulseTrackingModel.BlazorWebAssemblyFast; + if (isSingleThreadModel) + services.AddTransient(); else - services.AddSingleton(); + services.AddTransient(); - services.AddTransient(); - services.AddTransient(); services.AddSingleton(Registry); - if (ConfigureOptions.ScanAssemblies.Count() > 0) + if (ConfigureOptions.ScanAssemblies.Any()) services.ScanStatePulseAssemblies(ConfigureOptions.ScanAssemblies); return services; @@ -74,17 +75,36 @@ private static IServiceCollection AddStatePulseReducer(this IServiceCollection s public static IServiceCollection AddStatePulseStateFeature(this IServiceCollection services) where TImplementation : IStateFeature => services.AddStatePulseStateFeature(typeof(TImplementation)); + //private static IServiceCollection AddStatePulseStateFeature(this IServiceCollection services, Type implementation) + //{ + // var accessorType = typeof(IStateAccessor<>).MakeGenericType(implementation); + // var accessorImplementationType = typeof(StateAccessor<>).MakeGenericType(implementation); + + // if (services.IsStateAccessorRegistered(accessorImplementationType)) return services; + // if (ConfigureOptions.ServiceLifetime == Lifetime.Scoped) + // services.AddScoped(accessorType, accessorImplementationType); + // else + // services.AddSingleton(accessorType, accessorImplementationType); + + // Registry.RegisterState(implementation); + // return services; + //} private static IServiceCollection AddStatePulseStateFeature(this IServiceCollection services, Type implementation) - { var accessorType = typeof(IStateAccessor<>).MakeGenericType(implementation); var accessorImplementationType = typeof(StateAccessor<>).MakeGenericType(implementation); - if (services.IsStateAccessorRegistered(accessorImplementationType)) return services; - if (ConfigureOptions.ServiceLifetime == Lifetime.Scoped) - services.AddScoped(accessorType, accessorImplementationType); - else + if (services.IsStateAccessorRegistered(accessorImplementationType)) + return services; + + // Check if the state implements IStateFeatureSingleton + bool isSingletonFeature = typeof(IStateFeatureSingleton).IsAssignableFrom(implementation); + + if (isSingletonFeature) services.AddSingleton(accessorType, accessorImplementationType); + else + services.AddScoped(accessorType, accessorImplementationType); + Registry.RegisterState(implementation); return services; diff --git a/src/StatePulse.NET/StatePulse.NET.csproj b/src/StatePulse.NET/StatePulse.NET.csproj index 2d02d95..bb47ad1 100644 --- a/src/StatePulse.NET/StatePulse.NET.csproj +++ b/src/StatePulse.NET/StatePulse.NET.csproj @@ -31,7 +31,7 @@ True \ - + True \ diff --git a/src/StatePulse.Net.Abstractions/IPulseGlobalTracker.cs b/src/StatePulse.Net.Abstractions/IPulseGlobalTracker.cs index 6498dc1..9d78f34 100644 --- a/src/StatePulse.Net.Abstractions/IPulseGlobalTracker.cs +++ b/src/StatePulse.Net.Abstractions/IPulseGlobalTracker.cs @@ -1,8 +1,9 @@ ο»Ώnamespace StatePulse.Net; public interface IPulseGlobalTracker { - public int ActivePulsars { get; } - public void Register(IStatePulse pulsar); - public void UnRegister(IStatePulse pulsar); - public event EventHandler? onAfterCleanUp; + int ActivePulsars { get; } + void Register(IStatePulse pulsar); + void UnRegister(IStatePulse pulsar); + IReadOnlyCollection Registered { get; } + event EventHandler? onAfterCleanUp; } diff --git a/src/StatePulse.Net.Abstractions/IStateFeatureSingleton.cs b/src/StatePulse.Net.Abstractions/IStateFeatureSingleton.cs new file mode 100644 index 0000000..3351474 --- /dev/null +++ b/src/StatePulse.Net.Abstractions/IStateFeatureSingleton.cs @@ -0,0 +1,11 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StatePulse.Net; + +public interface IStateFeatureSingleton : IStateFeature +{ +} diff --git a/src/StatePulse.Net.Abstractions/IStatePulseRegistry.cs b/src/StatePulse.Net.Abstractions/IStatePulseRegistry.cs index a140e43..5f00d68 100644 --- a/src/StatePulse.Net.Abstractions/IStatePulseRegistry.cs +++ b/src/StatePulse.Net.Abstractions/IStatePulseRegistry.cs @@ -6,12 +6,12 @@ public interface IStatePulseRegistry IReadOnlyDictionary KnownEffects { get; } IReadOnlyDictionary KnownReducers { get; } IReadOnlyDictionary> KnownReducersReduceMethod { get; } - public IReadOnlyList KnownActions { get; } - public IReadOnlyDictionary KnownActionValidators { get; } - public IReadOnlyDictionary> KnownStateAccessorsStateGetter { get; } - public IReadOnlyDictionary> KnownStateAccessorsStateSetter { get; } - public IReadOnlyDictionary> KnownReducersTaskResult { get; } - public IReadOnlyDictionary KnownStateToAccessors { get; } + IReadOnlyList KnownActions { get; } + IReadOnlyDictionary KnownActionValidators { get; } + IReadOnlyDictionary> KnownStateAccessorsStateGetter { get; } + IReadOnlyDictionary> KnownStateAccessorsStateSetter { get; } + IReadOnlyDictionary> KnownReducersTaskResult { get; } + IReadOnlyDictionary KnownStateToAccessors { get; } void RegisterState(Type stateType); void RegisterEffect(Type effectType, Type interfaceType); diff --git a/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj b/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj index f04f87e..b171a89 100644 --- a/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj +++ b/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj @@ -27,7 +27,7 @@ True \ - + True \ diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pages/Counter.razor b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pages/Counter.razor new file mode 100644 index 0000000..182989f --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pages/Counter.razor @@ -0,0 +1,26 @@ +ο»Ώ@page "/counter" +@rendermode InteractiveServer + +Counter + +

    Counter

    + + +

    Current Singleton count: @Shared.Count

    + +@*

    Current count: @State.Count

    *@ +@* *@ + +
    +

    + Global Tracker Info: @($"{_pulseGlobalTracker.ActivePulsars} Pulsars")

    +

    Global Tracker Info:

    +@foreach (var t in _statePulseRegistry.KnownStates) +{ +

    @t.FullName

    +} + +@foreach (var t in _statePulseRegistry.KnownStateToAccessors) +{ +

    @t.Value.FullName

    +} \ No newline at end of file diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pages/Counter.razor.cs b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pages/Counter.razor.cs new file mode 100644 index 0000000..1a7c328 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pages/Counter.razor.cs @@ -0,0 +1,38 @@ +ο»Ώusing Microsoft.AspNetCore.Components; +using StatePulse.Net.BlazorServerTest.Client.Pulses.Counter.Action; +using StatePulse.Net.BlazorServerTest.Client.Pulses.Counter.Stores; +using System.Diagnostics; + +namespace StatePulse.Net.BlazorServerTest.Client.Pages; + +public partial class Counter : ComponentBase +{ + [Inject] IStatePulse _statePulse { get; set; } = default!; + [Inject] IDispatcher _dispatcher { get; set; } = default!; + [Inject] IPulseGlobalTracker _pulseGlobalTracker { get; set; } = default!; + [Inject] IStatePulseRegistry _statePulseRegistry { get; set; } = default!; + [Inject] IStateAccessor _stateAccessor { get; set; } = default!; + + + public CounterSingletonState Shared => _statePulse.StateOf(() => this, OnUpdate); + //public CounterState State => _statePulse.StateOf(() => this, OnUpdate); + private async Task OnUpdate() + { + Debugger.Break(); + StateHasChanged(); + } + + protected override void OnInitialized() + { + //_stateAccessor.OnStateChangedNoDetails += (_, e)=> StateHasChanged(); + } + private async Task SingletonIncrease() + { + await _dispatcher.Prepare().DispatchAsync(); + } + + private async Task Increase() + { + await _dispatcher.Prepare().DispatchAsync(); + } +} diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Program.cs b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Program.cs new file mode 100644 index 0000000..91d1e28 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Program.cs @@ -0,0 +1,6 @@ +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; +using StatePulse.Net; +using StatePulse.Net.Configuration; +var builder = WebAssemblyHostBuilder.CreateDefault(args); + +await builder.Build().RunAsync(); diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Action/CounterIncreaseAction.cs b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Action/CounterIncreaseAction.cs new file mode 100644 index 0000000..73e44d2 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Action/CounterIncreaseAction.cs @@ -0,0 +1,4 @@ +ο»Ώnamespace StatePulse.Net.BlazorServerTest.Client.Pulses.Counter.Action; +public class CounterIncreaseAction : IAction +{ +} diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Action/CounterSingletonIncreaseAction.cs b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Action/CounterSingletonIncreaseAction.cs new file mode 100644 index 0000000..592b2d1 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Action/CounterSingletonIncreaseAction.cs @@ -0,0 +1,4 @@ +ο»Ώnamespace StatePulse.Net.BlazorServerTest.Client.Pulses.Counter.Action; +public class CounterSingletonIncreaseAction : IAction +{ +} diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Reducers/CounterIncreaseReducer.cs b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Reducers/CounterIncreaseReducer.cs new file mode 100644 index 0000000..80a2e5d --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Reducers/CounterIncreaseReducer.cs @@ -0,0 +1,9 @@ +ο»Ώusing StatePulse.Net.BlazorServerTest.Client.Pulses.Counter.Action; +using StatePulse.Net.BlazorServerTest.Client.Pulses.Counter.Stores; + +namespace StatePulse.Net.BlazorServerTest.Client.Pulses.Counter.Reducers; +internal class CounterIncreaseReducer : IReducer +{ + public Task ReduceAsync(CounterState state, CounterIncreaseAction action) + => Task.FromResult(state with { Count = state.Count + 1 }); +} diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Reducers/CounterSingletonIncreaseReducer.cs b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Reducers/CounterSingletonIncreaseReducer.cs new file mode 100644 index 0000000..055343a --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Reducers/CounterSingletonIncreaseReducer.cs @@ -0,0 +1,9 @@ +ο»Ώusing StatePulse.Net.BlazorServerTest.Client.Pulses.Counter.Action; +using StatePulse.Net.BlazorServerTest.Client.Pulses.Counter.Stores; + +namespace StatePulse.Net.BlazorServerTest.Client.Pulses.Counter.Reducers; +internal class CounterSingletonIncreaseReducer : IReducer +{ + public Task ReduceAsync(CounterSingletonState state, CounterSingletonIncreaseAction action) + => Task.FromResult(state with { Count = state.Count + 1 }); +} diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Stores/CounterSingletonState.cs b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Stores/CounterSingletonState.cs new file mode 100644 index 0000000..9958fb7 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Stores/CounterSingletonState.cs @@ -0,0 +1,5 @@ +ο»Ώnamespace StatePulse.Net.BlazorServerTest.Client.Pulses.Counter.Stores; +public record CounterSingletonState : IStateFeatureSingleton +{ + public int Count { get; set; } +} diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Stores/CounterState.cs b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Stores/CounterState.cs new file mode 100644 index 0000000..72e767c --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Stores/CounterState.cs @@ -0,0 +1,5 @@ +ο»Ώnamespace StatePulse.Net.BlazorServerTest.Client.Pulses.Counter.Stores; +public record CounterState : IStateFeature +{ + public int Count { get; set; } +} diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/StatePulse.Net.BlazorServerTest.Client.csproj b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/StatePulse.Net.BlazorServerTest.Client.csproj new file mode 100644 index 0000000..6e8e962 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/StatePulse.Net.BlazorServerTest.Client.csproj @@ -0,0 +1,26 @@ + + + + net10.0 + enable + enable + true + Default + true + + + + + + + + + + + + + + + + + diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/_Imports.razor b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/_Imports.razor new file mode 100644 index 0000000..27939a7 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/_Imports.razor @@ -0,0 +1,9 @@ +ο»Ώ@using System.Net.Http +@using System.Net.Http.Json +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using static Microsoft.AspNetCore.Components.Web.RenderMode +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.JSInterop +@using StatePulse.Net.BlazorServerTest.Client diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/wwwroot/appsettings.Development.json b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/wwwroot/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/wwwroot/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/wwwroot/appsettings.json b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/wwwroot/appsettings.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/wwwroot/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/App.razor b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/App.razor new file mode 100644 index 0000000..85302bc --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/App.razor @@ -0,0 +1,23 @@ +ο»Ώ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/MainLayout.razor b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/MainLayout.razor new file mode 100644 index 0000000..78624f3 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/MainLayout.razor @@ -0,0 +1,23 @@ +ο»Ώ@inherits LayoutComponentBase + +
    + + +
    +
    + About +
    + +
    + @Body +
    +
    +
    + +
    + An unhandled error has occurred. + Reload + πŸ—™ +
    diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/MainLayout.razor.css b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/MainLayout.razor.css new file mode 100644 index 0000000..38d1f25 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/MainLayout.razor.css @@ -0,0 +1,98 @@ +.page { + position: relative; + display: flex; + flex-direction: column; +} + +main { + flex: 1; +} + +.sidebar { + background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); +} + +.top-row { + background-color: #f7f7f7; + border-bottom: 1px solid #d6d5d5; + justify-content: flex-end; + height: 3.5rem; + display: flex; + align-items: center; +} + + .top-row ::deep a, .top-row ::deep .btn-link { + white-space: nowrap; + margin-left: 1.5rem; + text-decoration: none; + } + + .top-row ::deep a:hover, .top-row ::deep .btn-link:hover { + text-decoration: underline; + } + + .top-row ::deep a:first-child { + overflow: hidden; + text-overflow: ellipsis; + } + +@media (max-width: 640.98px) { + .top-row { + justify-content: space-between; + } + + .top-row ::deep a, .top-row ::deep .btn-link { + margin-left: 0; + } +} + +@media (min-width: 641px) { + .page { + flex-direction: row; + } + + .sidebar { + width: 250px; + height: 100vh; + position: sticky; + top: 0; + } + + .top-row { + position: sticky; + top: 0; + z-index: 1; + } + + .top-row.auth ::deep a:first-child { + flex: 1; + text-align: right; + width: 0; + } + + .top-row, article { + padding-left: 2rem !important; + padding-right: 1.5rem !important; + } +} + +#blazor-error-ui { + color-scheme: light only; + background: lightyellow; + bottom: 0; + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); + box-sizing: border-box; + display: none; + left: 0; + padding: 0.6rem 1.25rem 0.7rem 1.25rem; + position: fixed; + width: 100%; + z-index: 1000; +} + + #blazor-error-ui .dismiss { + cursor: pointer; + position: absolute; + right: 0.75rem; + top: 0.5rem; + } diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/NavMenu.razor b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/NavMenu.razor new file mode 100644 index 0000000..1ebfadf --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/NavMenu.razor @@ -0,0 +1,30 @@ +ο»Ώ + + + + + diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/NavMenu.razor.css b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/NavMenu.razor.css new file mode 100644 index 0000000..a2aeace --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/NavMenu.razor.css @@ -0,0 +1,105 @@ +.navbar-toggler { + appearance: none; + cursor: pointer; + width: 3.5rem; + height: 2.5rem; + color: white; + position: absolute; + top: 0.5rem; + right: 1rem; + border: 1px solid rgba(255, 255, 255, 0.1); + background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1); +} + +.navbar-toggler:checked { + background-color: rgba(255, 255, 255, 0.5); +} + +.top-row { + min-height: 3.5rem; + background-color: rgba(0,0,0,0.4); +} + +.navbar-brand { + font-size: 1.1rem; +} + +.bi { + display: inline-block; + position: relative; + width: 1.25rem; + height: 1.25rem; + margin-right: 0.75rem; + top: -1px; + background-size: cover; +} + +.bi-house-door-fill-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E"); +} + +.bi-plus-square-fill-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.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 1 0z'/%3E%3C/svg%3E"); +} + +.bi-list-nested-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E"); +} + +.nav-item { + font-size: 0.9rem; + padding-bottom: 0.5rem; +} + + .nav-item:first-of-type { + padding-top: 1rem; + } + + .nav-item:last-of-type { + padding-bottom: 1rem; + } + + .nav-item ::deep .nav-link { + color: #d7d7d7; + background: none; + border: none; + border-radius: 4px; + height: 3rem; + display: flex; + align-items: center; + line-height: 3rem; + width: 100%; + } + +.nav-item ::deep a.active { + background-color: rgba(255,255,255,0.37); + color: white; +} + +.nav-item ::deep .nav-link:hover { + background-color: rgba(255,255,255,0.1); + color: white; +} + +.nav-scrollable { + display: none; +} + +.navbar-toggler:checked ~ .nav-scrollable { + display: block; +} + +@media (min-width: 641px) { + .navbar-toggler { + display: none; + } + + .nav-scrollable { + /* Never collapse the sidebar for wide screens */ + display: block; + + /* Allow sidebar to scroll for tall menus */ + height: calc(100vh - 3.5rem); + overflow-y: auto; + } +} diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/ReconnectModal.razor b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/ReconnectModal.razor new file mode 100644 index 0000000..49d916b --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/ReconnectModal.razor @@ -0,0 +1,31 @@ +ο»Ώ + + +
    + +

    + Rejoining the server... +

    +

    + Rejoin failed... trying again in seconds. +

    +

    + Failed to rejoin.
    Please retry or reload the page. +

    + +

    + The session has been paused by the server. +

    + +

    + Failed to resume the session.
    Please reload the page. +

    +
    +
    diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/ReconnectModal.razor.css b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/ReconnectModal.razor.css new file mode 100644 index 0000000..3ad3773 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/ReconnectModal.razor.css @@ -0,0 +1,157 @@ +.components-reconnect-first-attempt-visible, +.components-reconnect-repeated-attempt-visible, +.components-reconnect-failed-visible, +.components-pause-visible, +.components-resume-failed-visible, +.components-rejoining-animation { + display: none; +} + +#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible, +#components-reconnect-modal.components-reconnect-show .components-rejoining-animation, +#components-reconnect-modal.components-reconnect-paused .components-pause-visible, +#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible, +#components-reconnect-modal.components-reconnect-retrying, +#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible, +#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation, +#components-reconnect-modal.components-reconnect-failed, +#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible { + display: block; +} + + +#components-reconnect-modal { + background-color: white; + width: 20rem; + margin: 20vh auto; + padding: 2rem; + border: 0; + border-radius: 0.5rem; + box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3); + opacity: 0; + transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete; + animation: components-reconnect-modal-fadeOutOpacity 0.5s both; + &[open] + +{ + animation: components-reconnect-modal-slideUp 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity 0.5s ease-in-out 0.3s; + animation-fill-mode: both; +} + +} + +#components-reconnect-modal::backdrop { + background-color: rgba(0, 0, 0, 0.4); + animation: components-reconnect-modal-fadeInOpacity 0.5s ease-in-out; + opacity: 1; +} + +@keyframes components-reconnect-modal-slideUp { + 0% { + transform: translateY(30px) scale(0.95); + } + + 100% { + transform: translateY(0); + } +} + +@keyframes components-reconnect-modal-fadeInOpacity { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +@keyframes components-reconnect-modal-fadeOutOpacity { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + } +} + +.components-reconnect-container { + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; +} + +#components-reconnect-modal p { + margin: 0; + text-align: center; +} + +#components-reconnect-modal button { + border: 0; + background-color: #6b9ed2; + color: white; + padding: 4px 24px; + border-radius: 4px; +} + + #components-reconnect-modal button:hover { + background-color: #3b6ea2; + } + + #components-reconnect-modal button:active { + background-color: #6b9ed2; + } + +.components-rejoining-animation { + position: relative; + width: 80px; + height: 80px; +} + + .components-rejoining-animation div { + position: absolute; + border: 3px solid #0087ff; + opacity: 1; + border-radius: 50%; + animation: components-rejoining-animation 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite; + } + + .components-rejoining-animation div:nth-child(2) { + animation-delay: -0.5s; + } + +@keyframes components-rejoining-animation { + 0% { + top: 40px; + left: 40px; + width: 0; + height: 0; + opacity: 0; + } + + 4.9% { + top: 40px; + left: 40px; + width: 0; + height: 0; + opacity: 0; + } + + 5% { + top: 40px; + left: 40px; + width: 0; + height: 0; + opacity: 1; + } + + 100% { + top: 0px; + left: 0px; + width: 80px; + height: 80px; + opacity: 0; + } +} diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/ReconnectModal.razor.js b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/ReconnectModal.razor.js new file mode 100644 index 0000000..e52a190 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Layout/ReconnectModal.razor.js @@ -0,0 +1,63 @@ +// Set up event handlers +const reconnectModal = document.getElementById("components-reconnect-modal"); +reconnectModal.addEventListener("components-reconnect-state-changed", handleReconnectStateChanged); + +const retryButton = document.getElementById("components-reconnect-button"); +retryButton.addEventListener("click", retry); + +const resumeButton = document.getElementById("components-resume-button"); +resumeButton.addEventListener("click", resume); + +function handleReconnectStateChanged(event) { + if (event.detail.state === "show") { + reconnectModal.showModal(); + } else if (event.detail.state === "hide") { + reconnectModal.close(); + } else if (event.detail.state === "failed") { + document.addEventListener("visibilitychange", retryWhenDocumentBecomesVisible); + } else if (event.detail.state === "rejected") { + location.reload(); + } +} + +async function retry() { + document.removeEventListener("visibilitychange", retryWhenDocumentBecomesVisible); + + try { + // Reconnect will asynchronously return: + // - true to mean success + // - false to mean we reached the server, but it rejected the connection (e.g., unknown circuit ID) + // - exception to mean we didn't reach the server (this can be sync or async) + const successful = await Blazor.reconnect(); + if (!successful) { + // We have been able to reach the server, but the circuit is no longer available. + // We'll reload the page so the user can continue using the app as quickly as possible. + const resumeSuccessful = await Blazor.resumeCircuit(); + if (!resumeSuccessful) { + location.reload(); + } else { + reconnectModal.close(); + } + } + } catch (err) { + // We got an exception, server is currently unavailable + document.addEventListener("visibilitychange", retryWhenDocumentBecomesVisible); + } +} + +async function resume() { + try { + const successful = await Blazor.resumeCircuit(); + if (!successful) { + location.reload(); + } + } catch { + location.reload(); + } +} + +async function retryWhenDocumentBecomesVisible() { + if (document.visibilityState === "visible") { + await retry(); + } +} diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Pages/Error.razor b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Pages/Error.razor new file mode 100644 index 0000000..576cc2d --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Pages/Error.razor @@ -0,0 +1,36 @@ +ο»Ώ@page "/Error" +@using System.Diagnostics + +Error + +

    Error.

    +

    An error occurred while processing your request.

    + +@if (ShowRequestId) +{ +

    + Request ID: @RequestId +

    +} + +

    Development Mode

    +

    + Swapping to Development environment will display more detailed information about the error that occurred. +

    +

    + The Development environment shouldn't be enabled for deployed applications. + It can result in displaying sensitive information from exceptions to end users. + For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development + and restarting the app. +

    + +@code{ + [CascadingParameter] + private HttpContext? HttpContext { get; set; } + + private string? RequestId { get; set; } + private bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + + protected override void OnInitialized() => + RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier; +} diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Pages/Home.razor b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Pages/Home.razor new file mode 100644 index 0000000..9001e0b --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Pages/Home.razor @@ -0,0 +1,7 @@ +ο»Ώ@page "/" + +Home + +

    Hello, world!

    + +Welcome to your new app. diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Pages/NotFound.razor b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Pages/NotFound.razor new file mode 100644 index 0000000..917ada1 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Pages/NotFound.razor @@ -0,0 +1,5 @@ +ο»Ώ@page "/not-found" +@layout MainLayout + +

    Not Found

    +

    Sorry, the content you are looking for does not exist.

    \ No newline at end of file diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Pages/Weather.razor b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Pages/Weather.razor new file mode 100644 index 0000000..f437e5e --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Pages/Weather.razor @@ -0,0 +1,64 @@ +ο»Ώ@page "/weather" +@attribute [StreamRendering] + +Weather + +

    Weather

    + +

    This component demonstrates showing data.

    + +@if (forecasts == null) +{ +

    Loading...

    +} +else +{ + + + + + + + + + + + @foreach (var forecast in forecasts) + { + + + + + + + } + +
    DateTemp. (C)Temp. (F)Summary
    @forecast.Date.ToShortDateString()@forecast.TemperatureC@forecast.TemperatureF@forecast.Summary
    +} + +@code { + private WeatherForecast[]? forecasts; + + protected override async Task OnInitializedAsync() + { + // Simulate asynchronous loading to demonstrate streaming rendering + await Task.Delay(500); + + var startDate = DateOnly.FromDateTime(DateTime.Now); + var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; + forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = startDate.AddDays(index), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = summaries[Random.Shared.Next(summaries.Length)] + }).ToArray(); + } + + private class WeatherForecast + { + public DateOnly Date { get; set; } + public int TemperatureC { get; set; } + public string? Summary { get; set; } + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + } +} diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Routes.razor b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Routes.razor new file mode 100644 index 0000000..1e8a229 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/Routes.razor @@ -0,0 +1,6 @@ +ο»Ώ + + + + + diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/_Imports.razor b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/_Imports.razor new file mode 100644 index 0000000..c34379e --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Components/_Imports.razor @@ -0,0 +1,12 @@ +ο»Ώ@using System.Net.Http +@using System.Net.Http.Json +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using static Microsoft.AspNetCore.Components.Web.RenderMode +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.JSInterop +@using StatePulse.Net.BlazorServerTest +@using StatePulse.Net.BlazorServerTest.Client +@using StatePulse.Net.BlazorServerTest.Components +@using StatePulse.Net.BlazorServerTest.Components.Layout diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Program.cs b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Program.cs new file mode 100644 index 0000000..fcb8996 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Program.cs @@ -0,0 +1,43 @@ +using StatePulse.Net.BlazorServerTest.Client.Pages; +using StatePulse.Net.BlazorServerTest.Components; +using StatePulse.Net; +using StatePulse.Net.Configuration; +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +builder.Services.AddRazorComponents() + .AddInteractiveServerComponents() + .AddInteractiveWebAssemblyComponents(); + +builder.Services.AddStatePulseServices(c => { + c.PulseTrackingPerformance = PulseTrackingModel.BlazorServerSafe; + c.DispatchEffectExecutionBehavior = DispatchEffectExecutionBehavior.YieldAndFire; + c.DispatchEffectBehavior = DispatchEffectBehavior.Sequential; + + c.ScanAssemblies = [typeof(Program), typeof(StatePulse.Net.BlazorServerTest.Client._Imports)]; +}); +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseWebAssemblyDebugging(); +} +else +{ + app.UseExceptionHandler("/Error", createScopeForErrors: true); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); +} +app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true); +app.UseHttpsRedirection(); + +app.UseAntiforgery(); + +app.MapStaticAssets(); +app.MapRazorComponents() + .AddInteractiveServerRenderMode() + .AddInteractiveWebAssemblyRenderMode() + .AddAdditionalAssemblies(typeof(StatePulse.Net.BlazorServerTest.Client._Imports).Assembly); + +app.Run(); diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Properties/launchSettings.json b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Properties/launchSettings.json new file mode 100644 index 0000000..8775d1b --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Properties/launchSettings.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "http://localhost:5030", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "https://localhost:7193;http://localhost:5030", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } + } diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.csproj b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.csproj new file mode 100644 index 0000000..12aca57 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.csproj @@ -0,0 +1,16 @@ + + + + net10.0 + enable + enable + true + + + + + + + + + diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/appsettings.Development.json b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/appsettings.json b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/app.css b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/app.css new file mode 100644 index 0000000..73a69d6 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/app.css @@ -0,0 +1,60 @@ +html, body { + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; +} + +a, .btn-link { + color: #006bb7; +} + +.btn-primary { + color: #fff; + background-color: #1b6ec2; + border-color: #1861ac; +} + +.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { + box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb; +} + +.content { + padding-top: 1.1rem; +} + +h1:focus { + outline: none; +} + +.valid.modified:not([type=checkbox]) { + outline: 1px solid #26b050; +} + +.invalid { + outline: 1px solid #e50000; +} + +.validation-message { + color: #e50000; +} + +.blazor-error-boundary { + background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; + padding: 1rem 1rem 1rem 3.7rem; + color: white; +} + + .blazor-error-boundary::after { + content: "An error has occurred." + } + +.darker-border-checkbox.form-check-input { + border-color: #929292; +} + +.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder { + color: var(--bs-secondary-color); + text-align: end; +} + +.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder { + text-align: start; +} \ No newline at end of file diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/favicon.png b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8422b59695935d180d11d5dbe99653e711097819 GIT binary patch literal 1148 zcmV-?1cUpDP)9h26h2-Cs%i*@Moc3?#6qJID|D#|3|2Hn7gTIYEkr|%Xjp);YgvFmB&0#2E2b=| zkVr)lMv9=KqwN&%obTp-$<51T%rx*NCwceh-E+=&e(oLO`@Z~7gybJ#U|^tB2Pai} zRN@5%1qsZ1e@R(XC8n~)nU1S0QdzEYlWPdUpH{wJ2Pd4V8kI3BM=)sG^IkUXF2-j{ zrPTYA6sxpQ`Q1c6mtar~gG~#;lt=s^6_OccmRd>o{*=>)KS=lM zZ!)iG|8G0-9s3VLm`bsa6e ze*TlRxAjXtm^F8V`M1%s5d@tYS>&+_ga#xKGb|!oUBx3uc@mj1%=MaH4GR0tPBG_& z9OZE;->dO@`Q)nr<%dHAsEZRKl zedN6+3+uGHejJp;Q==pskSAcRcyh@6mjm2z-uG;s%dM-u0*u##7OxI7wwyCGpS?4U zBFAr(%GBv5j$jS@@t@iI8?ZqE36I^4t+P^J9D^ELbS5KMtZ z{Qn#JnSd$15nJ$ggkF%I4yUQC+BjDF^}AtB7w348EL>7#sAsLWs}ndp8^DsAcOIL9 zTOO!!0!k2`9BLk25)NeZp7ev>I1Mn={cWI3Yhx2Q#DnAo4IphoV~R^c0x&nw*MoIV zPthX?{6{u}sMS(MxD*dmd5rU(YazQE59b|TsB5Tm)I4a!VaN@HYOR)DwH1U5y(E)z zQqQU*B%MwtRQ$%x&;1p%ANmc|PkoFJZ%<-uq%PX&C!c-7ypis=eP+FCeuv+B@h#{4 zGx1m0PjS~FJt}3mdt4c!lel`1;4W|03kcZRG+DzkTy|7-F~eDsV2Tx!73dM0H0CTh zl)F-YUkE1zEzEW(;JXc|KR5{ox%YTh{$%F$a36JP6Nb<0%#NbSh$dMYF-{ z1_x(Vx)}fs?5_|!5xBTWiiIQHG<%)*e=45Fhjw_tlnmlixq;mUdC$R8v#j( zhQ$9YR-o%i5Uc`S?6EC51!bTRK=Xkyb<18FkCKnS2;o*qlij1YA@-nRpq#OMTX&RbL<^2q@0qja!uIvI;j$6>~k@IMwD42=8$$!+R^@5o6HX(*n~ * { + box-sizing: border-box; + flex-shrink: 0; + width: 100%; + max-width: 100%; + padding-right: calc(var(--bs-gutter-x) * 0.5); + padding-left: calc(var(--bs-gutter-x) * 0.5); + margin-top: var(--bs-gutter-y); +} + +.col { + flex: 1 0 0%; +} + +.row-cols-auto > * { + flex: 0 0 auto; + width: auto; +} + +.row-cols-1 > * { + flex: 0 0 auto; + width: 100%; +} + +.row-cols-2 > * { + flex: 0 0 auto; + width: 50%; +} + +.row-cols-3 > * { + flex: 0 0 auto; + width: 33.33333333%; +} + +.row-cols-4 > * { + flex: 0 0 auto; + width: 25%; +} + +.row-cols-5 > * { + flex: 0 0 auto; + width: 20%; +} + +.row-cols-6 > * { + flex: 0 0 auto; + width: 16.66666667%; +} + +.col-auto { + flex: 0 0 auto; + width: auto; +} + +.col-1 { + flex: 0 0 auto; + width: 8.33333333%; +} + +.col-2 { + flex: 0 0 auto; + width: 16.66666667%; +} + +.col-3 { + flex: 0 0 auto; + width: 25%; +} + +.col-4 { + flex: 0 0 auto; + width: 33.33333333%; +} + +.col-5 { + flex: 0 0 auto; + width: 41.66666667%; +} + +.col-6 { + flex: 0 0 auto; + width: 50%; +} + +.col-7 { + flex: 0 0 auto; + width: 58.33333333%; +} + +.col-8 { + flex: 0 0 auto; + width: 66.66666667%; +} + +.col-9 { + flex: 0 0 auto; + width: 75%; +} + +.col-10 { + flex: 0 0 auto; + width: 83.33333333%; +} + +.col-11 { + flex: 0 0 auto; + width: 91.66666667%; +} + +.col-12 { + flex: 0 0 auto; + width: 100%; +} + +.offset-1 { + margin-left: 8.33333333%; +} + +.offset-2 { + margin-left: 16.66666667%; +} + +.offset-3 { + margin-left: 25%; +} + +.offset-4 { + margin-left: 33.33333333%; +} + +.offset-5 { + margin-left: 41.66666667%; +} + +.offset-6 { + margin-left: 50%; +} + +.offset-7 { + margin-left: 58.33333333%; +} + +.offset-8 { + margin-left: 66.66666667%; +} + +.offset-9 { + margin-left: 75%; +} + +.offset-10 { + margin-left: 83.33333333%; +} + +.offset-11 { + margin-left: 91.66666667%; +} + +.g-0, +.gx-0 { + --bs-gutter-x: 0; +} + +.g-0, +.gy-0 { + --bs-gutter-y: 0; +} + +.g-1, +.gx-1 { + --bs-gutter-x: 0.25rem; +} + +.g-1, +.gy-1 { + --bs-gutter-y: 0.25rem; +} + +.g-2, +.gx-2 { + --bs-gutter-x: 0.5rem; +} + +.g-2, +.gy-2 { + --bs-gutter-y: 0.5rem; +} + +.g-3, +.gx-3 { + --bs-gutter-x: 1rem; +} + +.g-3, +.gy-3 { + --bs-gutter-y: 1rem; +} + +.g-4, +.gx-4 { + --bs-gutter-x: 1.5rem; +} + +.g-4, +.gy-4 { + --bs-gutter-y: 1.5rem; +} + +.g-5, +.gx-5 { + --bs-gutter-x: 3rem; +} + +.g-5, +.gy-5 { + --bs-gutter-y: 3rem; +} + +@media (min-width: 576px) { + .col-sm { + flex: 1 0 0%; + } + .row-cols-sm-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-sm-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-sm-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-sm-3 > * { + flex: 0 0 auto; + width: 33.33333333%; + } + .row-cols-sm-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-sm-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-sm-6 > * { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-sm-auto { + flex: 0 0 auto; + width: auto; + } + .col-sm-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-sm-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-sm-3 { + flex: 0 0 auto; + width: 25%; + } + .col-sm-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-sm-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-sm-6 { + flex: 0 0 auto; + width: 50%; + } + .col-sm-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-sm-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-sm-9 { + flex: 0 0 auto; + width: 75%; + } + .col-sm-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-sm-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-sm-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-sm-0 { + margin-left: 0; + } + .offset-sm-1 { + margin-left: 8.33333333%; + } + .offset-sm-2 { + margin-left: 16.66666667%; + } + .offset-sm-3 { + margin-left: 25%; + } + .offset-sm-4 { + margin-left: 33.33333333%; + } + .offset-sm-5 { + margin-left: 41.66666667%; + } + .offset-sm-6 { + margin-left: 50%; + } + .offset-sm-7 { + margin-left: 58.33333333%; + } + .offset-sm-8 { + margin-left: 66.66666667%; + } + .offset-sm-9 { + margin-left: 75%; + } + .offset-sm-10 { + margin-left: 83.33333333%; + } + .offset-sm-11 { + margin-left: 91.66666667%; + } + .g-sm-0, + .gx-sm-0 { + --bs-gutter-x: 0; + } + .g-sm-0, + .gy-sm-0 { + --bs-gutter-y: 0; + } + .g-sm-1, + .gx-sm-1 { + --bs-gutter-x: 0.25rem; + } + .g-sm-1, + .gy-sm-1 { + --bs-gutter-y: 0.25rem; + } + .g-sm-2, + .gx-sm-2 { + --bs-gutter-x: 0.5rem; + } + .g-sm-2, + .gy-sm-2 { + --bs-gutter-y: 0.5rem; + } + .g-sm-3, + .gx-sm-3 { + --bs-gutter-x: 1rem; + } + .g-sm-3, + .gy-sm-3 { + --bs-gutter-y: 1rem; + } + .g-sm-4, + .gx-sm-4 { + --bs-gutter-x: 1.5rem; + } + .g-sm-4, + .gy-sm-4 { + --bs-gutter-y: 1.5rem; + } + .g-sm-5, + .gx-sm-5 { + --bs-gutter-x: 3rem; + } + .g-sm-5, + .gy-sm-5 { + --bs-gutter-y: 3rem; + } +} +@media (min-width: 768px) { + .col-md { + flex: 1 0 0%; + } + .row-cols-md-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-md-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-md-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-md-3 > * { + flex: 0 0 auto; + width: 33.33333333%; + } + .row-cols-md-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-md-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-md-6 > * { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-md-auto { + flex: 0 0 auto; + width: auto; + } + .col-md-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-md-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-md-3 { + flex: 0 0 auto; + width: 25%; + } + .col-md-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-md-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-md-6 { + flex: 0 0 auto; + width: 50%; + } + .col-md-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-md-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-md-9 { + flex: 0 0 auto; + width: 75%; + } + .col-md-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-md-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-md-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-md-0 { + margin-left: 0; + } + .offset-md-1 { + margin-left: 8.33333333%; + } + .offset-md-2 { + margin-left: 16.66666667%; + } + .offset-md-3 { + margin-left: 25%; + } + .offset-md-4 { + margin-left: 33.33333333%; + } + .offset-md-5 { + margin-left: 41.66666667%; + } + .offset-md-6 { + margin-left: 50%; + } + .offset-md-7 { + margin-left: 58.33333333%; + } + .offset-md-8 { + margin-left: 66.66666667%; + } + .offset-md-9 { + margin-left: 75%; + } + .offset-md-10 { + margin-left: 83.33333333%; + } + .offset-md-11 { + margin-left: 91.66666667%; + } + .g-md-0, + .gx-md-0 { + --bs-gutter-x: 0; + } + .g-md-0, + .gy-md-0 { + --bs-gutter-y: 0; + } + .g-md-1, + .gx-md-1 { + --bs-gutter-x: 0.25rem; + } + .g-md-1, + .gy-md-1 { + --bs-gutter-y: 0.25rem; + } + .g-md-2, + .gx-md-2 { + --bs-gutter-x: 0.5rem; + } + .g-md-2, + .gy-md-2 { + --bs-gutter-y: 0.5rem; + } + .g-md-3, + .gx-md-3 { + --bs-gutter-x: 1rem; + } + .g-md-3, + .gy-md-3 { + --bs-gutter-y: 1rem; + } + .g-md-4, + .gx-md-4 { + --bs-gutter-x: 1.5rem; + } + .g-md-4, + .gy-md-4 { + --bs-gutter-y: 1.5rem; + } + .g-md-5, + .gx-md-5 { + --bs-gutter-x: 3rem; + } + .g-md-5, + .gy-md-5 { + --bs-gutter-y: 3rem; + } +} +@media (min-width: 992px) { + .col-lg { + flex: 1 0 0%; + } + .row-cols-lg-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-lg-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-lg-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-lg-3 > * { + flex: 0 0 auto; + width: 33.33333333%; + } + .row-cols-lg-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-lg-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-lg-6 > * { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-lg-auto { + flex: 0 0 auto; + width: auto; + } + .col-lg-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-lg-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-lg-3 { + flex: 0 0 auto; + width: 25%; + } + .col-lg-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-lg-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-lg-6 { + flex: 0 0 auto; + width: 50%; + } + .col-lg-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-lg-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-lg-9 { + flex: 0 0 auto; + width: 75%; + } + .col-lg-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-lg-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-lg-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-lg-0 { + margin-left: 0; + } + .offset-lg-1 { + margin-left: 8.33333333%; + } + .offset-lg-2 { + margin-left: 16.66666667%; + } + .offset-lg-3 { + margin-left: 25%; + } + .offset-lg-4 { + margin-left: 33.33333333%; + } + .offset-lg-5 { + margin-left: 41.66666667%; + } + .offset-lg-6 { + margin-left: 50%; + } + .offset-lg-7 { + margin-left: 58.33333333%; + } + .offset-lg-8 { + margin-left: 66.66666667%; + } + .offset-lg-9 { + margin-left: 75%; + } + .offset-lg-10 { + margin-left: 83.33333333%; + } + .offset-lg-11 { + margin-left: 91.66666667%; + } + .g-lg-0, + .gx-lg-0 { + --bs-gutter-x: 0; + } + .g-lg-0, + .gy-lg-0 { + --bs-gutter-y: 0; + } + .g-lg-1, + .gx-lg-1 { + --bs-gutter-x: 0.25rem; + } + .g-lg-1, + .gy-lg-1 { + --bs-gutter-y: 0.25rem; + } + .g-lg-2, + .gx-lg-2 { + --bs-gutter-x: 0.5rem; + } + .g-lg-2, + .gy-lg-2 { + --bs-gutter-y: 0.5rem; + } + .g-lg-3, + .gx-lg-3 { + --bs-gutter-x: 1rem; + } + .g-lg-3, + .gy-lg-3 { + --bs-gutter-y: 1rem; + } + .g-lg-4, + .gx-lg-4 { + --bs-gutter-x: 1.5rem; + } + .g-lg-4, + .gy-lg-4 { + --bs-gutter-y: 1.5rem; + } + .g-lg-5, + .gx-lg-5 { + --bs-gutter-x: 3rem; + } + .g-lg-5, + .gy-lg-5 { + --bs-gutter-y: 3rem; + } +} +@media (min-width: 1200px) { + .col-xl { + flex: 1 0 0%; + } + .row-cols-xl-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-xl-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-xl-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-xl-3 > * { + flex: 0 0 auto; + width: 33.33333333%; + } + .row-cols-xl-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-xl-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-xl-6 > * { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-xl-auto { + flex: 0 0 auto; + width: auto; + } + .col-xl-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-xl-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-xl-3 { + flex: 0 0 auto; + width: 25%; + } + .col-xl-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-xl-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-xl-6 { + flex: 0 0 auto; + width: 50%; + } + .col-xl-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-xl-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-xl-9 { + flex: 0 0 auto; + width: 75%; + } + .col-xl-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-xl-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-xl-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-xl-0 { + margin-left: 0; + } + .offset-xl-1 { + margin-left: 8.33333333%; + } + .offset-xl-2 { + margin-left: 16.66666667%; + } + .offset-xl-3 { + margin-left: 25%; + } + .offset-xl-4 { + margin-left: 33.33333333%; + } + .offset-xl-5 { + margin-left: 41.66666667%; + } + .offset-xl-6 { + margin-left: 50%; + } + .offset-xl-7 { + margin-left: 58.33333333%; + } + .offset-xl-8 { + margin-left: 66.66666667%; + } + .offset-xl-9 { + margin-left: 75%; + } + .offset-xl-10 { + margin-left: 83.33333333%; + } + .offset-xl-11 { + margin-left: 91.66666667%; + } + .g-xl-0, + .gx-xl-0 { + --bs-gutter-x: 0; + } + .g-xl-0, + .gy-xl-0 { + --bs-gutter-y: 0; + } + .g-xl-1, + .gx-xl-1 { + --bs-gutter-x: 0.25rem; + } + .g-xl-1, + .gy-xl-1 { + --bs-gutter-y: 0.25rem; + } + .g-xl-2, + .gx-xl-2 { + --bs-gutter-x: 0.5rem; + } + .g-xl-2, + .gy-xl-2 { + --bs-gutter-y: 0.5rem; + } + .g-xl-3, + .gx-xl-3 { + --bs-gutter-x: 1rem; + } + .g-xl-3, + .gy-xl-3 { + --bs-gutter-y: 1rem; + } + .g-xl-4, + .gx-xl-4 { + --bs-gutter-x: 1.5rem; + } + .g-xl-4, + .gy-xl-4 { + --bs-gutter-y: 1.5rem; + } + .g-xl-5, + .gx-xl-5 { + --bs-gutter-x: 3rem; + } + .g-xl-5, + .gy-xl-5 { + --bs-gutter-y: 3rem; + } +} +@media (min-width: 1400px) { + .col-xxl { + flex: 1 0 0%; + } + .row-cols-xxl-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-xxl-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-xxl-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-xxl-3 > * { + flex: 0 0 auto; + width: 33.33333333%; + } + .row-cols-xxl-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-xxl-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-xxl-6 > * { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-xxl-auto { + flex: 0 0 auto; + width: auto; + } + .col-xxl-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-xxl-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-xxl-3 { + flex: 0 0 auto; + width: 25%; + } + .col-xxl-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-xxl-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-xxl-6 { + flex: 0 0 auto; + width: 50%; + } + .col-xxl-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-xxl-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-xxl-9 { + flex: 0 0 auto; + width: 75%; + } + .col-xxl-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-xxl-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-xxl-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-xxl-0 { + margin-left: 0; + } + .offset-xxl-1 { + margin-left: 8.33333333%; + } + .offset-xxl-2 { + margin-left: 16.66666667%; + } + .offset-xxl-3 { + margin-left: 25%; + } + .offset-xxl-4 { + margin-left: 33.33333333%; + } + .offset-xxl-5 { + margin-left: 41.66666667%; + } + .offset-xxl-6 { + margin-left: 50%; + } + .offset-xxl-7 { + margin-left: 58.33333333%; + } + .offset-xxl-8 { + margin-left: 66.66666667%; + } + .offset-xxl-9 { + margin-left: 75%; + } + .offset-xxl-10 { + margin-left: 83.33333333%; + } + .offset-xxl-11 { + margin-left: 91.66666667%; + } + .g-xxl-0, + .gx-xxl-0 { + --bs-gutter-x: 0; + } + .g-xxl-0, + .gy-xxl-0 { + --bs-gutter-y: 0; + } + .g-xxl-1, + .gx-xxl-1 { + --bs-gutter-x: 0.25rem; + } + .g-xxl-1, + .gy-xxl-1 { + --bs-gutter-y: 0.25rem; + } + .g-xxl-2, + .gx-xxl-2 { + --bs-gutter-x: 0.5rem; + } + .g-xxl-2, + .gy-xxl-2 { + --bs-gutter-y: 0.5rem; + } + .g-xxl-3, + .gx-xxl-3 { + --bs-gutter-x: 1rem; + } + .g-xxl-3, + .gy-xxl-3 { + --bs-gutter-y: 1rem; + } + .g-xxl-4, + .gx-xxl-4 { + --bs-gutter-x: 1.5rem; + } + .g-xxl-4, + .gy-xxl-4 { + --bs-gutter-y: 1.5rem; + } + .g-xxl-5, + .gx-xxl-5 { + --bs-gutter-x: 3rem; + } + .g-xxl-5, + .gy-xxl-5 { + --bs-gutter-y: 3rem; + } +} +.d-inline { + display: inline !important; +} + +.d-inline-block { + display: inline-block !important; +} + +.d-block { + display: block !important; +} + +.d-grid { + display: grid !important; +} + +.d-inline-grid { + display: inline-grid !important; +} + +.d-table { + display: table !important; +} + +.d-table-row { + display: table-row !important; +} + +.d-table-cell { + display: table-cell !important; +} + +.d-flex { + display: flex !important; +} + +.d-inline-flex { + display: inline-flex !important; +} + +.d-none { + display: none !important; +} + +.flex-fill { + flex: 1 1 auto !important; +} + +.flex-row { + flex-direction: row !important; +} + +.flex-column { + flex-direction: column !important; +} + +.flex-row-reverse { + flex-direction: row-reverse !important; +} + +.flex-column-reverse { + flex-direction: column-reverse !important; +} + +.flex-grow-0 { + flex-grow: 0 !important; +} + +.flex-grow-1 { + flex-grow: 1 !important; +} + +.flex-shrink-0 { + flex-shrink: 0 !important; +} + +.flex-shrink-1 { + flex-shrink: 1 !important; +} + +.flex-wrap { + flex-wrap: wrap !important; +} + +.flex-nowrap { + flex-wrap: nowrap !important; +} + +.flex-wrap-reverse { + flex-wrap: wrap-reverse !important; +} + +.justify-content-start { + justify-content: flex-start !important; +} + +.justify-content-end { + justify-content: flex-end !important; +} + +.justify-content-center { + justify-content: center !important; +} + +.justify-content-between { + justify-content: space-between !important; +} + +.justify-content-around { + justify-content: space-around !important; +} + +.justify-content-evenly { + justify-content: space-evenly !important; +} + +.align-items-start { + align-items: flex-start !important; +} + +.align-items-end { + align-items: flex-end !important; +} + +.align-items-center { + align-items: center !important; +} + +.align-items-baseline { + align-items: baseline !important; +} + +.align-items-stretch { + align-items: stretch !important; +} + +.align-content-start { + align-content: flex-start !important; +} + +.align-content-end { + align-content: flex-end !important; +} + +.align-content-center { + align-content: center !important; +} + +.align-content-between { + align-content: space-between !important; +} + +.align-content-around { + align-content: space-around !important; +} + +.align-content-stretch { + align-content: stretch !important; +} + +.align-self-auto { + align-self: auto !important; +} + +.align-self-start { + align-self: flex-start !important; +} + +.align-self-end { + align-self: flex-end !important; +} + +.align-self-center { + align-self: center !important; +} + +.align-self-baseline { + align-self: baseline !important; +} + +.align-self-stretch { + align-self: stretch !important; +} + +.order-first { + order: -1 !important; +} + +.order-0 { + order: 0 !important; +} + +.order-1 { + order: 1 !important; +} + +.order-2 { + order: 2 !important; +} + +.order-3 { + order: 3 !important; +} + +.order-4 { + order: 4 !important; +} + +.order-5 { + order: 5 !important; +} + +.order-last { + order: 6 !important; +} + +.m-0 { + margin: 0 !important; +} + +.m-1 { + margin: 0.25rem !important; +} + +.m-2 { + margin: 0.5rem !important; +} + +.m-3 { + margin: 1rem !important; +} + +.m-4 { + margin: 1.5rem !important; +} + +.m-5 { + margin: 3rem !important; +} + +.m-auto { + margin: auto !important; +} + +.mx-0 { + margin-right: 0 !important; + margin-left: 0 !important; +} + +.mx-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; +} + +.mx-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; +} + +.mx-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; +} + +.mx-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; +} + +.mx-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; +} + +.mx-auto { + margin-right: auto !important; + margin-left: auto !important; +} + +.my-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +.my-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; +} + +.my-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; +} + +.my-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; +} + +.my-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; +} + +.my-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; +} + +.my-auto { + margin-top: auto !important; + margin-bottom: auto !important; +} + +.mt-0 { + margin-top: 0 !important; +} + +.mt-1 { + margin-top: 0.25rem !important; +} + +.mt-2 { + margin-top: 0.5rem !important; +} + +.mt-3 { + margin-top: 1rem !important; +} + +.mt-4 { + margin-top: 1.5rem !important; +} + +.mt-5 { + margin-top: 3rem !important; +} + +.mt-auto { + margin-top: auto !important; +} + +.me-0 { + margin-right: 0 !important; +} + +.me-1 { + margin-right: 0.25rem !important; +} + +.me-2 { + margin-right: 0.5rem !important; +} + +.me-3 { + margin-right: 1rem !important; +} + +.me-4 { + margin-right: 1.5rem !important; +} + +.me-5 { + margin-right: 3rem !important; +} + +.me-auto { + margin-right: auto !important; +} + +.mb-0 { + margin-bottom: 0 !important; +} + +.mb-1 { + margin-bottom: 0.25rem !important; +} + +.mb-2 { + margin-bottom: 0.5rem !important; +} + +.mb-3 { + margin-bottom: 1rem !important; +} + +.mb-4 { + margin-bottom: 1.5rem !important; +} + +.mb-5 { + margin-bottom: 3rem !important; +} + +.mb-auto { + margin-bottom: auto !important; +} + +.ms-0 { + margin-left: 0 !important; +} + +.ms-1 { + margin-left: 0.25rem !important; +} + +.ms-2 { + margin-left: 0.5rem !important; +} + +.ms-3 { + margin-left: 1rem !important; +} + +.ms-4 { + margin-left: 1.5rem !important; +} + +.ms-5 { + margin-left: 3rem !important; +} + +.ms-auto { + margin-left: auto !important; +} + +.p-0 { + padding: 0 !important; +} + +.p-1 { + padding: 0.25rem !important; +} + +.p-2 { + padding: 0.5rem !important; +} + +.p-3 { + padding: 1rem !important; +} + +.p-4 { + padding: 1.5rem !important; +} + +.p-5 { + padding: 3rem !important; +} + +.px-0 { + padding-right: 0 !important; + padding-left: 0 !important; +} + +.px-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; +} + +.px-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; +} + +.px-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; +} + +.px-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; +} + +.px-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; +} + +.py-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; +} + +.py-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; +} + +.py-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; +} + +.py-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; +} + +.py-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; +} + +.py-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; +} + +.pt-0 { + padding-top: 0 !important; +} + +.pt-1 { + padding-top: 0.25rem !important; +} + +.pt-2 { + padding-top: 0.5rem !important; +} + +.pt-3 { + padding-top: 1rem !important; +} + +.pt-4 { + padding-top: 1.5rem !important; +} + +.pt-5 { + padding-top: 3rem !important; +} + +.pe-0 { + padding-right: 0 !important; +} + +.pe-1 { + padding-right: 0.25rem !important; +} + +.pe-2 { + padding-right: 0.5rem !important; +} + +.pe-3 { + padding-right: 1rem !important; +} + +.pe-4 { + padding-right: 1.5rem !important; +} + +.pe-5 { + padding-right: 3rem !important; +} + +.pb-0 { + padding-bottom: 0 !important; +} + +.pb-1 { + padding-bottom: 0.25rem !important; +} + +.pb-2 { + padding-bottom: 0.5rem !important; +} + +.pb-3 { + padding-bottom: 1rem !important; +} + +.pb-4 { + padding-bottom: 1.5rem !important; +} + +.pb-5 { + padding-bottom: 3rem !important; +} + +.ps-0 { + padding-left: 0 !important; +} + +.ps-1 { + padding-left: 0.25rem !important; +} + +.ps-2 { + padding-left: 0.5rem !important; +} + +.ps-3 { + padding-left: 1rem !important; +} + +.ps-4 { + padding-left: 1.5rem !important; +} + +.ps-5 { + padding-left: 3rem !important; +} + +@media (min-width: 576px) { + .d-sm-inline { + display: inline !important; + } + .d-sm-inline-block { + display: inline-block !important; + } + .d-sm-block { + display: block !important; + } + .d-sm-grid { + display: grid !important; + } + .d-sm-inline-grid { + display: inline-grid !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: flex !important; + } + .d-sm-inline-flex { + display: inline-flex !important; + } + .d-sm-none { + display: none !important; + } + .flex-sm-fill { + flex: 1 1 auto !important; + } + .flex-sm-row { + flex-direction: row !important; + } + .flex-sm-column { + flex-direction: column !important; + } + .flex-sm-row-reverse { + flex-direction: row-reverse !important; + } + .flex-sm-column-reverse { + flex-direction: column-reverse !important; + } + .flex-sm-grow-0 { + flex-grow: 0 !important; + } + .flex-sm-grow-1 { + flex-grow: 1 !important; + } + .flex-sm-shrink-0 { + flex-shrink: 0 !important; + } + .flex-sm-shrink-1 { + flex-shrink: 1 !important; + } + .flex-sm-wrap { + flex-wrap: wrap !important; + } + .flex-sm-nowrap { + flex-wrap: nowrap !important; + } + .flex-sm-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-sm-start { + justify-content: flex-start !important; + } + .justify-content-sm-end { + justify-content: flex-end !important; + } + .justify-content-sm-center { + justify-content: center !important; + } + .justify-content-sm-between { + justify-content: space-between !important; + } + .justify-content-sm-around { + justify-content: space-around !important; + } + .justify-content-sm-evenly { + justify-content: space-evenly !important; + } + .align-items-sm-start { + align-items: flex-start !important; + } + .align-items-sm-end { + align-items: flex-end !important; + } + .align-items-sm-center { + align-items: center !important; + } + .align-items-sm-baseline { + align-items: baseline !important; + } + .align-items-sm-stretch { + align-items: stretch !important; + } + .align-content-sm-start { + align-content: flex-start !important; + } + .align-content-sm-end { + align-content: flex-end !important; + } + .align-content-sm-center { + align-content: center !important; + } + .align-content-sm-between { + align-content: space-between !important; + } + .align-content-sm-around { + align-content: space-around !important; + } + .align-content-sm-stretch { + align-content: stretch !important; + } + .align-self-sm-auto { + align-self: auto !important; + } + .align-self-sm-start { + align-self: flex-start !important; + } + .align-self-sm-end { + align-self: flex-end !important; + } + .align-self-sm-center { + align-self: center !important; + } + .align-self-sm-baseline { + align-self: baseline !important; + } + .align-self-sm-stretch { + align-self: stretch !important; + } + .order-sm-first { + order: -1 !important; + } + .order-sm-0 { + order: 0 !important; + } + .order-sm-1 { + order: 1 !important; + } + .order-sm-2 { + order: 2 !important; + } + .order-sm-3 { + order: 3 !important; + } + .order-sm-4 { + order: 4 !important; + } + .order-sm-5 { + order: 5 !important; + } + .order-sm-last { + order: 6 !important; + } + .m-sm-0 { + margin: 0 !important; + } + .m-sm-1 { + margin: 0.25rem !important; + } + .m-sm-2 { + margin: 0.5rem !important; + } + .m-sm-3 { + margin: 1rem !important; + } + .m-sm-4 { + margin: 1.5rem !important; + } + .m-sm-5 { + margin: 3rem !important; + } + .m-sm-auto { + margin: auto !important; + } + .mx-sm-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-sm-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-sm-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-sm-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-sm-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-sm-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-sm-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-sm-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-sm-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-sm-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-sm-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-sm-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-sm-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-sm-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-sm-0 { + margin-top: 0 !important; + } + .mt-sm-1 { + margin-top: 0.25rem !important; + } + .mt-sm-2 { + margin-top: 0.5rem !important; + } + .mt-sm-3 { + margin-top: 1rem !important; + } + .mt-sm-4 { + margin-top: 1.5rem !important; + } + .mt-sm-5 { + margin-top: 3rem !important; + } + .mt-sm-auto { + margin-top: auto !important; + } + .me-sm-0 { + margin-right: 0 !important; + } + .me-sm-1 { + margin-right: 0.25rem !important; + } + .me-sm-2 { + margin-right: 0.5rem !important; + } + .me-sm-3 { + margin-right: 1rem !important; + } + .me-sm-4 { + margin-right: 1.5rem !important; + } + .me-sm-5 { + margin-right: 3rem !important; + } + .me-sm-auto { + margin-right: auto !important; + } + .mb-sm-0 { + margin-bottom: 0 !important; + } + .mb-sm-1 { + margin-bottom: 0.25rem !important; + } + .mb-sm-2 { + margin-bottom: 0.5rem !important; + } + .mb-sm-3 { + margin-bottom: 1rem !important; + } + .mb-sm-4 { + margin-bottom: 1.5rem !important; + } + .mb-sm-5 { + margin-bottom: 3rem !important; + } + .mb-sm-auto { + margin-bottom: auto !important; + } + .ms-sm-0 { + margin-left: 0 !important; + } + .ms-sm-1 { + margin-left: 0.25rem !important; + } + .ms-sm-2 { + margin-left: 0.5rem !important; + } + .ms-sm-3 { + margin-left: 1rem !important; + } + .ms-sm-4 { + margin-left: 1.5rem !important; + } + .ms-sm-5 { + margin-left: 3rem !important; + } + .ms-sm-auto { + margin-left: auto !important; + } + .p-sm-0 { + padding: 0 !important; + } + .p-sm-1 { + padding: 0.25rem !important; + } + .p-sm-2 { + padding: 0.5rem !important; + } + .p-sm-3 { + padding: 1rem !important; + } + .p-sm-4 { + padding: 1.5rem !important; + } + .p-sm-5 { + padding: 3rem !important; + } + .px-sm-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-sm-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-sm-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-sm-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-sm-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-sm-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .py-sm-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-sm-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-sm-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-sm-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-sm-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-sm-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-sm-0 { + padding-top: 0 !important; + } + .pt-sm-1 { + padding-top: 0.25rem !important; + } + .pt-sm-2 { + padding-top: 0.5rem !important; + } + .pt-sm-3 { + padding-top: 1rem !important; + } + .pt-sm-4 { + padding-top: 1.5rem !important; + } + .pt-sm-5 { + padding-top: 3rem !important; + } + .pe-sm-0 { + padding-right: 0 !important; + } + .pe-sm-1 { + padding-right: 0.25rem !important; + } + .pe-sm-2 { + padding-right: 0.5rem !important; + } + .pe-sm-3 { + padding-right: 1rem !important; + } + .pe-sm-4 { + padding-right: 1.5rem !important; + } + .pe-sm-5 { + padding-right: 3rem !important; + } + .pb-sm-0 { + padding-bottom: 0 !important; + } + .pb-sm-1 { + padding-bottom: 0.25rem !important; + } + .pb-sm-2 { + padding-bottom: 0.5rem !important; + } + .pb-sm-3 { + padding-bottom: 1rem !important; + } + .pb-sm-4 { + padding-bottom: 1.5rem !important; + } + .pb-sm-5 { + padding-bottom: 3rem !important; + } + .ps-sm-0 { + padding-left: 0 !important; + } + .ps-sm-1 { + padding-left: 0.25rem !important; + } + .ps-sm-2 { + padding-left: 0.5rem !important; + } + .ps-sm-3 { + padding-left: 1rem !important; + } + .ps-sm-4 { + padding-left: 1.5rem !important; + } + .ps-sm-5 { + padding-left: 3rem !important; + } +} +@media (min-width: 768px) { + .d-md-inline { + display: inline !important; + } + .d-md-inline-block { + display: inline-block !important; + } + .d-md-block { + display: block !important; + } + .d-md-grid { + display: grid !important; + } + .d-md-inline-grid { + display: inline-grid !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: flex !important; + } + .d-md-inline-flex { + display: inline-flex !important; + } + .d-md-none { + display: none !important; + } + .flex-md-fill { + flex: 1 1 auto !important; + } + .flex-md-row { + flex-direction: row !important; + } + .flex-md-column { + flex-direction: column !important; + } + .flex-md-row-reverse { + flex-direction: row-reverse !important; + } + .flex-md-column-reverse { + flex-direction: column-reverse !important; + } + .flex-md-grow-0 { + flex-grow: 0 !important; + } + .flex-md-grow-1 { + flex-grow: 1 !important; + } + .flex-md-shrink-0 { + flex-shrink: 0 !important; + } + .flex-md-shrink-1 { + flex-shrink: 1 !important; + } + .flex-md-wrap { + flex-wrap: wrap !important; + } + .flex-md-nowrap { + flex-wrap: nowrap !important; + } + .flex-md-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-md-start { + justify-content: flex-start !important; + } + .justify-content-md-end { + justify-content: flex-end !important; + } + .justify-content-md-center { + justify-content: center !important; + } + .justify-content-md-between { + justify-content: space-between !important; + } + .justify-content-md-around { + justify-content: space-around !important; + } + .justify-content-md-evenly { + justify-content: space-evenly !important; + } + .align-items-md-start { + align-items: flex-start !important; + } + .align-items-md-end { + align-items: flex-end !important; + } + .align-items-md-center { + align-items: center !important; + } + .align-items-md-baseline { + align-items: baseline !important; + } + .align-items-md-stretch { + align-items: stretch !important; + } + .align-content-md-start { + align-content: flex-start !important; + } + .align-content-md-end { + align-content: flex-end !important; + } + .align-content-md-center { + align-content: center !important; + } + .align-content-md-between { + align-content: space-between !important; + } + .align-content-md-around { + align-content: space-around !important; + } + .align-content-md-stretch { + align-content: stretch !important; + } + .align-self-md-auto { + align-self: auto !important; + } + .align-self-md-start { + align-self: flex-start !important; + } + .align-self-md-end { + align-self: flex-end !important; + } + .align-self-md-center { + align-self: center !important; + } + .align-self-md-baseline { + align-self: baseline !important; + } + .align-self-md-stretch { + align-self: stretch !important; + } + .order-md-first { + order: -1 !important; + } + .order-md-0 { + order: 0 !important; + } + .order-md-1 { + order: 1 !important; + } + .order-md-2 { + order: 2 !important; + } + .order-md-3 { + order: 3 !important; + } + .order-md-4 { + order: 4 !important; + } + .order-md-5 { + order: 5 !important; + } + .order-md-last { + order: 6 !important; + } + .m-md-0 { + margin: 0 !important; + } + .m-md-1 { + margin: 0.25rem !important; + } + .m-md-2 { + margin: 0.5rem !important; + } + .m-md-3 { + margin: 1rem !important; + } + .m-md-4 { + margin: 1.5rem !important; + } + .m-md-5 { + margin: 3rem !important; + } + .m-md-auto { + margin: auto !important; + } + .mx-md-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-md-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-md-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-md-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-md-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-md-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-md-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-md-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-md-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-md-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-md-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-md-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-md-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-md-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-md-0 { + margin-top: 0 !important; + } + .mt-md-1 { + margin-top: 0.25rem !important; + } + .mt-md-2 { + margin-top: 0.5rem !important; + } + .mt-md-3 { + margin-top: 1rem !important; + } + .mt-md-4 { + margin-top: 1.5rem !important; + } + .mt-md-5 { + margin-top: 3rem !important; + } + .mt-md-auto { + margin-top: auto !important; + } + .me-md-0 { + margin-right: 0 !important; + } + .me-md-1 { + margin-right: 0.25rem !important; + } + .me-md-2 { + margin-right: 0.5rem !important; + } + .me-md-3 { + margin-right: 1rem !important; + } + .me-md-4 { + margin-right: 1.5rem !important; + } + .me-md-5 { + margin-right: 3rem !important; + } + .me-md-auto { + margin-right: auto !important; + } + .mb-md-0 { + margin-bottom: 0 !important; + } + .mb-md-1 { + margin-bottom: 0.25rem !important; + } + .mb-md-2 { + margin-bottom: 0.5rem !important; + } + .mb-md-3 { + margin-bottom: 1rem !important; + } + .mb-md-4 { + margin-bottom: 1.5rem !important; + } + .mb-md-5 { + margin-bottom: 3rem !important; + } + .mb-md-auto { + margin-bottom: auto !important; + } + .ms-md-0 { + margin-left: 0 !important; + } + .ms-md-1 { + margin-left: 0.25rem !important; + } + .ms-md-2 { + margin-left: 0.5rem !important; + } + .ms-md-3 { + margin-left: 1rem !important; + } + .ms-md-4 { + margin-left: 1.5rem !important; + } + .ms-md-5 { + margin-left: 3rem !important; + } + .ms-md-auto { + margin-left: auto !important; + } + .p-md-0 { + padding: 0 !important; + } + .p-md-1 { + padding: 0.25rem !important; + } + .p-md-2 { + padding: 0.5rem !important; + } + .p-md-3 { + padding: 1rem !important; + } + .p-md-4 { + padding: 1.5rem !important; + } + .p-md-5 { + padding: 3rem !important; + } + .px-md-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-md-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-md-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-md-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-md-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-md-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .py-md-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-md-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-md-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-md-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-md-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-md-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-md-0 { + padding-top: 0 !important; + } + .pt-md-1 { + padding-top: 0.25rem !important; + } + .pt-md-2 { + padding-top: 0.5rem !important; + } + .pt-md-3 { + padding-top: 1rem !important; + } + .pt-md-4 { + padding-top: 1.5rem !important; + } + .pt-md-5 { + padding-top: 3rem !important; + } + .pe-md-0 { + padding-right: 0 !important; + } + .pe-md-1 { + padding-right: 0.25rem !important; + } + .pe-md-2 { + padding-right: 0.5rem !important; + } + .pe-md-3 { + padding-right: 1rem !important; + } + .pe-md-4 { + padding-right: 1.5rem !important; + } + .pe-md-5 { + padding-right: 3rem !important; + } + .pb-md-0 { + padding-bottom: 0 !important; + } + .pb-md-1 { + padding-bottom: 0.25rem !important; + } + .pb-md-2 { + padding-bottom: 0.5rem !important; + } + .pb-md-3 { + padding-bottom: 1rem !important; + } + .pb-md-4 { + padding-bottom: 1.5rem !important; + } + .pb-md-5 { + padding-bottom: 3rem !important; + } + .ps-md-0 { + padding-left: 0 !important; + } + .ps-md-1 { + padding-left: 0.25rem !important; + } + .ps-md-2 { + padding-left: 0.5rem !important; + } + .ps-md-3 { + padding-left: 1rem !important; + } + .ps-md-4 { + padding-left: 1.5rem !important; + } + .ps-md-5 { + padding-left: 3rem !important; + } +} +@media (min-width: 992px) { + .d-lg-inline { + display: inline !important; + } + .d-lg-inline-block { + display: inline-block !important; + } + .d-lg-block { + display: block !important; + } + .d-lg-grid { + display: grid !important; + } + .d-lg-inline-grid { + display: inline-grid !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: flex !important; + } + .d-lg-inline-flex { + display: inline-flex !important; + } + .d-lg-none { + display: none !important; + } + .flex-lg-fill { + flex: 1 1 auto !important; + } + .flex-lg-row { + flex-direction: row !important; + } + .flex-lg-column { + flex-direction: column !important; + } + .flex-lg-row-reverse { + flex-direction: row-reverse !important; + } + .flex-lg-column-reverse { + flex-direction: column-reverse !important; + } + .flex-lg-grow-0 { + flex-grow: 0 !important; + } + .flex-lg-grow-1 { + flex-grow: 1 !important; + } + .flex-lg-shrink-0 { + flex-shrink: 0 !important; + } + .flex-lg-shrink-1 { + flex-shrink: 1 !important; + } + .flex-lg-wrap { + flex-wrap: wrap !important; + } + .flex-lg-nowrap { + flex-wrap: nowrap !important; + } + .flex-lg-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-lg-start { + justify-content: flex-start !important; + } + .justify-content-lg-end { + justify-content: flex-end !important; + } + .justify-content-lg-center { + justify-content: center !important; + } + .justify-content-lg-between { + justify-content: space-between !important; + } + .justify-content-lg-around { + justify-content: space-around !important; + } + .justify-content-lg-evenly { + justify-content: space-evenly !important; + } + .align-items-lg-start { + align-items: flex-start !important; + } + .align-items-lg-end { + align-items: flex-end !important; + } + .align-items-lg-center { + align-items: center !important; + } + .align-items-lg-baseline { + align-items: baseline !important; + } + .align-items-lg-stretch { + align-items: stretch !important; + } + .align-content-lg-start { + align-content: flex-start !important; + } + .align-content-lg-end { + align-content: flex-end !important; + } + .align-content-lg-center { + align-content: center !important; + } + .align-content-lg-between { + align-content: space-between !important; + } + .align-content-lg-around { + align-content: space-around !important; + } + .align-content-lg-stretch { + align-content: stretch !important; + } + .align-self-lg-auto { + align-self: auto !important; + } + .align-self-lg-start { + align-self: flex-start !important; + } + .align-self-lg-end { + align-self: flex-end !important; + } + .align-self-lg-center { + align-self: center !important; + } + .align-self-lg-baseline { + align-self: baseline !important; + } + .align-self-lg-stretch { + align-self: stretch !important; + } + .order-lg-first { + order: -1 !important; + } + .order-lg-0 { + order: 0 !important; + } + .order-lg-1 { + order: 1 !important; + } + .order-lg-2 { + order: 2 !important; + } + .order-lg-3 { + order: 3 !important; + } + .order-lg-4 { + order: 4 !important; + } + .order-lg-5 { + order: 5 !important; + } + .order-lg-last { + order: 6 !important; + } + .m-lg-0 { + margin: 0 !important; + } + .m-lg-1 { + margin: 0.25rem !important; + } + .m-lg-2 { + margin: 0.5rem !important; + } + .m-lg-3 { + margin: 1rem !important; + } + .m-lg-4 { + margin: 1.5rem !important; + } + .m-lg-5 { + margin: 3rem !important; + } + .m-lg-auto { + margin: auto !important; + } + .mx-lg-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-lg-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-lg-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-lg-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-lg-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-lg-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-lg-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-lg-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-lg-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-lg-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-lg-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-lg-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-lg-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-lg-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-lg-0 { + margin-top: 0 !important; + } + .mt-lg-1 { + margin-top: 0.25rem !important; + } + .mt-lg-2 { + margin-top: 0.5rem !important; + } + .mt-lg-3 { + margin-top: 1rem !important; + } + .mt-lg-4 { + margin-top: 1.5rem !important; + } + .mt-lg-5 { + margin-top: 3rem !important; + } + .mt-lg-auto { + margin-top: auto !important; + } + .me-lg-0 { + margin-right: 0 !important; + } + .me-lg-1 { + margin-right: 0.25rem !important; + } + .me-lg-2 { + margin-right: 0.5rem !important; + } + .me-lg-3 { + margin-right: 1rem !important; + } + .me-lg-4 { + margin-right: 1.5rem !important; + } + .me-lg-5 { + margin-right: 3rem !important; + } + .me-lg-auto { + margin-right: auto !important; + } + .mb-lg-0 { + margin-bottom: 0 !important; + } + .mb-lg-1 { + margin-bottom: 0.25rem !important; + } + .mb-lg-2 { + margin-bottom: 0.5rem !important; + } + .mb-lg-3 { + margin-bottom: 1rem !important; + } + .mb-lg-4 { + margin-bottom: 1.5rem !important; + } + .mb-lg-5 { + margin-bottom: 3rem !important; + } + .mb-lg-auto { + margin-bottom: auto !important; + } + .ms-lg-0 { + margin-left: 0 !important; + } + .ms-lg-1 { + margin-left: 0.25rem !important; + } + .ms-lg-2 { + margin-left: 0.5rem !important; + } + .ms-lg-3 { + margin-left: 1rem !important; + } + .ms-lg-4 { + margin-left: 1.5rem !important; + } + .ms-lg-5 { + margin-left: 3rem !important; + } + .ms-lg-auto { + margin-left: auto !important; + } + .p-lg-0 { + padding: 0 !important; + } + .p-lg-1 { + padding: 0.25rem !important; + } + .p-lg-2 { + padding: 0.5rem !important; + } + .p-lg-3 { + padding: 1rem !important; + } + .p-lg-4 { + padding: 1.5rem !important; + } + .p-lg-5 { + padding: 3rem !important; + } + .px-lg-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-lg-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-lg-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-lg-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-lg-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-lg-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .py-lg-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-lg-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-lg-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-lg-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-lg-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-lg-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-lg-0 { + padding-top: 0 !important; + } + .pt-lg-1 { + padding-top: 0.25rem !important; + } + .pt-lg-2 { + padding-top: 0.5rem !important; + } + .pt-lg-3 { + padding-top: 1rem !important; + } + .pt-lg-4 { + padding-top: 1.5rem !important; + } + .pt-lg-5 { + padding-top: 3rem !important; + } + .pe-lg-0 { + padding-right: 0 !important; + } + .pe-lg-1 { + padding-right: 0.25rem !important; + } + .pe-lg-2 { + padding-right: 0.5rem !important; + } + .pe-lg-3 { + padding-right: 1rem !important; + } + .pe-lg-4 { + padding-right: 1.5rem !important; + } + .pe-lg-5 { + padding-right: 3rem !important; + } + .pb-lg-0 { + padding-bottom: 0 !important; + } + .pb-lg-1 { + padding-bottom: 0.25rem !important; + } + .pb-lg-2 { + padding-bottom: 0.5rem !important; + } + .pb-lg-3 { + padding-bottom: 1rem !important; + } + .pb-lg-4 { + padding-bottom: 1.5rem !important; + } + .pb-lg-5 { + padding-bottom: 3rem !important; + } + .ps-lg-0 { + padding-left: 0 !important; + } + .ps-lg-1 { + padding-left: 0.25rem !important; + } + .ps-lg-2 { + padding-left: 0.5rem !important; + } + .ps-lg-3 { + padding-left: 1rem !important; + } + .ps-lg-4 { + padding-left: 1.5rem !important; + } + .ps-lg-5 { + padding-left: 3rem !important; + } +} +@media (min-width: 1200px) { + .d-xl-inline { + display: inline !important; + } + .d-xl-inline-block { + display: inline-block !important; + } + .d-xl-block { + display: block !important; + } + .d-xl-grid { + display: grid !important; + } + .d-xl-inline-grid { + display: inline-grid !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: flex !important; + } + .d-xl-inline-flex { + display: inline-flex !important; + } + .d-xl-none { + display: none !important; + } + .flex-xl-fill { + flex: 1 1 auto !important; + } + .flex-xl-row { + flex-direction: row !important; + } + .flex-xl-column { + flex-direction: column !important; + } + .flex-xl-row-reverse { + flex-direction: row-reverse !important; + } + .flex-xl-column-reverse { + flex-direction: column-reverse !important; + } + .flex-xl-grow-0 { + flex-grow: 0 !important; + } + .flex-xl-grow-1 { + flex-grow: 1 !important; + } + .flex-xl-shrink-0 { + flex-shrink: 0 !important; + } + .flex-xl-shrink-1 { + flex-shrink: 1 !important; + } + .flex-xl-wrap { + flex-wrap: wrap !important; + } + .flex-xl-nowrap { + flex-wrap: nowrap !important; + } + .flex-xl-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-xl-start { + justify-content: flex-start !important; + } + .justify-content-xl-end { + justify-content: flex-end !important; + } + .justify-content-xl-center { + justify-content: center !important; + } + .justify-content-xl-between { + justify-content: space-between !important; + } + .justify-content-xl-around { + justify-content: space-around !important; + } + .justify-content-xl-evenly { + justify-content: space-evenly !important; + } + .align-items-xl-start { + align-items: flex-start !important; + } + .align-items-xl-end { + align-items: flex-end !important; + } + .align-items-xl-center { + align-items: center !important; + } + .align-items-xl-baseline { + align-items: baseline !important; + } + .align-items-xl-stretch { + align-items: stretch !important; + } + .align-content-xl-start { + align-content: flex-start !important; + } + .align-content-xl-end { + align-content: flex-end !important; + } + .align-content-xl-center { + align-content: center !important; + } + .align-content-xl-between { + align-content: space-between !important; + } + .align-content-xl-around { + align-content: space-around !important; + } + .align-content-xl-stretch { + align-content: stretch !important; + } + .align-self-xl-auto { + align-self: auto !important; + } + .align-self-xl-start { + align-self: flex-start !important; + } + .align-self-xl-end { + align-self: flex-end !important; + } + .align-self-xl-center { + align-self: center !important; + } + .align-self-xl-baseline { + align-self: baseline !important; + } + .align-self-xl-stretch { + align-self: stretch !important; + } + .order-xl-first { + order: -1 !important; + } + .order-xl-0 { + order: 0 !important; + } + .order-xl-1 { + order: 1 !important; + } + .order-xl-2 { + order: 2 !important; + } + .order-xl-3 { + order: 3 !important; + } + .order-xl-4 { + order: 4 !important; + } + .order-xl-5 { + order: 5 !important; + } + .order-xl-last { + order: 6 !important; + } + .m-xl-0 { + margin: 0 !important; + } + .m-xl-1 { + margin: 0.25rem !important; + } + .m-xl-2 { + margin: 0.5rem !important; + } + .m-xl-3 { + margin: 1rem !important; + } + .m-xl-4 { + margin: 1.5rem !important; + } + .m-xl-5 { + margin: 3rem !important; + } + .m-xl-auto { + margin: auto !important; + } + .mx-xl-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-xl-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-xl-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-xl-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-xl-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-xl-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-xl-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-xl-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-xl-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-xl-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-xl-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-xl-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-xl-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-xl-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-xl-0 { + margin-top: 0 !important; + } + .mt-xl-1 { + margin-top: 0.25rem !important; + } + .mt-xl-2 { + margin-top: 0.5rem !important; + } + .mt-xl-3 { + margin-top: 1rem !important; + } + .mt-xl-4 { + margin-top: 1.5rem !important; + } + .mt-xl-5 { + margin-top: 3rem !important; + } + .mt-xl-auto { + margin-top: auto !important; + } + .me-xl-0 { + margin-right: 0 !important; + } + .me-xl-1 { + margin-right: 0.25rem !important; + } + .me-xl-2 { + margin-right: 0.5rem !important; + } + .me-xl-3 { + margin-right: 1rem !important; + } + .me-xl-4 { + margin-right: 1.5rem !important; + } + .me-xl-5 { + margin-right: 3rem !important; + } + .me-xl-auto { + margin-right: auto !important; + } + .mb-xl-0 { + margin-bottom: 0 !important; + } + .mb-xl-1 { + margin-bottom: 0.25rem !important; + } + .mb-xl-2 { + margin-bottom: 0.5rem !important; + } + .mb-xl-3 { + margin-bottom: 1rem !important; + } + .mb-xl-4 { + margin-bottom: 1.5rem !important; + } + .mb-xl-5 { + margin-bottom: 3rem !important; + } + .mb-xl-auto { + margin-bottom: auto !important; + } + .ms-xl-0 { + margin-left: 0 !important; + } + .ms-xl-1 { + margin-left: 0.25rem !important; + } + .ms-xl-2 { + margin-left: 0.5rem !important; + } + .ms-xl-3 { + margin-left: 1rem !important; + } + .ms-xl-4 { + margin-left: 1.5rem !important; + } + .ms-xl-5 { + margin-left: 3rem !important; + } + .ms-xl-auto { + margin-left: auto !important; + } + .p-xl-0 { + padding: 0 !important; + } + .p-xl-1 { + padding: 0.25rem !important; + } + .p-xl-2 { + padding: 0.5rem !important; + } + .p-xl-3 { + padding: 1rem !important; + } + .p-xl-4 { + padding: 1.5rem !important; + } + .p-xl-5 { + padding: 3rem !important; + } + .px-xl-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-xl-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-xl-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-xl-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-xl-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-xl-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .py-xl-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-xl-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-xl-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-xl-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-xl-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-xl-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-xl-0 { + padding-top: 0 !important; + } + .pt-xl-1 { + padding-top: 0.25rem !important; + } + .pt-xl-2 { + padding-top: 0.5rem !important; + } + .pt-xl-3 { + padding-top: 1rem !important; + } + .pt-xl-4 { + padding-top: 1.5rem !important; + } + .pt-xl-5 { + padding-top: 3rem !important; + } + .pe-xl-0 { + padding-right: 0 !important; + } + .pe-xl-1 { + padding-right: 0.25rem !important; + } + .pe-xl-2 { + padding-right: 0.5rem !important; + } + .pe-xl-3 { + padding-right: 1rem !important; + } + .pe-xl-4 { + padding-right: 1.5rem !important; + } + .pe-xl-5 { + padding-right: 3rem !important; + } + .pb-xl-0 { + padding-bottom: 0 !important; + } + .pb-xl-1 { + padding-bottom: 0.25rem !important; + } + .pb-xl-2 { + padding-bottom: 0.5rem !important; + } + .pb-xl-3 { + padding-bottom: 1rem !important; + } + .pb-xl-4 { + padding-bottom: 1.5rem !important; + } + .pb-xl-5 { + padding-bottom: 3rem !important; + } + .ps-xl-0 { + padding-left: 0 !important; + } + .ps-xl-1 { + padding-left: 0.25rem !important; + } + .ps-xl-2 { + padding-left: 0.5rem !important; + } + .ps-xl-3 { + padding-left: 1rem !important; + } + .ps-xl-4 { + padding-left: 1.5rem !important; + } + .ps-xl-5 { + padding-left: 3rem !important; + } +} +@media (min-width: 1400px) { + .d-xxl-inline { + display: inline !important; + } + .d-xxl-inline-block { + display: inline-block !important; + } + .d-xxl-block { + display: block !important; + } + .d-xxl-grid { + display: grid !important; + } + .d-xxl-inline-grid { + display: inline-grid !important; + } + .d-xxl-table { + display: table !important; + } + .d-xxl-table-row { + display: table-row !important; + } + .d-xxl-table-cell { + display: table-cell !important; + } + .d-xxl-flex { + display: flex !important; + } + .d-xxl-inline-flex { + display: inline-flex !important; + } + .d-xxl-none { + display: none !important; + } + .flex-xxl-fill { + flex: 1 1 auto !important; + } + .flex-xxl-row { + flex-direction: row !important; + } + .flex-xxl-column { + flex-direction: column !important; + } + .flex-xxl-row-reverse { + flex-direction: row-reverse !important; + } + .flex-xxl-column-reverse { + flex-direction: column-reverse !important; + } + .flex-xxl-grow-0 { + flex-grow: 0 !important; + } + .flex-xxl-grow-1 { + flex-grow: 1 !important; + } + .flex-xxl-shrink-0 { + flex-shrink: 0 !important; + } + .flex-xxl-shrink-1 { + flex-shrink: 1 !important; + } + .flex-xxl-wrap { + flex-wrap: wrap !important; + } + .flex-xxl-nowrap { + flex-wrap: nowrap !important; + } + .flex-xxl-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-xxl-start { + justify-content: flex-start !important; + } + .justify-content-xxl-end { + justify-content: flex-end !important; + } + .justify-content-xxl-center { + justify-content: center !important; + } + .justify-content-xxl-between { + justify-content: space-between !important; + } + .justify-content-xxl-around { + justify-content: space-around !important; + } + .justify-content-xxl-evenly { + justify-content: space-evenly !important; + } + .align-items-xxl-start { + align-items: flex-start !important; + } + .align-items-xxl-end { + align-items: flex-end !important; + } + .align-items-xxl-center { + align-items: center !important; + } + .align-items-xxl-baseline { + align-items: baseline !important; + } + .align-items-xxl-stretch { + align-items: stretch !important; + } + .align-content-xxl-start { + align-content: flex-start !important; + } + .align-content-xxl-end { + align-content: flex-end !important; + } + .align-content-xxl-center { + align-content: center !important; + } + .align-content-xxl-between { + align-content: space-between !important; + } + .align-content-xxl-around { + align-content: space-around !important; + } + .align-content-xxl-stretch { + align-content: stretch !important; + } + .align-self-xxl-auto { + align-self: auto !important; + } + .align-self-xxl-start { + align-self: flex-start !important; + } + .align-self-xxl-end { + align-self: flex-end !important; + } + .align-self-xxl-center { + align-self: center !important; + } + .align-self-xxl-baseline { + align-self: baseline !important; + } + .align-self-xxl-stretch { + align-self: stretch !important; + } + .order-xxl-first { + order: -1 !important; + } + .order-xxl-0 { + order: 0 !important; + } + .order-xxl-1 { + order: 1 !important; + } + .order-xxl-2 { + order: 2 !important; + } + .order-xxl-3 { + order: 3 !important; + } + .order-xxl-4 { + order: 4 !important; + } + .order-xxl-5 { + order: 5 !important; + } + .order-xxl-last { + order: 6 !important; + } + .m-xxl-0 { + margin: 0 !important; + } + .m-xxl-1 { + margin: 0.25rem !important; + } + .m-xxl-2 { + margin: 0.5rem !important; + } + .m-xxl-3 { + margin: 1rem !important; + } + .m-xxl-4 { + margin: 1.5rem !important; + } + .m-xxl-5 { + margin: 3rem !important; + } + .m-xxl-auto { + margin: auto !important; + } + .mx-xxl-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-xxl-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-xxl-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-xxl-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-xxl-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-xxl-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-xxl-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-xxl-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-xxl-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-xxl-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-xxl-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-xxl-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-xxl-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-xxl-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-xxl-0 { + margin-top: 0 !important; + } + .mt-xxl-1 { + margin-top: 0.25rem !important; + } + .mt-xxl-2 { + margin-top: 0.5rem !important; + } + .mt-xxl-3 { + margin-top: 1rem !important; + } + .mt-xxl-4 { + margin-top: 1.5rem !important; + } + .mt-xxl-5 { + margin-top: 3rem !important; + } + .mt-xxl-auto { + margin-top: auto !important; + } + .me-xxl-0 { + margin-right: 0 !important; + } + .me-xxl-1 { + margin-right: 0.25rem !important; + } + .me-xxl-2 { + margin-right: 0.5rem !important; + } + .me-xxl-3 { + margin-right: 1rem !important; + } + .me-xxl-4 { + margin-right: 1.5rem !important; + } + .me-xxl-5 { + margin-right: 3rem !important; + } + .me-xxl-auto { + margin-right: auto !important; + } + .mb-xxl-0 { + margin-bottom: 0 !important; + } + .mb-xxl-1 { + margin-bottom: 0.25rem !important; + } + .mb-xxl-2 { + margin-bottom: 0.5rem !important; + } + .mb-xxl-3 { + margin-bottom: 1rem !important; + } + .mb-xxl-4 { + margin-bottom: 1.5rem !important; + } + .mb-xxl-5 { + margin-bottom: 3rem !important; + } + .mb-xxl-auto { + margin-bottom: auto !important; + } + .ms-xxl-0 { + margin-left: 0 !important; + } + .ms-xxl-1 { + margin-left: 0.25rem !important; + } + .ms-xxl-2 { + margin-left: 0.5rem !important; + } + .ms-xxl-3 { + margin-left: 1rem !important; + } + .ms-xxl-4 { + margin-left: 1.5rem !important; + } + .ms-xxl-5 { + margin-left: 3rem !important; + } + .ms-xxl-auto { + margin-left: auto !important; + } + .p-xxl-0 { + padding: 0 !important; + } + .p-xxl-1 { + padding: 0.25rem !important; + } + .p-xxl-2 { + padding: 0.5rem !important; + } + .p-xxl-3 { + padding: 1rem !important; + } + .p-xxl-4 { + padding: 1.5rem !important; + } + .p-xxl-5 { + padding: 3rem !important; + } + .px-xxl-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-xxl-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-xxl-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-xxl-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-xxl-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-xxl-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .py-xxl-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-xxl-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-xxl-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-xxl-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-xxl-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-xxl-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-xxl-0 { + padding-top: 0 !important; + } + .pt-xxl-1 { + padding-top: 0.25rem !important; + } + .pt-xxl-2 { + padding-top: 0.5rem !important; + } + .pt-xxl-3 { + padding-top: 1rem !important; + } + .pt-xxl-4 { + padding-top: 1.5rem !important; + } + .pt-xxl-5 { + padding-top: 3rem !important; + } + .pe-xxl-0 { + padding-right: 0 !important; + } + .pe-xxl-1 { + padding-right: 0.25rem !important; + } + .pe-xxl-2 { + padding-right: 0.5rem !important; + } + .pe-xxl-3 { + padding-right: 1rem !important; + } + .pe-xxl-4 { + padding-right: 1.5rem !important; + } + .pe-xxl-5 { + padding-right: 3rem !important; + } + .pb-xxl-0 { + padding-bottom: 0 !important; + } + .pb-xxl-1 { + padding-bottom: 0.25rem !important; + } + .pb-xxl-2 { + padding-bottom: 0.5rem !important; + } + .pb-xxl-3 { + padding-bottom: 1rem !important; + } + .pb-xxl-4 { + padding-bottom: 1.5rem !important; + } + .pb-xxl-5 { + padding-bottom: 3rem !important; + } + .ps-xxl-0 { + padding-left: 0 !important; + } + .ps-xxl-1 { + padding-left: 0.25rem !important; + } + .ps-xxl-2 { + padding-left: 0.5rem !important; + } + .ps-xxl-3 { + padding-left: 1rem !important; + } + .ps-xxl-4 { + padding-left: 1.5rem !important; + } + .ps-xxl-5 { + padding-left: 3rem !important; + } +} +@media print { + .d-print-inline { + display: inline !important; + } + .d-print-inline-block { + display: inline-block !important; + } + .d-print-block { + display: block !important; + } + .d-print-grid { + display: grid !important; + } + .d-print-inline-grid { + display: inline-grid !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: flex !important; + } + .d-print-inline-flex { + display: inline-flex !important; + } + .d-print-none { + display: none !important; + } +} + +/*# sourceMappingURL=bootstrap-grid.css.map */ \ No newline at end of file diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map new file mode 100644 index 0000000..ce99ec1 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../scss/mixins/_banner.scss","../../scss/_containers.scss","../../scss/mixins/_container.scss","bootstrap-grid.css","../../scss/mixins/_breakpoints.scss","../../scss/_variables.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/mixins/_utilities.scss","../../scss/utilities/_api.scss"],"names":[],"mappings":"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EE,mBAAA;EJ6+BR;EI1+BM;;IAEE,mBAAA;EJ4+BR;AACF;AKpiCQ;EAOI,0BAAA;ALgiCZ;;AKviCQ;EAOI,gCAAA;ALoiCZ;;AK3iCQ;EAOI,yBAAA;ALwiCZ;;AK/iCQ;EAOI,wBAAA;AL4iCZ;;AKnjCQ;EAOI,+BAAA;ALgjCZ;;AKvjCQ;EAOI,yBAAA;ALojCZ;;AK3jCQ;EAOI,6BAAA;ALwjCZ;;AK/jCQ;EAOI,8BAAA;AL4jCZ;;AKnkCQ;EAOI,wBAAA;ALgkCZ;;AKvkCQ;EAOI,+BAAA;ALokCZ;;AK3kCQ;EAOI,wBAAA;ALwkCZ;;AK/kCQ;EAOI,yBAAA;AL4kCZ;;AKnlCQ;EAOI,8BAAA;ALglCZ;;AKvlCQ;EAOI,iCAAA;ALolCZ;;AK3lCQ;EAOI,sCAAA;ALwlCZ;;AK/lCQ;EAOI,yCAAA;AL4lCZ;;AKnmCQ;EAOI,uBAAA;ALgmCZ;;AKvmCQ;EAOI,uBAAA;ALomCZ;;AK3mCQ;EAOI,yBAAA;ALwmCZ;;AK/mCQ;EAOI,yBAAA;AL4mCZ;;AKnnCQ;EAOI,0BAAA;ALgnCZ;;AKvnCQ;EAOI,4BAAA;ALonCZ;;AK3nCQ;EAOI,kCAAA;ALwnCZ;;AK/nCQ;EAOI,sCAAA;AL4nCZ;;AKnoCQ;EAOI,oCAAA;ALgoCZ;;AKvoCQ;EAOI,kCAAA;ALooCZ;;AK3oCQ;EAOI,yCAAA;ALwoCZ;;AK/oCQ;EAOI,wCAAA;AL4oCZ;;AKnpCQ;EAOI,wCAAA;ALgpCZ;;AKvpCQ;EAOI,kCAAA;ALopCZ;;AK3pCQ;EAOI,gCAAA;ALwpCZ;;AK/pCQ;EAOI,8BAAA;AL4pCZ;;AKnqCQ;EAOI,gCAAA;ALgqCZ;;AKvqCQ;EAOI,+BAAA;ALoqCZ;;AK3qCQ;EAOI,oCAAA;ALwqCZ;;AK/qCQ;EAOI,kCAAA;AL4qCZ;;AKnrCQ;EAOI,gCAAA;ALgrCZ;;AKvrCQ;EAOI,uCAAA;ALorCZ;;AK3rCQ;EAOI,sCAAA;ALwrCZ;;AK/rCQ;EAOI,iCAAA;AL4rCZ;;AKnsCQ;EAOI,2BAAA;ALgsCZ;;AKvsCQ;EAOI,iCAAA;ALosCZ;;AK3sCQ;EAOI,+BAAA;ALwsCZ;;AK/sCQ;EAOI,6BAAA;AL4sCZ;;AKntCQ;EA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;AL8iDZ;;AKrjDQ;EAOI,4BAAA;ALkjDZ;;AKzjDQ;EAOI,2BAAA;ALsjDZ;;AK7jDQ;EAOI,iCAAA;AL0jDZ;;AKjkDQ;EAOI,gCAAA;AL8jDZ;;AKrkDQ;EAOI,8BAAA;ALkkDZ;;AKzkDQ;EAOI,gCAAA;ALskDZ;;AK7kDQ;EAOI,8BAAA;AL0kDZ;;AKjlDQ;EAOI,4BAAA;AL8kDZ;;AKrlDQ;EAOI,kCAAA;ALklDZ;;AKzlDQ;EAOI,iCAAA;ALslDZ;;AK7lDQ;EAOI,+BAAA;AL0lDZ;;AKjmDQ;EAOI,iCAAA;AL8lDZ;;AKrmDQ;EAOI,+BAAA;ALkmDZ;;AKzmDQ;EAOI,0BAAA;ALsmDZ;;AK7mDQ;EAOI,gCAAA;AL0mDZ;;AKjnDQ;EAOI,+BAAA;AL8mDZ;;AKrnDQ;EAOI,6BAAA;ALknDZ;;AKznDQ;EAOI,+BAAA;ALsnDZ;;AK7nDQ;EAOI,6BAAA;AL0nDZ;;ACpoDI;EIGI;IAOI,0BAAA;EL+nDV;EKtoDM;IAOI,gCAAA;ELkoDV;EKzoDM;IAOI,yBAAA;ELqoDV;EK5oDM;IAOI,wBAAA;ELwoDV;EK/oDM;IAOI,+BAAA;EL2oDV;EKlpDM;IAOI,yBAAA;EL8oDV;EKrpDM;IAOI,6BAAA;ELipDV;EKxpDM;IAOI,8BAAA;ELopDV;EK3pDM;IAOI,wBAAA;ELupDV;EK9pDM;IAOI,+BAAA;EL0pDV;EKjqDM;IAOI,wBAAA;EL6pDV;EKpqDM;IAOI,yBAAA;ELgqDV;EKvqDM;IAOI,8BAAA;ELmqDV;EK1qDM;IAOI,iCAAA;ELsqDV;EK7qDM;IAOI,sCAAA;ELyqDV;EKhrDM;IAOI,yCAAA;EL4qDV;EKnrDM;IAOI,uBAAA;EL+qDV;EKtrDM;IAOI,uBAAA;ELkrDV;EKzrDM;IAOI,yBAAA;ELqrDV;EK5rDM;IAOI,yBAAA;ELwrDV;EK/rDM;IAOI,0BAAA;EL2rDV;EKlsDM;IAOI,4BAAA;EL8rDV;EKrsDM;IAOI,kCAAA;ELisDV;EKxsDM;IAOI,sCAAA;ELosDV;EK3sDM;IAOI,oCAAA;ELusDV;EK9sDM;IAOI,kCAAA;EL0sDV;EKjtDM;IAOI,yCAAA;EL6sDV;EKptDM;IAOI,wCAAA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nEV;EK/nEM;IAOI,yCAAA;EL2nEV;EKloEM;IAOI,uBAAA;EL8nEV;EKroEM;IAOI,uBAAA;ELioEV;EKxoEM;IAOI,yBAAA;ELooEV;EK3oEM;IAOI,yBAAA;ELuoEV;EK9oEM;IAOI,0BAAA;EL0oEV;EKjpEM;IAOI,4BAAA;EL6oEV;EKppEM;IAOI,kCAAA;ELgpEV;EKvpEM;IAOI,sCAAA;ELmpEV;EK1pEM;IAOI,oCAAA;ELspEV;EK7pEM;IAOI,kCAAA;ELypEV;EKhqEM;IAOI,yCAAA;EL4pEV;EKnqEM;IAOI,wCAAA;EL+pEV;EKtqEM;IAOI,wCAAA;ELkqEV;EKzqEM;IAOI,kCAAA;ELqqEV;EK5qEM;IAOI,gCAAA;ELwqEV;EK/qEM;IAOI,8BAAA;EL2qEV;EKlrEM;IAOI,gCAAA;EL8qEV;EKrrEM;IAOI,+BAAA;ELirEV;EKxrEM;IAOI,oCAAA;ELorEV;EK3rEM;IAOI,kCAAA;ELurEV;EK9rEM;IAOI,gCAAA;EL0rEV;EKjsEM;IAOI,uCAAA;EL6rEV;EKpsEM;IAOI,sCAAA;ELgsEV;EKvsEM;IAOI,iCAAA;ELmsEV;EK1sEM;IAOI,2BAAA;ELssEV;EK7sEM;IAOI,iCAAA;ELysEV;EKhtEM;IAOI,+BAAA;EL4sEV;EKntEM;IAOI,6BAAA;EL+sEV;EKttEM;IAOI,+BAAA;ELktEV;EKztEM;IAOI,8BAAA;ELqtEV;EK5tEM;IAOI,oBAAA;ELwtEV;EK/tEM;IAOI,mBAAA;EL2tEV;EKluEM;IAOI,mBAAA;EL8tEV;EKruEM;IAOI,mBAAA;ELiuEV;EKxuEM;IAOI,mBAAA;ELouEV;EK3uEM;IAOI,mBAAA;ELuuEV;EK9uEM;IAOI,mBAAA;EL0uEV;EKjvEM;IAOI,mBAAA;EL6uEV;EKpvEM;IAOI,oBAAA;ELgvEV;EKvvEM;IAOI,0BAAA;ELmvEV;EK1vEM;IAOI,yBAAA;ELsvEV;EK7vEM;IAOI,uBAAA;ELyvEV;EKhwEM;IAOI,yBAAA;EL4vEV;EKnwEM;IAOI,uBAAA;EL+vEV;EKtwEM;IAOI,uBAAA;ELkwEV;EKzwEM;IAOI,0BAAA;IAAA,yBAAA;ELswEV;EK7wEM;IAO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EKviFM;IAOI,yBAAA;ELmiFV;EK1iFM;IAOI,wBAAA;ELsiFV;EK7iFM;IAOI,+BAAA;ELyiFV;EKhjFM;IAOI,yBAAA;EL4iFV;EKnjFM;IAOI,6BAAA;EL+iFV;EKtjFM;IAOI,8BAAA;ELkjFV;EKzjFM;IAOI,wBAAA;ELqjFV;EK5jFM;IAOI,+BAAA;ELwjFV;EK/jFM;IAOI,wBAAA;EL2jFV;EKlkFM;IAOI,yBAAA;EL8jFV;EKrkFM;IAOI,8BAAA;ELikFV;EKxkFM;IAOI,iCAAA;ELokFV;EK3kFM;IAOI,sCAAA;ELukFV;EK9kFM;IAOI,yCAAA;EL0kFV;EKjlFM;IAOI,uBAAA;EL6kFV;EKplFM;IAOI,uBAAA;ELglFV;EKvlFM;IAOI,yBAAA;ELmlFV;EK1lFM;IAOI,yBAAA;ELslFV;EK7lFM;IAOI,0BAAA;ELylFV;EKhmFM;IAOI,4BAAA;EL4lFV;EKnmFM;IAOI,kCAAA;EL+lFV;EKtmFM;IAOI,sCAAA;ELkmFV;EKzmFM;IAOI,oCAAA;ELqmFV;EK5mFM;IAOI,kCAAA;ELwmFV;EK/mFM;IAOI,yCAAA;EL2mFV;EKlnFM;IAOI,wCAAA;EL8mFV;EKrnFM;IAOI,wCAAA;ELinFV;EKxnFM;IAOI,kCAAA;ELonFV;EK3nFM;IAOI,gCAAA;ELunFV;EK9nFM;IAOI,8BAAA;EL0nFV;EKjoFM;IAOI,gCAAA;EL6nFV;EKpoFM;IAOI,+BAAA;ELgoFV;EKvoFM;IAOI,oCAAA;ELmoFV;EK1oFM;IAOI,kCAAA;ELsoFV;EK7oFM;IAOI,gCAAA;ELyoFV;EKhpFM;IAOI,uCAAA;EL4oFV;EKnpFM;IAOI,sCAAA;EL+oFV;EKtpFM;IAOI,iCAAA;ELkpFV;EKzpFM;IAOI,2BAAA;ELqpFV;EK5pFM;IAOI,iCAAA;ELwpFV;EK/pFM;IAOI,+BAAA;EL2pFV;EKlqFM;IAOI,6BAAA;EL8pFV;EKrqFM;IAOI,+BAAA;ELiqFV;EKxqFM;IAOI,8BAAA;ELoqFV;EK3qFM;IAOI,oBAAA;ELuqFV;EK9qFM;IAOI,mBAAA;EL0qFV;EKjrFM;IAOI,mBAAA;EL6qFV;EKprFM;IAOI,mBAAA;ELgrFV;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AAA;ELy8FV;EKh9FM;IAOI,iCAAA;EL48FV;EKn9FM;IAOI,+BAAA;EL+8FV;EKt9FM;IAOI,iCAAA;ELk9FV;EKz9FM;IAOI,+BAAA;ELq9FV;EK59FM;IAOI,0BAAA;ELw9FV;EK/9FM;IAOI,gCAAA;EL29FV;EKl+FM;IAOI,+BAAA;EL89FV;EKr+FM;IAOI,6BAAA;ELi+FV;EKx+FM;IAOI,+BAAA;ELo+FV;EK3+FM;IAOI,6BAAA;ELu+FV;AACF;ACl/FI;EIGI;IAOI,0BAAA;EL4+FV;EKn/FM;IAOI,gCAAA;EL++FV;EKt/FM;IAOI,yBAAA;ELk/FV;EKz/FM;IAOI,wBAAA;ELq/FV;EK5/FM;IAOI,+BAAA;ELw/FV;EK//FM;IAOI,yBAAA;EL2/FV;EKlgGM;IAOI,6BAAA;EL8/FV;EKrgGM;IAOI,8BAAA;ELigGV;EKxgGM;IAOI,wBAAA;ELogGV;EK3gGM;IAOI,+BAAA;ELugGV;EK9gGM;IAOI,wBAAA;EL0gGV;EKjhGM;IAOI,yBAAA;EL6gGV;EKphGM;IAOI,8BAAA;ELghGV;EKvhGM;IAOI,iCAAA;ELmhGV;EK1hGM;IAOI,sCAAA;ELshGV;EK7hGM;IAOI,yCAAA;ELyhGV;EKhiGM;IAOI,uBAAA;EL4hGV;EKniGM;IAOI,uBAAA;EL+hGV;EKtiGM;IAOI,yBAAA;ELkiGV;EKziGM;IAOI,yBAAA;ELqiGV;EK5iGM;IAOI,0BAAA;ELwiGV;EK/iGM;IAOI,4BAAA;EL2iGV;EKljGM;IAOI,kCAAA;EL8iGV;EKrjGM;IAOI,sCAAA;ELijGV;EKxjGM;IAOI,oCAAA;ELojGV;EK3jGM;IAOI,kCAAA;ELujGV;EK9jGM;IAOI,yCAAA;EL0jGV;EKjkGM;IAOI,wCAAA;EL6jGV;EKpkGM;IAOI,wCAAA;ELgkGV;EKvkGM;IAOI,kCAAA;ELmkGV;EK1kGM;IAOI,gCAAA;ELskGV;EK7kGM;IAOI,8BAAA;ELykGV;EKhlGM;IAOI,gCAAA;EL4kGV;EKnlGM;IAOI,+BAAA;EL+kGV;EKtlGM;IAOI,oCAAA;ELklGV;EKzlGM;IAOI,kCAAA;ELqlGV;EK5lGM;IAOI,gCAAA;ELwlGV;EK/l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ELi3GV;EKx3GM;IAOI,+BAAA;ELo3GV;EK33GM;IAOI,8BAAA;ELu3GV;EK93GM;IAOI,4BAAA;EL03GV;EKj4GM;IAOI,8BAAA;EL63GV;EKp4GM;IAOI,4BAAA;ELg4GV;EKv4GM;IAOI,2BAAA;ELm4GV;EK14GM;IAOI,iCAAA;ELs4GV;EK74GM;IAOI,gCAAA;ELy4GV;EKh5GM;IAOI,8BAAA;EL44GV;EKn5GM;IAOI,gCAAA;EL+4GV;EKt5GM;IAOI,8BAAA;ELk5GV;EKz5GM;IAOI,4BAAA;ELq5GV;EK55GM;IAOI,kCAAA;ELw5GV;EK/5GM;IAOI,iCAAA;EL25GV;EKl6GM;IAOI,+BAAA;EL85GV;EKr6GM;IAOI,iCAAA;ELi6GV;EKx6GM;IAOI,+BAAA;ELo6GV;EK36GM;IAOI,0BAAA;ELu6GV;EK96GM;IAOI,gCAAA;EL06GV;EKj7GM;IAOI,+BAAA;EL66GV;EKp7GM;IAOI,6BAAA;ELg7GV;EKv7GM;IAOI,+BAAA;ELm7GV;EK17GM;IAOI,6BAAA;ELs7GV;AACF;ACj8GI;EIGI;IAOI,0BAAA;EL27GV;EKl8GM;IAOI,gCAAA;EL87GV;EKr8GM;IAOI,yBAAA;ELi8GV;EKx8GM;IAOI,wBAAA;ELo8GV;EK38GM;IAOI,+BAAA;ELu8GV;EK98GM;IAOI,yBAAA;EL08GV;EKj9GM;IAOI,6BAAA;EL68GV;EKp9GM;IAOI,8BAAA;ELg9GV;EKv9GM;IAOI,wBAAA;ELm9GV;EK19GM;IAOI,+BAAA;ELs9GV;EK79GM;IAOI,wBAAA;ELy9GV;EKh+GM;IAOI,yBAAA;EL49GV;EKn+GM;IAOI,8BAAA;EL+9GV;EKt+GM;IAOI,iCAAA;ELk+GV;EKz+GM;IAOI,sCAAA;ELq+GV;EK5+GM;IAOI,yCAAA;ELw+GV;EK/+GM;IAOI,uBAAA;EL2+GV;EKl/GM;IAOI,uBAAA;EL8+GV;EKr/GM;IAOI,yBAAA;ELi/GV;EKx/GM;IAOI,yBAAA;ELo/GV;EK3/GM;IAOI,0BAAA;ELu/GV;EK9/GM;IAOI,4BAAA;EL0/GV;EKjgHM;IAOI,kCAAA;EL6/GV;EKpgHM;IAOI,sCAAA;ELggHV;EKvgHM;I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","file":"bootstrap-grid.css","sourcesContent":["@mixin bsBanner($file) {\n /*!\n * Bootstrap #{$file} v5.3.3 (https://getbootstrap.com/)\n * Copyright 2011-2024 The Bootstrap Authors\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n}\n","// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n@if $enable-container-classes {\n // Single container class with breakpoint max-widths\n .container,\n // 100% wide container at all breakpoints\n .container-fluid {\n @include make-container();\n }\n\n // Responsive containers that are 100% wide until a breakpoint\n @each $breakpoint, $container-max-width in $container-max-widths {\n .container-#{$breakpoint} {\n @extend .container-fluid;\n }\n\n @include media-breakpoint-up($breakpoint, $grid-breakpoints) {\n %responsive-container-#{$breakpoint} {\n max-width: $container-max-width;\n }\n\n // Extend each breakpoint which is smaller or equal to the current breakpoint\n $extend-breakpoint: true;\n\n @each $name, $width in $grid-breakpoints {\n @if ($extend-breakpoint) {\n .container#{breakpoint-infix($name, $grid-breakpoints)} {\n @extend %responsive-container-#{$breakpoint};\n }\n\n // Once the current breakpoint is reached, stop extending\n @if ($breakpoint == $name) {\n $extend-breakpoint: false;\n }\n }\n }\n }\n }\n}\n","// Container mixins\n\n@mixin make-container($gutter: $container-padding-x) {\n --#{$prefix}gutter-x: #{$gutter};\n --#{$prefix}gutter-y: 0;\n width: 100%;\n padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n margin-right: auto;\n margin-left: auto;\n}\n","/*!\n * Bootstrap Grid v5.3.3 (https://getbootstrap.com/)\n * Copyright 2011-2024 The Bootstrap Authors\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n.container,\n.container-fluid,\n.container-xxl,\n.container-xl,\n.container-lg,\n.container-md,\n.container-sm {\n --bs-gutter-x: 1.5rem;\n --bs-gutter-y: 0;\n width: 100%;\n padding-right: calc(var(--bs-gutter-x) * 0.5);\n padding-left: calc(var(--bs-gutter-x) * 0.5);\n margin-right: auto;\n margin-left: auto;\n}\n\n@media (min-width: 576px) {\n .container-sm, .container {\n max-width: 540px;\n }\n}\n@media (min-width: 768px) {\n .container-md, .container-sm, .container {\n max-width: 720px;\n }\n}\n@media (min-width: 992px) {\n .container-lg, .container-md, .container-sm, .container {\n max-width: 960px;\n }\n}\n@media (min-width: 1200px) {\n .container-xl, .container-lg, .container-md, .container-sm, .container {\n max-width: 1140px;\n }\n}\n@media (min-width: 1400px) {\n .container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container {\n max-width: 1320px;\n }\n}\n:root {\n --bs-breakpoint-xs: 0;\n --bs-breakpoint-sm: 576px;\n --bs-breakpoint-md: 768px;\n --bs-breakpoint-lg: 992px;\n --bs-breakpoint-xl: 1200px;\n --bs-breakpoint-xxl: 1400px;\n}\n\n.row {\n --bs-gutter-x: 1.5rem;\n --bs-gutter-y: 0;\n display: flex;\n flex-wrap: wrap;\n margin-top: calc(-1 * var(--bs-gutter-y));\n margin-right: calc(-0.5 * var(--bs-gutter-x));\n margin-left: calc(-0.5 * var(--bs-gutter-x));\n}\n.row > * {\n box-sizing: border-box;\n flex-shrink: 0;\n width: 100%;\n max-width: 100%;\n padding-right: calc(var(--bs-gutter-x) * 0.5);\n padding-left: calc(var(--bs-gutter-x) * 0.5);\n margin-top: var(--bs-gutter-y);\n}\n\n.col {\n flex: 1 0 0%;\n}\n\n.row-cols-auto > * {\n flex: 0 0 auto;\n width: auto;\n}\n\n.row-cols-1 > * {\n flex: 0 0 auto;\n width: 100%;\n}\n\n.row-cols-2 > * {\n flex: 0 0 auto;\n width: 50%;\n}\n\n.row-cols-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n}\n\n.row-cols-4 > * {\n flex: 0 0 auto;\n width: 25%;\n}\n\n.row-cols-5 > * {\n flex: 0 0 auto;\n width: 20%;\n}\n\n.row-cols-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n}\n\n.col-auto {\n flex: 0 0 auto;\n width: auto;\n}\n\n.col-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n}\n\n.col-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n}\n\n.col-3 {\n flex: 0 0 auto;\n width: 25%;\n}\n\n.col-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n}\n\n.col-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n}\n\n.col-6 {\n flex: 0 0 auto;\n width: 50%;\n}\n\n.col-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n}\n\n.col-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n}\n\n.col-9 {\n flex: 0 0 auto;\n width: 75%;\n}\n\n.col-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n}\n\n.col-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n}\n\n.col-12 {\n flex: 0 0 auto;\n width: 100%;\n}\n\n.offset-1 {\n margin-left: 8.33333333%;\n}\n\n.offset-2 {\n margin-left: 16.66666667%;\n}\n\n.offset-3 {\n margin-left: 25%;\n}\n\n.offset-4 {\n margin-left: 33.33333333%;\n}\n\n.offset-5 {\n margin-left: 41.66666667%;\n}\n\n.offset-6 {\n margin-left: 50%;\n}\n\n.offset-7 {\n margin-left: 58.33333333%;\n}\n\n.offset-8 {\n margin-left: 66.66666667%;\n}\n\n.offset-9 {\n margin-left: 75%;\n}\n\n.offset-10 {\n margin-left: 83.33333333%;\n}\n\n.offset-11 {\n margin-left: 91.66666667%;\n}\n\n.g-0,\n.gx-0 {\n --bs-gutter-x: 0;\n}\n\n.g-0,\n.gy-0 {\n --bs-gutter-y: 0;\n}\n\n.g-1,\n.gx-1 {\n --bs-gutter-x: 0.25rem;\n}\n\n.g-1,\n.gy-1 {\n --bs-gutter-y: 0.25rem;\n}\n\n.g-2,\n.gx-2 {\n --bs-gutter-x: 0.5rem;\n}\n\n.g-2,\n.gy-2 {\n --bs-gutter-y: 0.5rem;\n}\n\n.g-3,\n.gx-3 {\n --bs-gutter-x: 1rem;\n}\n\n.g-3,\n.gy-3 {\n --bs-gutter-y: 1rem;\n}\n\n.g-4,\n.gx-4 {\n --bs-gutter-x: 1.5rem;\n}\n\n.g-4,\n.gy-4 {\n --bs-gutter-y: 1.5rem;\n}\n\n.g-5,\n.gx-5 {\n --bs-gutter-x: 3rem;\n}\n\n.g-5,\n.gy-5 {\n --bs-gutter-y: 3rem;\n}\n\n@media (min-width: 576px) {\n .col-sm {\n flex: 1 0 0%;\n }\n .row-cols-sm-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-sm-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-sm-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-sm-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-sm-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-sm-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-sm-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-sm-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-sm-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-sm-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-sm-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-sm-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-sm-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-sm-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-sm-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-sm-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-sm-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-sm-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-sm-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-sm-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-sm-0 {\n margin-left: 0;\n }\n .offset-sm-1 {\n margin-left: 8.33333333%;\n }\n .offset-sm-2 {\n margin-left: 16.66666667%;\n }\n .offset-sm-3 {\n margin-left: 25%;\n }\n .offset-sm-4 {\n margin-left: 33.33333333%;\n }\n .offset-sm-5 {\n margin-left: 41.66666667%;\n }\n .offset-sm-6 {\n margin-left: 50%;\n }\n .offset-sm-7 {\n margin-left: 58.33333333%;\n }\n .offset-sm-8 {\n margin-left: 66.66666667%;\n }\n .offset-sm-9 {\n margin-left: 75%;\n }\n .offset-sm-10 {\n margin-left: 83.33333333%;\n }\n .offset-sm-11 {\n margin-left: 91.66666667%;\n }\n .g-sm-0,\n .gx-sm-0 {\n --bs-gutter-x: 0;\n }\n .g-sm-0,\n .gy-sm-0 {\n --bs-gutter-y: 0;\n }\n .g-sm-1,\n .gx-sm-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-sm-1,\n .gy-sm-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-sm-2,\n .gx-sm-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-sm-2,\n .gy-sm-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-sm-3,\n .gx-sm-3 {\n --bs-gutter-x: 1rem;\n }\n .g-sm-3,\n .gy-sm-3 {\n --bs-gutter-y: 1rem;\n }\n .g-sm-4,\n .gx-sm-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-sm-4,\n .gy-sm-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-sm-5,\n .gx-sm-5 {\n --bs-gutter-x: 3rem;\n }\n .g-sm-5,\n .gy-sm-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 768px) {\n .col-md {\n flex: 1 0 0%;\n }\n .row-cols-md-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-md-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-md-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-md-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-md-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-md-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-md-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-md-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-md-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-md-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-md-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-md-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-md-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-md-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-md-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-md-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-md-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-md-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-md-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-md-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-md-0 {\n margin-left: 0;\n }\n .offset-md-1 {\n margin-left: 8.33333333%;\n }\n .offset-md-2 {\n margin-left: 16.66666667%;\n }\n .offset-md-3 {\n margin-left: 25%;\n }\n .offset-md-4 {\n margin-left: 33.33333333%;\n }\n .offset-md-5 {\n margin-left: 41.66666667%;\n }\n .offset-md-6 {\n margin-left: 50%;\n }\n .offset-md-7 {\n margin-left: 58.33333333%;\n }\n .offset-md-8 {\n margin-left: 66.66666667%;\n }\n .offset-md-9 {\n margin-left: 75%;\n }\n .offset-md-10 {\n margin-left: 83.33333333%;\n }\n .offset-md-11 {\n margin-left: 91.66666667%;\n }\n .g-md-0,\n .gx-md-0 {\n --bs-gutter-x: 0;\n }\n .g-md-0,\n .gy-md-0 {\n --bs-gutter-y: 0;\n }\n .g-md-1,\n .gx-md-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-md-1,\n .gy-md-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-md-2,\n .gx-md-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-md-2,\n .gy-md-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-md-3,\n .gx-md-3 {\n --bs-gutter-x: 1rem;\n }\n .g-md-3,\n .gy-md-3 {\n --bs-gutter-y: 1rem;\n }\n .g-md-4,\n .gx-md-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-md-4,\n .gy-md-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-md-5,\n .gx-md-5 {\n --bs-gutter-x: 3rem;\n }\n .g-md-5,\n .gy-md-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 992px) {\n .col-lg {\n flex: 1 0 0%;\n }\n .row-cols-lg-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-lg-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-lg-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-lg-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-lg-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-lg-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-lg-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-lg-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-lg-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-lg-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-lg-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-lg-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-lg-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-lg-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-lg-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-lg-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-lg-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-lg-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-lg-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-lg-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-lg-0 {\n margin-left: 0;\n }\n .offset-lg-1 {\n margin-left: 8.33333333%;\n }\n .offset-lg-2 {\n margin-left: 16.66666667%;\n }\n .offset-lg-3 {\n margin-left: 25%;\n }\n .offset-lg-4 {\n margin-left: 33.33333333%;\n }\n .offset-lg-5 {\n margin-left: 41.66666667%;\n }\n .offset-lg-6 {\n margin-left: 50%;\n }\n .offset-lg-7 {\n margin-left: 58.33333333%;\n }\n .offset-lg-8 {\n margin-left: 66.66666667%;\n }\n .offset-lg-9 {\n margin-left: 75%;\n }\n .offset-lg-10 {\n margin-left: 83.33333333%;\n }\n .offset-lg-11 {\n margin-left: 91.66666667%;\n }\n .g-lg-0,\n .gx-lg-0 {\n --bs-gutter-x: 0;\n }\n .g-lg-0,\n .gy-lg-0 {\n --bs-gutter-y: 0;\n }\n .g-lg-1,\n .gx-lg-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-lg-1,\n .gy-lg-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-lg-2,\n .gx-lg-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-lg-2,\n .gy-lg-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-lg-3,\n .gx-lg-3 {\n --bs-gutter-x: 1rem;\n }\n .g-lg-3,\n .gy-lg-3 {\n --bs-gutter-y: 1rem;\n }\n .g-lg-4,\n .gx-lg-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-lg-4,\n .gy-lg-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-lg-5,\n .gx-lg-5 {\n --bs-gutter-x: 3rem;\n }\n .g-lg-5,\n .gy-lg-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 1200px) {\n .col-xl {\n flex: 1 0 0%;\n }\n .row-cols-xl-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-xl-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-xl-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-xl-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-xl-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-xl-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-xl-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xl-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-xl-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-xl-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xl-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-xl-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-xl-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-xl-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-xl-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-xl-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-xl-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-xl-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-xl-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-xl-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-xl-0 {\n margin-left: 0;\n }\n .offset-xl-1 {\n margin-left: 8.33333333%;\n }\n .offset-xl-2 {\n margin-left: 16.66666667%;\n }\n .offset-xl-3 {\n margin-left: 25%;\n }\n .offset-xl-4 {\n margin-left: 33.33333333%;\n }\n .offset-xl-5 {\n margin-left: 41.66666667%;\n }\n .offset-xl-6 {\n margin-left: 50%;\n }\n .offset-xl-7 {\n margin-left: 58.33333333%;\n }\n .offset-xl-8 {\n margin-left: 66.66666667%;\n }\n .offset-xl-9 {\n margin-left: 75%;\n }\n .offset-xl-10 {\n margin-left: 83.33333333%;\n }\n .offset-xl-11 {\n margin-left: 91.66666667%;\n }\n .g-xl-0,\n .gx-xl-0 {\n --bs-gutter-x: 0;\n }\n .g-xl-0,\n .gy-xl-0 {\n --bs-gutter-y: 0;\n }\n .g-xl-1,\n .gx-xl-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-xl-1,\n .gy-xl-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-xl-2,\n .gx-xl-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-xl-2,\n .gy-xl-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-xl-3,\n .gx-xl-3 {\n --bs-gutter-x: 1rem;\n }\n .g-xl-3,\n .gy-xl-3 {\n --bs-gutter-y: 1rem;\n }\n .g-xl-4,\n .gx-xl-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-xl-4,\n .gy-xl-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-xl-5,\n .gx-xl-5 {\n --bs-gutter-x: 3rem;\n }\n .g-xl-5,\n .gy-xl-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 1400px) {\n .col-xxl {\n flex: 1 0 0%;\n }\n .row-cols-xxl-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-xxl-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-xxl-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-xxl-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-xxl-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-xxl-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-xxl-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xxl-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-xxl-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-xxl-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xxl-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-xxl-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-xxl-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-xxl-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-xxl-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-xxl-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-xxl-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-xxl-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-xxl-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-xxl-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-xxl-0 {\n margin-left: 0;\n }\n .offset-xxl-1 {\n margin-left: 8.33333333%;\n }\n .offset-xxl-2 {\n margin-left: 16.66666667%;\n }\n .offset-xxl-3 {\n margin-left: 25%;\n }\n .offset-xxl-4 {\n margin-left: 33.33333333%;\n }\n .offset-xxl-5 {\n margin-left: 41.66666667%;\n }\n .offset-xxl-6 {\n margin-left: 50%;\n }\n .offset-xxl-7 {\n margin-left: 58.33333333%;\n }\n .offset-xxl-8 {\n margin-left: 66.66666667%;\n }\n .offset-xxl-9 {\n margin-left: 75%;\n }\n .offset-xxl-10 {\n margin-left: 83.33333333%;\n }\n .offset-xxl-11 {\n margin-left: 91.66666667%;\n }\n .g-xxl-0,\n .gx-xxl-0 {\n --bs-gutter-x: 0;\n }\n .g-xxl-0,\n .gy-xxl-0 {\n --bs-gutter-y: 0;\n }\n .g-xxl-1,\n .gx-xxl-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-xxl-1,\n .gy-xxl-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-xxl-2,\n .gx-xxl-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-xxl-2,\n .gy-xxl-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-xxl-3,\n .gx-xxl-3 {\n --bs-gutter-x: 1rem;\n }\n .g-xxl-3,\n .gy-xxl-3 {\n --bs-gutter-y: 1rem;\n }\n .g-xxl-4,\n .gx-xxl-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-xxl-4,\n .gy-xxl-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-xxl-5,\n .gx-xxl-5 {\n --bs-gutter-x: 3rem;\n }\n .g-xxl-5,\n .gy-xxl-5 {\n --bs-gutter-y: 3rem;\n }\n}\n.d-inline {\n display: inline !important;\n}\n\n.d-inline-block {\n display: inline-block !important;\n}\n\n.d-block {\n display: block !important;\n}\n\n.d-grid {\n display: grid !important;\n}\n\n.d-inline-grid {\n display: inline-grid !important;\n}\n\n.d-table {\n display: table !important;\n}\n\n.d-table-row {\n display: table-row !important;\n}\n\n.d-table-cell {\n display: table-cell !important;\n}\n\n.d-flex {\n display: flex !important;\n}\n\n.d-inline-flex {\n display: inline-flex !important;\n}\n\n.d-none {\n display: none !important;\n}\n\n.flex-fill {\n flex: 1 1 auto !important;\n}\n\n.flex-row {\n flex-direction: row !important;\n}\n\n.flex-column {\n flex-direction: column !important;\n}\n\n.flex-row-reverse {\n flex-direction: row-reverse !important;\n}\n\n.flex-column-reverse {\n flex-direction: column-reverse !important;\n}\n\n.flex-grow-0 {\n flex-grow: 0 !important;\n}\n\n.flex-grow-1 {\n flex-grow: 1 !important;\n}\n\n.flex-shrink-0 {\n flex-shrink: 0 !important;\n}\n\n.flex-shrink-1 {\n flex-shrink: 1 !important;\n}\n\n.flex-wrap {\n flex-wrap: wrap !important;\n}\n\n.flex-nowrap {\n flex-wrap: nowrap !important;\n}\n\n.flex-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n}\n\n.justify-content-start {\n justify-content: flex-start !important;\n}\n\n.justify-content-end {\n justify-content: flex-end !important;\n}\n\n.justify-content-center {\n justify-content: center !important;\n}\n\n.justify-content-between {\n justify-content: space-between !important;\n}\n\n.justify-content-around {\n justify-content: space-around !important;\n}\n\n.justify-content-evenly {\n justify-content: space-evenly !important;\n}\n\n.align-items-start {\n align-items: flex-start !important;\n}\n\n.align-items-end {\n align-items: flex-end !important;\n}\n\n.align-items-center {\n align-items: center !important;\n}\n\n.align-items-baseline {\n align-items: baseline !important;\n}\n\n.align-items-stretch {\n align-items: stretch !important;\n}\n\n.align-content-start {\n align-content: flex-start !important;\n}\n\n.align-content-end {\n align-content: flex-end !important;\n}\n\n.align-content-center {\n align-content: center !important;\n}\n\n.align-content-between {\n align-content: space-between !important;\n}\n\n.align-content-around {\n align-content: space-around !important;\n}\n\n.align-content-stretch {\n align-content: stretch !important;\n}\n\n.align-self-auto {\n align-self: auto !important;\n}\n\n.align-self-start {\n align-self: flex-start !important;\n}\n\n.align-self-end {\n align-self: flex-end !important;\n}\n\n.align-self-center {\n align-self: center !important;\n}\n\n.align-self-baseline {\n align-self: baseline !important;\n}\n\n.align-self-stretch {\n align-self: stretch !important;\n}\n\n.order-first {\n order: -1 !important;\n}\n\n.order-0 {\n order: 0 !important;\n}\n\n.order-1 {\n order: 1 !important;\n}\n\n.order-2 {\n order: 2 !important;\n}\n\n.order-3 {\n order: 3 !important;\n}\n\n.order-4 {\n order: 4 !important;\n}\n\n.order-5 {\n order: 5 !important;\n}\n\n.order-last {\n order: 6 !important;\n}\n\n.m-0 {\n margin: 0 !important;\n}\n\n.m-1 {\n margin: 0.25rem !important;\n}\n\n.m-2 {\n margin: 0.5rem !important;\n}\n\n.m-3 {\n margin: 1rem !important;\n}\n\n.m-4 {\n margin: 1.5rem !important;\n}\n\n.m-5 {\n margin: 3rem !important;\n}\n\n.m-auto {\n margin: auto !important;\n}\n\n.mx-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n}\n\n.mx-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n}\n\n.mx-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n}\n\n.mx-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n}\n\n.mx-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n}\n\n.mx-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n}\n\n.mx-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n}\n\n.my-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n.my-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n}\n\n.my-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n}\n\n.my-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n}\n\n.my-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n}\n\n.my-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n}\n\n.my-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n}\n\n.mt-0 {\n margin-top: 0 !important;\n}\n\n.mt-1 {\n margin-top: 0.25rem !important;\n}\n\n.mt-2 {\n margin-top: 0.5rem !important;\n}\n\n.mt-3 {\n margin-top: 1rem !important;\n}\n\n.mt-4 {\n margin-top: 1.5rem !important;\n}\n\n.mt-5 {\n margin-top: 3rem !important;\n}\n\n.mt-auto {\n margin-top: auto !important;\n}\n\n.me-0 {\n margin-right: 0 !important;\n}\n\n.me-1 {\n margin-right: 0.25rem !important;\n}\n\n.me-2 {\n margin-right: 0.5rem !important;\n}\n\n.me-3 {\n margin-right: 1rem !important;\n}\n\n.me-4 {\n margin-right: 1.5rem !important;\n}\n\n.me-5 {\n margin-right: 3rem !important;\n}\n\n.me-auto {\n margin-right: auto !important;\n}\n\n.mb-0 {\n margin-bottom: 0 !important;\n}\n\n.mb-1 {\n margin-bottom: 0.25rem !important;\n}\n\n.mb-2 {\n margin-bottom: 0.5rem !important;\n}\n\n.mb-3 {\n margin-bottom: 1rem !important;\n}\n\n.mb-4 {\n margin-bottom: 1.5rem !important;\n}\n\n.mb-5 {\n margin-bottom: 3rem !important;\n}\n\n.mb-auto {\n margin-bottom: auto !important;\n}\n\n.ms-0 {\n margin-left: 0 !important;\n}\n\n.ms-1 {\n margin-left: 0.25rem !important;\n}\n\n.ms-2 {\n margin-left: 0.5rem !important;\n}\n\n.ms-3 {\n margin-left: 1rem !important;\n}\n\n.ms-4 {\n margin-left: 1.5rem !important;\n}\n\n.ms-5 {\n margin-left: 3rem !important;\n}\n\n.ms-auto {\n margin-left: auto !important;\n}\n\n.p-0 {\n padding: 0 !important;\n}\n\n.p-1 {\n padding: 0.25rem !important;\n}\n\n.p-2 {\n padding: 0.5rem !important;\n}\n\n.p-3 {\n padding: 1rem !important;\n}\n\n.p-4 {\n padding: 1.5rem !important;\n}\n\n.p-5 {\n padding: 3rem !important;\n}\n\n.px-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n}\n\n.px-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n}\n\n.px-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n}\n\n.px-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n}\n\n.px-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n}\n\n.px-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n}\n\n.py-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n}\n\n.py-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n}\n\n.py-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n}\n\n.py-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n}\n\n.py-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n}\n\n.py-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n}\n\n.pt-0 {\n padding-top: 0 !important;\n}\n\n.pt-1 {\n padding-top: 0.25rem !important;\n}\n\n.pt-2 {\n padding-top: 0.5rem !important;\n}\n\n.pt-3 {\n padding-top: 1rem !important;\n}\n\n.pt-4 {\n padding-top: 1.5rem !important;\n}\n\n.pt-5 {\n padding-top: 3rem !important;\n}\n\n.pe-0 {\n padding-right: 0 !important;\n}\n\n.pe-1 {\n padding-right: 0.25rem !important;\n}\n\n.pe-2 {\n padding-right: 0.5rem !important;\n}\n\n.pe-3 {\n padding-right: 1rem !important;\n}\n\n.pe-4 {\n padding-right: 1.5rem !important;\n}\n\n.pe-5 {\n padding-right: 3rem !important;\n}\n\n.pb-0 {\n padding-bottom: 0 !important;\n}\n\n.pb-1 {\n padding-bottom: 0.25rem !important;\n}\n\n.pb-2 {\n padding-bottom: 0.5rem !important;\n}\n\n.pb-3 {\n padding-bottom: 1rem !important;\n}\n\n.pb-4 {\n padding-bottom: 1.5rem !important;\n}\n\n.pb-5 {\n padding-bottom: 3rem !important;\n}\n\n.ps-0 {\n padding-left: 0 !important;\n}\n\n.ps-1 {\n padding-left: 0.25rem !important;\n}\n\n.ps-2 {\n padding-left: 0.5rem !important;\n}\n\n.ps-3 {\n padding-left: 1rem !important;\n}\n\n.ps-4 {\n padding-left: 1.5rem !important;\n}\n\n.ps-5 {\n padding-left: 3rem !important;\n}\n\n@media (min-width: 576px) {\n .d-sm-inline {\n display: inline !important;\n }\n .d-sm-inline-block {\n display: inline-block !important;\n }\n .d-sm-block {\n display: block !important;\n }\n .d-sm-grid {\n display: grid !important;\n }\n .d-sm-inline-grid {\n display: inline-grid !important;\n }\n .d-sm-table {\n display: table !important;\n }\n .d-sm-table-row {\n display: table-row !important;\n }\n .d-sm-table-cell {\n display: table-cell !important;\n }\n .d-sm-flex {\n display: flex !important;\n }\n .d-sm-inline-flex {\n display: inline-flex !important;\n }\n .d-sm-none {\n display: none !important;\n }\n .flex-sm-fill {\n flex: 1 1 auto !important;\n }\n .flex-sm-row {\n flex-direction: row !important;\n }\n .flex-sm-column {\n flex-direction: column !important;\n }\n .flex-sm-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-sm-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-sm-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-sm-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-sm-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-sm-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-sm-wrap {\n flex-wrap: wrap !important;\n }\n .flex-sm-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-sm-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-sm-start {\n justify-content: flex-start !important;\n }\n .justify-content-sm-end {\n justify-content: flex-end !important;\n }\n .justify-content-sm-center {\n justify-content: center !important;\n }\n .justify-content-sm-between {\n justify-content: space-between !important;\n }\n .justify-content-sm-around {\n justify-content: space-around !important;\n }\n .justify-content-sm-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-sm-start {\n align-items: flex-start !important;\n }\n .align-items-sm-end {\n align-items: flex-end !important;\n }\n .align-items-sm-center {\n align-items: center !important;\n }\n .align-items-sm-baseline {\n align-items: baseline !important;\n }\n .align-items-sm-stretch {\n align-items: stretch !important;\n }\n .align-content-sm-start {\n align-content: flex-start !important;\n }\n .align-content-sm-end {\n align-content: flex-end !important;\n }\n .align-content-sm-center {\n align-content: center !important;\n }\n .align-content-sm-between {\n align-content: space-between !important;\n }\n .align-content-sm-around {\n align-content: space-around !important;\n }\n .align-content-sm-stretch {\n align-content: stretch !important;\n }\n .align-self-sm-auto {\n align-self: auto !important;\n }\n .align-self-sm-start {\n align-self: flex-start !important;\n }\n .align-self-sm-end {\n align-self: flex-end !important;\n }\n .align-self-sm-center {\n align-self: center !important;\n }\n .align-self-sm-baseline {\n align-self: baseline !important;\n }\n .align-self-sm-stretch {\n align-self: stretch !important;\n }\n .order-sm-first {\n order: -1 !important;\n }\n .order-sm-0 {\n order: 0 !important;\n }\n .order-sm-1 {\n order: 1 !important;\n }\n .order-sm-2 {\n order: 2 !important;\n }\n .order-sm-3 {\n order: 3 !important;\n }\n .order-sm-4 {\n order: 4 !important;\n }\n .order-sm-5 {\n order: 5 !important;\n }\n .order-sm-last {\n order: 6 !important;\n }\n .m-sm-0 {\n margin: 0 !important;\n }\n .m-sm-1 {\n margin: 0.25rem !important;\n }\n .m-sm-2 {\n margin: 0.5rem !important;\n }\n .m-sm-3 {\n margin: 1rem !important;\n }\n .m-sm-4 {\n margin: 1.5rem !important;\n }\n .m-sm-5 {\n margin: 3rem !important;\n }\n .m-sm-auto {\n margin: auto !important;\n }\n .mx-sm-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-sm-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-sm-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-sm-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-sm-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-sm-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-sm-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-sm-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-sm-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-sm-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-sm-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-sm-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-sm-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-sm-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-sm-0 {\n margin-top: 0 !important;\n }\n .mt-sm-1 {\n margin-top: 0.25rem !important;\n }\n .mt-sm-2 {\n margin-top: 0.5rem !important;\n }\n .mt-sm-3 {\n margin-top: 1rem !important;\n }\n .mt-sm-4 {\n margin-top: 1.5rem !important;\n }\n .mt-sm-5 {\n margin-top: 3rem !important;\n }\n .mt-sm-auto {\n margin-top: auto !important;\n }\n .me-sm-0 {\n margin-right: 0 !important;\n }\n .me-sm-1 {\n margin-right: 0.25rem !important;\n }\n .me-sm-2 {\n margin-right: 0.5rem !important;\n }\n .me-sm-3 {\n margin-right: 1rem !important;\n }\n .me-sm-4 {\n margin-right: 1.5rem !important;\n }\n .me-sm-5 {\n margin-right: 3rem !important;\n }\n .me-sm-auto {\n margin-right: auto !important;\n }\n .mb-sm-0 {\n margin-bottom: 0 !important;\n }\n .mb-sm-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-sm-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-sm-3 {\n margin-bottom: 1rem !important;\n }\n .mb-sm-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-sm-5 {\n margin-bottom: 3rem !important;\n }\n .mb-sm-auto {\n margin-bottom: auto !important;\n }\n .ms-sm-0 {\n margin-left: 0 !important;\n }\n .ms-sm-1 {\n margin-left: 0.25rem !important;\n }\n .ms-sm-2 {\n margin-left: 0.5rem !important;\n }\n .ms-sm-3 {\n margin-left: 1rem !important;\n }\n .ms-sm-4 {\n margin-left: 1.5rem !important;\n }\n .ms-sm-5 {\n margin-left: 3rem !important;\n }\n .ms-sm-auto {\n margin-left: auto !important;\n }\n .p-sm-0 {\n padding: 0 !important;\n }\n .p-sm-1 {\n padding: 0.25rem !important;\n }\n .p-sm-2 {\n padding: 0.5rem !important;\n }\n .p-sm-3 {\n padding: 1rem !important;\n }\n .p-sm-4 {\n padding: 1.5rem !important;\n }\n .p-sm-5 {\n padding: 3rem !important;\n }\n .px-sm-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-sm-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-sm-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-sm-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-sm-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-sm-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-sm-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-sm-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-sm-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-sm-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-sm-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-sm-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-sm-0 {\n padding-top: 0 !important;\n }\n .pt-sm-1 {\n padding-top: 0.25rem !important;\n }\n .pt-sm-2 {\n padding-top: 0.5rem !important;\n }\n .pt-sm-3 {\n padding-top: 1rem !important;\n }\n .pt-sm-4 {\n padding-top: 1.5rem !important;\n }\n .pt-sm-5 {\n padding-top: 3rem !important;\n }\n .pe-sm-0 {\n padding-right: 0 !important;\n }\n .pe-sm-1 {\n padding-right: 0.25rem !important;\n }\n .pe-sm-2 {\n padding-right: 0.5rem !important;\n }\n .pe-sm-3 {\n padding-right: 1rem !important;\n }\n .pe-sm-4 {\n padding-right: 1.5rem !important;\n }\n .pe-sm-5 {\n padding-right: 3rem !important;\n }\n .pb-sm-0 {\n padding-bottom: 0 !important;\n }\n .pb-sm-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-sm-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-sm-3 {\n padding-bottom: 1rem !important;\n }\n .pb-sm-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-sm-5 {\n padding-bottom: 3rem !important;\n }\n .ps-sm-0 {\n padding-left: 0 !important;\n }\n .ps-sm-1 {\n padding-left: 0.25rem !important;\n }\n .ps-sm-2 {\n padding-left: 0.5rem !important;\n }\n .ps-sm-3 {\n padding-left: 1rem !important;\n }\n .ps-sm-4 {\n padding-left: 1.5rem !important;\n }\n .ps-sm-5 {\n padding-left: 3rem !important;\n }\n}\n@media (min-width: 768px) {\n .d-md-inline {\n display: inline !important;\n }\n .d-md-inline-block {\n display: inline-block !important;\n }\n .d-md-block {\n display: block !important;\n }\n .d-md-grid {\n display: grid !important;\n }\n .d-md-inline-grid {\n display: inline-grid !important;\n }\n .d-md-table {\n display: table !important;\n }\n .d-md-table-row {\n display: table-row !important;\n }\n .d-md-table-cell {\n display: table-cell !important;\n }\n .d-md-flex {\n display: flex !important;\n }\n .d-md-inline-flex {\n display: inline-flex !important;\n }\n .d-md-none {\n display: none !important;\n }\n .flex-md-fill {\n flex: 1 1 auto !important;\n }\n .flex-md-row {\n flex-direction: row !important;\n }\n .flex-md-column {\n flex-direction: column !important;\n }\n .flex-md-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-md-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-md-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-md-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-md-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-md-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-md-wrap {\n flex-wrap: wrap !important;\n }\n .flex-md-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-md-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-md-start {\n justify-content: flex-start !important;\n }\n .justify-content-md-end {\n justify-content: flex-end !important;\n }\n .justify-content-md-center {\n justify-content: center !important;\n }\n .justify-content-md-between {\n justify-content: space-between !important;\n }\n .justify-content-md-around {\n justify-content: space-around !important;\n }\n .justify-content-md-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-md-start {\n align-items: flex-start !important;\n }\n .align-items-md-end {\n align-items: flex-end !important;\n }\n .align-items-md-center {\n align-items: center !important;\n }\n .align-items-md-baseline {\n align-items: baseline !important;\n }\n .align-items-md-stretch {\n align-items: stretch !important;\n }\n .align-content-md-start {\n align-content: flex-start !important;\n }\n .align-content-md-end {\n align-content: flex-end !important;\n }\n .align-content-md-center {\n align-content: center !important;\n }\n .align-content-md-between {\n align-content: space-between !important;\n }\n .align-content-md-around {\n align-content: space-around !important;\n }\n .align-content-md-stretch {\n align-content: stretch !important;\n }\n .align-self-md-auto {\n align-self: auto !important;\n }\n .align-self-md-start {\n align-self: flex-start !important;\n }\n .align-self-md-end {\n align-self: flex-end !important;\n }\n .align-self-md-center {\n align-self: center !important;\n }\n .align-self-md-baseline {\n align-self: baseline !important;\n }\n .align-self-md-stretch {\n align-self: stretch !important;\n }\n .order-md-first {\n order: -1 !important;\n }\n .order-md-0 {\n order: 0 !important;\n }\n .order-md-1 {\n order: 1 !important;\n }\n .order-md-2 {\n order: 2 !important;\n }\n .order-md-3 {\n order: 3 !important;\n }\n .order-md-4 {\n order: 4 !important;\n }\n .order-md-5 {\n order: 5 !important;\n }\n .order-md-last {\n order: 6 !important;\n }\n .m-md-0 {\n margin: 0 !important;\n }\n .m-md-1 {\n margin: 0.25rem !important;\n }\n .m-md-2 {\n margin: 0.5rem !important;\n }\n .m-md-3 {\n margin: 1rem !important;\n }\n .m-md-4 {\n margin: 1.5rem !important;\n }\n .m-md-5 {\n margin: 3rem !important;\n }\n .m-md-auto {\n margin: auto !important;\n }\n .mx-md-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-md-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-md-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-md-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-md-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-md-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-md-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-md-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-md-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-md-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-md-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-md-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-md-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-md-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-md-0 {\n margin-top: 0 !important;\n }\n .mt-md-1 {\n margin-top: 0.25rem !important;\n }\n .mt-md-2 {\n margin-top: 0.5rem !important;\n }\n .mt-md-3 {\n margin-top: 1rem !important;\n }\n .mt-md-4 {\n margin-top: 1.5rem !important;\n }\n .mt-md-5 {\n margin-top: 3rem !important;\n }\n .mt-md-auto {\n margin-top: auto !important;\n }\n .me-md-0 {\n margin-right: 0 !important;\n }\n .me-md-1 {\n margin-right: 0.25rem !important;\n }\n .me-md-2 {\n margin-right: 0.5rem !important;\n }\n .me-md-3 {\n margin-right: 1rem !important;\n }\n .me-md-4 {\n margin-right: 1.5rem !important;\n }\n .me-md-5 {\n margin-right: 3rem !important;\n }\n .me-md-auto {\n margin-right: auto !important;\n }\n .mb-md-0 {\n margin-bottom: 0 !important;\n }\n .mb-md-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-md-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-md-3 {\n margin-bottom: 1rem !important;\n }\n .mb-md-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-md-5 {\n margin-bottom: 3rem !important;\n }\n .mb-md-auto {\n margin-bottom: auto !important;\n }\n .ms-md-0 {\n margin-left: 0 !important;\n }\n .ms-md-1 {\n margin-left: 0.25rem !important;\n }\n .ms-md-2 {\n margin-left: 0.5rem !important;\n }\n .ms-md-3 {\n margin-left: 1rem !important;\n }\n .ms-md-4 {\n margin-left: 1.5rem !important;\n }\n .ms-md-5 {\n margin-left: 3rem !important;\n }\n .ms-md-auto {\n margin-left: auto !important;\n }\n .p-md-0 {\n padding: 0 !important;\n }\n .p-md-1 {\n padding: 0.25rem !important;\n }\n .p-md-2 {\n padding: 0.5rem !important;\n }\n .p-md-3 {\n padding: 1rem !important;\n }\n .p-md-4 {\n padding: 1.5rem !important;\n }\n .p-md-5 {\n padding: 3rem !important;\n }\n .px-md-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-md-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-md-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-md-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-md-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-md-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-md-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-md-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-md-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-md-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-md-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-md-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-md-0 {\n padding-top: 0 !important;\n }\n .pt-md-1 {\n padding-top: 0.25rem !important;\n }\n .pt-md-2 {\n padding-top: 0.5rem !important;\n }\n .pt-md-3 {\n padding-top: 1rem !important;\n }\n .pt-md-4 {\n padding-top: 1.5rem !important;\n }\n .pt-md-5 {\n padding-top: 3rem !important;\n }\n .pe-md-0 {\n padding-right: 0 !important;\n }\n .pe-md-1 {\n padding-right: 0.25rem !important;\n }\n .pe-md-2 {\n padding-right: 0.5rem !important;\n }\n .pe-md-3 {\n padding-right: 1rem !important;\n }\n .pe-md-4 {\n padding-right: 1.5rem !important;\n }\n .pe-md-5 {\n padding-right: 3rem !important;\n }\n .pb-md-0 {\n padding-bottom: 0 !important;\n }\n .pb-md-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-md-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-md-3 {\n padding-bottom: 1rem !important;\n }\n .pb-md-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-md-5 {\n padding-bottom: 3rem !important;\n }\n .ps-md-0 {\n padding-left: 0 !important;\n }\n .ps-md-1 {\n padding-left: 0.25rem !important;\n }\n .ps-md-2 {\n padding-left: 0.5rem !important;\n }\n .ps-md-3 {\n padding-left: 1rem !important;\n }\n .ps-md-4 {\n padding-left: 1.5rem !important;\n }\n .ps-md-5 {\n padding-left: 3rem !important;\n }\n}\n@media (min-width: 992px) {\n .d-lg-inline {\n display: inline !important;\n }\n .d-lg-inline-block {\n display: inline-block !important;\n }\n .d-lg-block {\n display: block !important;\n }\n .d-lg-grid {\n display: grid !important;\n }\n .d-lg-inline-grid {\n display: inline-grid !important;\n }\n .d-lg-table {\n display: table !important;\n }\n .d-lg-table-row {\n display: table-row !important;\n }\n .d-lg-table-cell {\n display: table-cell !important;\n }\n .d-lg-flex {\n display: flex !important;\n }\n .d-lg-inline-flex {\n display: inline-flex !important;\n }\n .d-lg-none {\n display: none !important;\n }\n .flex-lg-fill {\n flex: 1 1 auto !important;\n }\n .flex-lg-row {\n flex-direction: row !important;\n }\n .flex-lg-column {\n flex-direction: column !important;\n }\n .flex-lg-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-lg-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-lg-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-lg-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-lg-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-lg-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-lg-wrap {\n flex-wrap: wrap !important;\n }\n .flex-lg-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-lg-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-lg-start {\n justify-content: flex-start !important;\n }\n .justify-content-lg-end {\n justify-content: flex-end !important;\n }\n .justify-content-lg-center {\n justify-content: center !important;\n }\n .justify-content-lg-between {\n justify-content: space-between !important;\n }\n .justify-content-lg-around {\n justify-content: space-around !important;\n }\n .justify-content-lg-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-lg-start {\n align-items: flex-start !important;\n }\n .align-items-lg-end {\n align-items: flex-end !important;\n }\n .align-items-lg-center {\n align-items: center !important;\n }\n .align-items-lg-baseline {\n align-items: baseline !important;\n }\n .align-items-lg-stretch {\n align-items: stretch !important;\n }\n .align-content-lg-start {\n align-content: flex-start !important;\n }\n .align-content-lg-end {\n align-content: flex-end !important;\n }\n .align-content-lg-center {\n align-content: center !important;\n }\n .align-content-lg-between {\n align-content: space-between !important;\n }\n .align-content-lg-around {\n align-content: space-around !important;\n }\n .align-content-lg-stretch {\n align-content: stretch !important;\n }\n .align-self-lg-auto {\n align-self: auto !important;\n }\n .align-self-lg-start {\n align-self: flex-start !important;\n }\n .align-self-lg-end {\n align-self: flex-end !important;\n }\n .align-self-lg-center {\n align-self: center !important;\n }\n .align-self-lg-baseline {\n align-self: baseline !important;\n }\n .align-self-lg-stretch {\n align-self: stretch !important;\n }\n .order-lg-first {\n order: -1 !important;\n }\n .order-lg-0 {\n order: 0 !important;\n }\n .order-lg-1 {\n order: 1 !important;\n }\n .order-lg-2 {\n order: 2 !important;\n }\n .order-lg-3 {\n order: 3 !important;\n }\n .order-lg-4 {\n order: 4 !important;\n }\n .order-lg-5 {\n order: 5 !important;\n }\n .order-lg-last {\n order: 6 !important;\n }\n .m-lg-0 {\n margin: 0 !important;\n }\n .m-lg-1 {\n margin: 0.25rem !important;\n }\n .m-lg-2 {\n margin: 0.5rem !important;\n }\n .m-lg-3 {\n margin: 1rem !important;\n }\n .m-lg-4 {\n margin: 1.5rem !important;\n }\n .m-lg-5 {\n margin: 3rem !important;\n }\n .m-lg-auto {\n margin: auto !important;\n }\n .mx-lg-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-lg-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-lg-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-lg-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-lg-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-lg-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-lg-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-lg-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-lg-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-lg-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-lg-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-lg-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-lg-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-lg-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-lg-0 {\n margin-top: 0 !important;\n }\n .mt-lg-1 {\n margin-top: 0.25rem !important;\n }\n .mt-lg-2 {\n margin-top: 0.5rem !important;\n }\n .mt-lg-3 {\n margin-top: 1rem !important;\n }\n .mt-lg-4 {\n margin-top: 1.5rem !important;\n }\n .mt-lg-5 {\n margin-top: 3rem !important;\n }\n .mt-lg-auto {\n margin-top: auto !important;\n }\n .me-lg-0 {\n margin-right: 0 !important;\n }\n .me-lg-1 {\n margin-right: 0.25rem !important;\n }\n .me-lg-2 {\n margin-right: 0.5rem !important;\n }\n .me-lg-3 {\n margin-right: 1rem !important;\n }\n .me-lg-4 {\n margin-right: 1.5rem !important;\n }\n .me-lg-5 {\n margin-right: 3rem !important;\n }\n .me-lg-auto {\n margin-right: auto !important;\n }\n .mb-lg-0 {\n margin-bottom: 0 !important;\n }\n .mb-lg-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-lg-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-lg-3 {\n margin-bottom: 1rem !important;\n }\n .mb-lg-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-lg-5 {\n margin-bottom: 3rem !important;\n }\n .mb-lg-auto {\n margin-bottom: auto !important;\n }\n .ms-lg-0 {\n margin-left: 0 !important;\n }\n .ms-lg-1 {\n margin-left: 0.25rem !important;\n }\n .ms-lg-2 {\n margin-left: 0.5rem !important;\n }\n .ms-lg-3 {\n margin-left: 1rem !important;\n }\n .ms-lg-4 {\n margin-left: 1.5rem !important;\n }\n .ms-lg-5 {\n margin-left: 3rem !important;\n }\n .ms-lg-auto {\n margin-left: auto !important;\n }\n .p-lg-0 {\n padding: 0 !important;\n }\n .p-lg-1 {\n padding: 0.25rem !important;\n }\n .p-lg-2 {\n padding: 0.5rem !important;\n }\n .p-lg-3 {\n padding: 1rem !important;\n }\n .p-lg-4 {\n padding: 1.5rem !important;\n }\n .p-lg-5 {\n padding: 3rem !important;\n }\n .px-lg-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-lg-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-lg-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-lg-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-lg-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-lg-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-lg-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-lg-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-lg-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-lg-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-lg-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-lg-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-lg-0 {\n padding-top: 0 !important;\n }\n .pt-lg-1 {\n padding-top: 0.25rem !important;\n }\n .pt-lg-2 {\n padding-top: 0.5rem !important;\n }\n .pt-lg-3 {\n padding-top: 1rem !important;\n }\n .pt-lg-4 {\n padding-top: 1.5rem !important;\n }\n .pt-lg-5 {\n padding-top: 3rem !important;\n }\n .pe-lg-0 {\n padding-right: 0 !important;\n }\n .pe-lg-1 {\n padding-right: 0.25rem !important;\n }\n .pe-lg-2 {\n padding-right: 0.5rem !important;\n }\n .pe-lg-3 {\n padding-right: 1rem !important;\n }\n .pe-lg-4 {\n padding-right: 1.5rem !important;\n }\n .pe-lg-5 {\n padding-right: 3rem !important;\n }\n .pb-lg-0 {\n padding-bottom: 0 !important;\n }\n .pb-lg-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-lg-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-lg-3 {\n padding-bottom: 1rem !important;\n }\n .pb-lg-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-lg-5 {\n padding-bottom: 3rem !important;\n }\n .ps-lg-0 {\n padding-left: 0 !important;\n }\n .ps-lg-1 {\n padding-left: 0.25rem !important;\n }\n .ps-lg-2 {\n padding-left: 0.5rem !important;\n }\n .ps-lg-3 {\n padding-left: 1rem !important;\n }\n .ps-lg-4 {\n padding-left: 1.5rem !important;\n }\n .ps-lg-5 {\n padding-left: 3rem !important;\n }\n}\n@media (min-width: 1200px) {\n .d-xl-inline {\n display: inline !important;\n }\n .d-xl-inline-block {\n display: inline-block !important;\n }\n .d-xl-block {\n display: block !important;\n }\n .d-xl-grid {\n display: grid !important;\n }\n .d-xl-inline-grid {\n display: inline-grid !important;\n }\n .d-xl-table {\n display: table !important;\n }\n .d-xl-table-row {\n display: table-row !important;\n }\n .d-xl-table-cell {\n display: table-cell !important;\n }\n .d-xl-flex {\n display: flex !important;\n }\n .d-xl-inline-flex {\n display: inline-flex !important;\n }\n .d-xl-none {\n display: none !important;\n }\n .flex-xl-fill {\n flex: 1 1 auto !important;\n }\n .flex-xl-row {\n flex-direction: row !important;\n }\n .flex-xl-column {\n flex-direction: column !important;\n }\n .flex-xl-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-xl-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-xl-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-xl-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-xl-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-xl-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-xl-wrap {\n flex-wrap: wrap !important;\n }\n .flex-xl-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-xl-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-xl-start {\n justify-content: flex-start !important;\n }\n .justify-content-xl-end {\n justify-content: flex-end !important;\n }\n .justify-content-xl-center {\n justify-content: center !important;\n }\n .justify-content-xl-between {\n justify-content: space-between !important;\n }\n .justify-content-xl-around {\n justify-content: space-around !important;\n }\n .justify-content-xl-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-xl-start {\n align-items: flex-start !important;\n }\n .align-items-xl-end {\n align-items: flex-end !important;\n }\n .align-items-xl-center {\n align-items: center !important;\n }\n .align-items-xl-baseline {\n align-items: baseline !important;\n }\n .align-items-xl-stretch {\n align-items: stretch !important;\n }\n .align-content-xl-start {\n align-content: flex-start !important;\n }\n .align-content-xl-end {\n align-content: flex-end !important;\n }\n .align-content-xl-center {\n align-content: center !important;\n }\n .align-content-xl-between {\n align-content: space-between !important;\n }\n .align-content-xl-around {\n align-content: space-around !important;\n }\n .align-content-xl-stretch {\n align-content: stretch !important;\n }\n .align-self-xl-auto {\n align-self: auto !important;\n }\n .align-self-xl-start {\n align-self: flex-start !important;\n }\n .align-self-xl-end {\n align-self: flex-end !important;\n }\n .align-self-xl-center {\n align-self: center !important;\n }\n .align-self-xl-baseline {\n align-self: baseline !important;\n }\n .align-self-xl-stretch {\n align-self: stretch !important;\n }\n .order-xl-first {\n order: -1 !important;\n }\n .order-xl-0 {\n order: 0 !important;\n }\n .order-xl-1 {\n order: 1 !important;\n }\n .order-xl-2 {\n order: 2 !important;\n }\n .order-xl-3 {\n order: 3 !important;\n }\n .order-xl-4 {\n order: 4 !important;\n }\n .order-xl-5 {\n order: 5 !important;\n }\n .order-xl-last {\n order: 6 !important;\n }\n .m-xl-0 {\n margin: 0 !important;\n }\n .m-xl-1 {\n margin: 0.25rem !important;\n }\n .m-xl-2 {\n margin: 0.5rem !important;\n }\n .m-xl-3 {\n margin: 1rem !important;\n }\n .m-xl-4 {\n margin: 1.5rem !important;\n }\n .m-xl-5 {\n margin: 3rem !important;\n }\n .m-xl-auto {\n margin: auto !important;\n }\n .mx-xl-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-xl-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-xl-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-xl-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-xl-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-xl-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-xl-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-xl-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-xl-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-xl-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-xl-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-xl-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-xl-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-xl-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-xl-0 {\n margin-top: 0 !important;\n }\n .mt-xl-1 {\n margin-top: 0.25rem !important;\n }\n .mt-xl-2 {\n margin-top: 0.5rem !important;\n }\n .mt-xl-3 {\n margin-top: 1rem !important;\n }\n .mt-xl-4 {\n margin-top: 1.5rem !important;\n }\n .mt-xl-5 {\n margin-top: 3rem !important;\n }\n .mt-xl-auto {\n margin-top: auto !important;\n }\n .me-xl-0 {\n margin-right: 0 !important;\n }\n .me-xl-1 {\n margin-right: 0.25rem !important;\n }\n .me-xl-2 {\n margin-right: 0.5rem !important;\n }\n .me-xl-3 {\n margin-right: 1rem !important;\n }\n .me-xl-4 {\n margin-right: 1.5rem !important;\n }\n .me-xl-5 {\n margin-right: 3rem !important;\n }\n .me-xl-auto {\n margin-right: auto !important;\n }\n .mb-xl-0 {\n margin-bottom: 0 !important;\n }\n .mb-xl-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-xl-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-xl-3 {\n margin-bottom: 1rem !important;\n }\n .mb-xl-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-xl-5 {\n margin-bottom: 3rem !important;\n }\n .mb-xl-auto {\n margin-bottom: auto !important;\n }\n .ms-xl-0 {\n margin-left: 0 !important;\n }\n .ms-xl-1 {\n margin-left: 0.25rem !important;\n }\n .ms-xl-2 {\n margin-left: 0.5rem !important;\n }\n .ms-xl-3 {\n margin-left: 1rem !important;\n }\n .ms-xl-4 {\n margin-left: 1.5rem !important;\n }\n .ms-xl-5 {\n margin-left: 3rem !important;\n }\n .ms-xl-auto {\n margin-left: auto !important;\n }\n .p-xl-0 {\n padding: 0 !important;\n }\n .p-xl-1 {\n padding: 0.25rem !important;\n }\n .p-xl-2 {\n padding: 0.5rem !important;\n }\n .p-xl-3 {\n padding: 1rem !important;\n }\n .p-xl-4 {\n padding: 1.5rem !important;\n }\n .p-xl-5 {\n padding: 3rem !important;\n }\n .px-xl-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-xl-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-xl-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-xl-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-xl-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-xl-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-xl-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-xl-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-xl-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-xl-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-xl-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-xl-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-xl-0 {\n padding-top: 0 !important;\n }\n .pt-xl-1 {\n padding-top: 0.25rem !important;\n }\n .pt-xl-2 {\n padding-top: 0.5rem !important;\n }\n .pt-xl-3 {\n padding-top: 1rem !important;\n }\n .pt-xl-4 {\n padding-top: 1.5rem !important;\n }\n .pt-xl-5 {\n padding-top: 3rem !important;\n }\n .pe-xl-0 {\n padding-right: 0 !important;\n }\n .pe-xl-1 {\n padding-right: 0.25rem !important;\n }\n .pe-xl-2 {\n padding-right: 0.5rem !important;\n }\n .pe-xl-3 {\n padding-right: 1rem !important;\n }\n .pe-xl-4 {\n padding-right: 1.5rem !important;\n }\n .pe-xl-5 {\n padding-right: 3rem !important;\n }\n .pb-xl-0 {\n padding-bottom: 0 !important;\n }\n .pb-xl-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-xl-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-xl-3 {\n padding-bottom: 1rem !important;\n }\n .pb-xl-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-xl-5 {\n padding-bottom: 3rem !important;\n }\n .ps-xl-0 {\n padding-left: 0 !important;\n }\n .ps-xl-1 {\n padding-left: 0.25rem !important;\n }\n .ps-xl-2 {\n padding-left: 0.5rem !important;\n }\n .ps-xl-3 {\n padding-left: 1rem !important;\n }\n .ps-xl-4 {\n padding-left: 1.5rem !important;\n }\n .ps-xl-5 {\n padding-left: 3rem !important;\n }\n}\n@media (min-width: 1400px) {\n .d-xxl-inline {\n display: inline !important;\n }\n .d-xxl-inline-block {\n display: inline-block !important;\n }\n .d-xxl-block {\n display: block !important;\n }\n .d-xxl-grid {\n display: grid !important;\n }\n .d-xxl-inline-grid {\n display: inline-grid !important;\n }\n .d-xxl-table {\n display: table !important;\n }\n .d-xxl-table-row {\n display: table-row !important;\n }\n .d-xxl-table-cell {\n display: table-cell !important;\n }\n .d-xxl-flex {\n display: flex !important;\n }\n .d-xxl-inline-flex {\n display: inline-flex !important;\n }\n .d-xxl-none {\n display: none !important;\n }\n .flex-xxl-fill {\n flex: 1 1 auto !important;\n }\n .flex-xxl-row {\n flex-direction: row !important;\n }\n .flex-xxl-column {\n flex-direction: column !important;\n }\n .flex-xxl-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-xxl-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-xxl-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-xxl-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-xxl-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-xxl-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-xxl-wrap {\n flex-wrap: wrap !important;\n }\n .flex-xxl-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-xxl-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-xxl-start {\n justify-content: flex-start !important;\n }\n .justify-content-xxl-end {\n justify-content: flex-end !important;\n }\n .justify-content-xxl-center {\n justify-content: center !important;\n }\n .justify-content-xxl-between {\n justify-content: space-between !important;\n }\n .justify-content-xxl-around {\n justify-content: space-around !important;\n }\n .justify-content-xxl-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-xxl-start {\n align-items: flex-start !important;\n }\n .align-items-xxl-end {\n align-items: flex-end !important;\n }\n .align-items-xxl-center {\n align-items: center !important;\n }\n .align-items-xxl-baseline {\n align-items: baseline !important;\n }\n .align-items-xxl-stretch {\n align-items: stretch !important;\n }\n .align-content-xxl-start {\n align-content: flex-start !important;\n }\n .align-content-xxl-end {\n align-content: flex-end !important;\n }\n .align-content-xxl-center {\n align-content: center !important;\n }\n .align-content-xxl-between {\n align-content: space-between !important;\n }\n .align-content-xxl-around {\n align-content: space-around !important;\n }\n .align-content-xxl-stretch {\n align-content: stretch !important;\n }\n .align-self-xxl-auto {\n align-self: auto !important;\n }\n .align-self-xxl-start {\n align-self: flex-start !important;\n }\n .align-self-xxl-end {\n align-self: flex-end !important;\n }\n .align-self-xxl-center {\n align-self: center !important;\n }\n .align-self-xxl-baseline {\n align-self: baseline !important;\n }\n .align-self-xxl-stretch {\n align-self: stretch !important;\n }\n .order-xxl-first {\n order: -1 !important;\n }\n .order-xxl-0 {\n order: 0 !important;\n }\n .order-xxl-1 {\n order: 1 !important;\n }\n .order-xxl-2 {\n order: 2 !important;\n }\n .order-xxl-3 {\n order: 3 !important;\n }\n .order-xxl-4 {\n order: 4 !important;\n }\n .order-xxl-5 {\n order: 5 !important;\n }\n .order-xxl-last {\n order: 6 !important;\n }\n .m-xxl-0 {\n margin: 0 !important;\n }\n .m-xxl-1 {\n margin: 0.25rem !important;\n }\n .m-xxl-2 {\n margin: 0.5rem !important;\n }\n .m-xxl-3 {\n margin: 1rem !important;\n }\n .m-xxl-4 {\n margin: 1.5rem !important;\n }\n .m-xxl-5 {\n margin: 3rem !important;\n }\n .m-xxl-auto {\n margin: auto !important;\n }\n .mx-xxl-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-xxl-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-xxl-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-xxl-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-xxl-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-xxl-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-xxl-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-xxl-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-xxl-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-xxl-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-xxl-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-xxl-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-xxl-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-xxl-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-xxl-0 {\n margin-top: 0 !important;\n }\n .mt-xxl-1 {\n margin-top: 0.25rem !important;\n }\n .mt-xxl-2 {\n margin-top: 0.5rem !important;\n }\n .mt-xxl-3 {\n margin-top: 1rem !important;\n }\n .mt-xxl-4 {\n margin-top: 1.5rem !important;\n }\n .mt-xxl-5 {\n margin-top: 3rem !important;\n }\n .mt-xxl-auto {\n margin-top: auto !important;\n }\n .me-xxl-0 {\n margin-right: 0 !important;\n }\n .me-xxl-1 {\n margin-right: 0.25rem !important;\n }\n .me-xxl-2 {\n margin-right: 0.5rem !important;\n }\n .me-xxl-3 {\n margin-right: 1rem !important;\n }\n .me-xxl-4 {\n margin-right: 1.5rem !important;\n }\n .me-xxl-5 {\n margin-right: 3rem !important;\n }\n .me-xxl-auto {\n margin-right: auto !important;\n }\n .mb-xxl-0 {\n margin-bottom: 0 !important;\n }\n .mb-xxl-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-xxl-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-xxl-3 {\n margin-bottom: 1rem !important;\n }\n .mb-xxl-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-xxl-5 {\n margin-bottom: 3rem !important;\n }\n .mb-xxl-auto {\n margin-bottom: auto !important;\n }\n .ms-xxl-0 {\n margin-left: 0 !important;\n }\n .ms-xxl-1 {\n margin-left: 0.25rem !important;\n }\n .ms-xxl-2 {\n margin-left: 0.5rem !important;\n }\n .ms-xxl-3 {\n margin-left: 1rem !important;\n }\n .ms-xxl-4 {\n margin-left: 1.5rem !important;\n }\n .ms-xxl-5 {\n margin-left: 3rem !important;\n }\n .ms-xxl-auto {\n margin-left: auto !important;\n }\n .p-xxl-0 {\n padding: 0 !important;\n }\n .p-xxl-1 {\n padding: 0.25rem !important;\n }\n .p-xxl-2 {\n padding: 0.5rem !important;\n }\n .p-xxl-3 {\n padding: 1rem !important;\n }\n .p-xxl-4 {\n padding: 1.5rem !important;\n }\n .p-xxl-5 {\n padding: 3rem !important;\n }\n .px-xxl-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-xxl-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-xxl-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-xxl-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-xxl-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-xxl-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-xxl-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-xxl-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-xxl-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-xxl-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-xxl-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-xxl-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-xxl-0 {\n padding-top: 0 !important;\n }\n .pt-xxl-1 {\n padding-top: 0.25rem !important;\n }\n .pt-xxl-2 {\n padding-top: 0.5rem !important;\n }\n .pt-xxl-3 {\n padding-top: 1rem !important;\n }\n .pt-xxl-4 {\n padding-top: 1.5rem !important;\n }\n .pt-xxl-5 {\n padding-top: 3rem !important;\n }\n .pe-xxl-0 {\n padding-right: 0 !important;\n }\n .pe-xxl-1 {\n padding-right: 0.25rem !important;\n }\n .pe-xxl-2 {\n padding-right: 0.5rem !important;\n }\n .pe-xxl-3 {\n padding-right: 1rem !important;\n }\n .pe-xxl-4 {\n padding-right: 1.5rem !important;\n }\n .pe-xxl-5 {\n padding-right: 3rem !important;\n }\n .pb-xxl-0 {\n padding-bottom: 0 !important;\n }\n .pb-xxl-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-xxl-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-xxl-3 {\n padding-bottom: 1rem !important;\n }\n .pb-xxl-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-xxl-5 {\n padding-bottom: 3rem !important;\n }\n .ps-xxl-0 {\n padding-left: 0 !important;\n }\n .ps-xxl-1 {\n padding-left: 0.25rem !important;\n }\n .ps-xxl-2 {\n padding-left: 0.5rem !important;\n }\n .ps-xxl-3 {\n padding-left: 1rem !important;\n }\n .ps-xxl-4 {\n padding-left: 1.5rem !important;\n }\n .ps-xxl-5 {\n padding-left: 3rem !important;\n }\n}\n@media print {\n .d-print-inline {\n display: inline !important;\n }\n .d-print-inline-block {\n display: inline-block !important;\n }\n .d-print-block {\n display: block !important;\n }\n .d-print-grid {\n display: grid !important;\n }\n .d-print-inline-grid {\n display: inline-grid !important;\n }\n .d-print-table {\n display: table !important;\n }\n .d-print-table-row {\n display: table-row !important;\n }\n .d-print-table-cell {\n display: table-cell !important;\n }\n .d-print-flex {\n display: flex !important;\n }\n .d-print-inline-flex {\n display: inline-flex !important;\n }\n .d-print-none {\n display: none !important;\n }\n}\n\n/*# sourceMappingURL=bootstrap-grid.css.map */\n","// Breakpoint viewport sizes and media queries.\n//\n// Breakpoints are defined as a map of (name: minimum width), order from small to large:\n//\n// (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)\n//\n// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default.\n\n// Name of the next breakpoint, or null for the last breakpoint.\n//\n// >> breakpoint-next(sm)\n// md\n// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// md\n// >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl xxl))\n// md\n@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) {\n $n: index($breakpoint-names, $name);\n @if not $n {\n @error \"breakpoint `#{$name}` not found in `#{$breakpoints}`\";\n }\n @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null);\n}\n\n// Minimum breakpoint width. Null for the smallest (first) breakpoint.\n//\n// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// 576px\n@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {\n $min: map-get($breakpoints, $name);\n @return if($min != 0, $min, null);\n}\n\n// Maximum breakpoint width.\n// The maximum value is reduced by 0.02px to work around the limitations of\n// `min-` and `max-` prefixes and viewports with fractional widths.\n// See https://www.w3.org/TR/mediaqueries-4/#mq-min-max\n// Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari.\n// See https://bugs.webkit.org/show_bug.cgi?id=178261\n//\n// >> breakpoint-max(md, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// 767.98px\n@function breakpoint-max($name, $breakpoints: $grid-breakpoints) {\n $max: map-get($breakpoints, $name);\n @return if($max and $max > 0, $max - .02, null);\n}\n\n// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front.\n// Useful for making responsive utilities.\n//\n// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// \"\" (Returns a blank string)\n// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// \"-sm\"\n@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) {\n @return if(breakpoint-min($name, $breakpoints) == null, \"\", \"-#{$name}\");\n}\n\n// Media of at least the minimum breakpoint width. No query for the smallest breakpoint.\n// Makes the @content apply to the given breakpoint and wider.\n@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($name, $breakpoints);\n @if $min {\n @media (min-width: $min) {\n @content;\n }\n } @else {\n @content;\n }\n}\n\n// Media of at most the maximum breakpoint width. No query for the largest breakpoint.\n// Makes the @content apply to the given breakpoint and narrower.\n@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) {\n $max: breakpoint-max($name, $breakpoints);\n @if $max {\n @media (max-width: $max) {\n @content;\n }\n } @else {\n @content;\n }\n}\n\n// Media that spans multiple breakpoint widths.\n// Makes the @content apply between the min and max breakpoints\n@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($lower, $breakpoints);\n $max: breakpoint-max($upper, $breakpoints);\n\n @if $min != null and $max != null {\n @media (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else if $max == null {\n @include media-breakpoint-up($lower, $breakpoints) {\n @content;\n }\n } @else if $min == null {\n @include media-breakpoint-down($upper, $breakpoints) {\n @content;\n }\n }\n}\n\n// Media between the breakpoint's minimum and maximum widths.\n// No minimum for the smallest breakpoint, and no maximum for the largest one.\n// Makes the @content apply only to the given breakpoint, not viewports any wider or narrower.\n@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($name, $breakpoints);\n $next: breakpoint-next($name, $breakpoints);\n $max: breakpoint-max($next, $breakpoints);\n\n @if $min != null and $max != null {\n @media (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else if $max == null {\n @include media-breakpoint-up($name, $breakpoints) {\n @content;\n }\n } @else if $min == null {\n @include media-breakpoint-down($next, $breakpoints) {\n @content;\n }\n }\n}\n","// Variables\n//\n// Variables should follow the `$component-state-property-size` formula for\n// consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs.\n\n// Color system\n\n// scss-docs-start gray-color-variables\n$white: #fff !default;\n$gray-100: #f8f9fa !default;\n$gray-200: #e9ecef !default;\n$gray-300: #dee2e6 !default;\n$gray-400: #ced4da !default;\n$gray-500: #adb5bd !default;\n$gray-600: #6c757d !default;\n$gray-700: #495057 !default;\n$gray-800: #343a40 !default;\n$gray-900: #212529 !default;\n$black: #000 !default;\n// scss-docs-end gray-color-variables\n\n// fusv-disable\n// scss-docs-start gray-colors-map\n$grays: (\n \"100\": $gray-100,\n \"200\": $gray-200,\n \"300\": $gray-300,\n \"400\": $gray-400,\n \"500\": $gray-500,\n \"600\": $gray-600,\n \"700\": $gray-700,\n \"800\": $gray-800,\n \"900\": $gray-900\n) !default;\n// scss-docs-end gray-colors-map\n// fusv-enable\n\n// scss-docs-start color-variables\n$blue: #0d6efd !default;\n$indigo: #6610f2 !default;\n$purple: #6f42c1 !default;\n$pink: #d63384 !default;\n$red: #dc3545 !default;\n$orange: #fd7e14 !default;\n$yellow: #ffc107 !default;\n$green: #198754 !default;\n$teal: #20c997 !default;\n$cyan: #0dcaf0 !default;\n// scss-docs-end color-variables\n\n// scss-docs-start colors-map\n$colors: (\n \"blue\": $blue,\n \"indigo\": $indigo,\n \"purple\": $purple,\n \"pink\": $pink,\n \"red\": $red,\n \"orange\": $orange,\n \"yellow\": $yellow,\n \"green\": $green,\n \"teal\": $teal,\n \"cyan\": $cyan,\n \"black\": $black,\n \"white\": $white,\n \"gray\": $gray-600,\n \"gray-dark\": $gray-800\n) !default;\n// scss-docs-end colors-map\n\n// The contrast ratio to reach against white, to determine if color changes from \"light\" to \"dark\". Acceptable values for WCAG 2.0 are 3, 4.5 and 7.\n// See https://www.w3.org/TR/WCAG20/#visual-audio-contrast-contrast\n$min-contrast-ratio: 4.5 !default;\n\n// Customize the light and dark text colors for use in our color contrast function.\n$color-contrast-dark: $black !default;\n$color-contrast-light: $white !default;\n\n// fusv-disable\n$blue-100: tint-color($blue, 80%) !default;\n$blue-200: tint-color($blue, 60%) !default;\n$blue-300: tint-color($blue, 40%) !default;\n$blue-400: tint-color($blue, 20%) !default;\n$blue-500: $blue !default;\n$blue-600: shade-color($blue, 20%) !default;\n$blue-700: shade-color($blue, 40%) !default;\n$blue-800: shade-color($blue, 60%) !default;\n$blue-900: shade-color($blue, 80%) !default;\n\n$indigo-100: tint-color($indigo, 80%) !default;\n$indigo-200: tint-color($indigo, 60%) !default;\n$indigo-300: tint-color($indigo, 40%) !default;\n$indigo-400: tint-color($indigo, 20%) !default;\n$indigo-500: $indigo !default;\n$indigo-600: shade-color($indigo, 20%) !default;\n$indigo-700: shade-color($indigo, 40%) !default;\n$indigo-800: shade-color($indigo, 60%) !default;\n$indigo-900: shade-color($indigo, 80%) !default;\n\n$purple-100: tint-color($purple, 80%) !default;\n$purple-200: tint-color($purple, 60%) !default;\n$purple-300: tint-color($purple, 40%) !default;\n$purple-400: tint-color($purple, 20%) !default;\n$purple-500: $purple !default;\n$purple-600: shade-color($purple, 20%) !default;\n$purple-700: shade-color($purple, 40%) !default;\n$purple-800: shade-color($purple, 60%) !default;\n$purple-900: shade-color($purple, 80%) !default;\n\n$pink-100: tint-color($pink, 80%) !default;\n$pink-200: tint-color($pink, 60%) !default;\n$pink-300: tint-color($pink, 40%) !default;\n$pink-400: tint-color($pink, 20%) !default;\n$pink-500: $pink !default;\n$pink-600: shade-color($pink, 20%) !default;\n$pink-700: shade-color($pink, 40%) !default;\n$pink-800: shade-color($pink, 60%) !default;\n$pink-900: shade-color($pink, 80%) !default;\n\n$red-100: tint-color($red, 80%) !default;\n$red-200: tint-color($red, 60%) !default;\n$red-300: tint-color($red, 40%) !default;\n$red-400: tint-color($red, 20%) !default;\n$red-500: $red !default;\n$red-600: shade-color($red, 20%) !default;\n$red-700: shade-color($red, 40%) !default;\n$red-800: shade-color($red, 60%) !default;\n$red-900: shade-color($red, 80%) !default;\n\n$orange-100: tint-color($orange, 80%) !default;\n$orange-200: tint-color($orange, 60%) !default;\n$orange-300: tint-color($orange, 40%) !default;\n$orange-400: tint-color($orange, 20%) !default;\n$orange-500: $orange !default;\n$orange-600: shade-color($orange, 20%) !default;\n$orange-700: shade-color($orange, 40%) !default;\n$orange-800: shade-color($orange, 60%) !default;\n$orange-900: shade-color($orange, 80%) !default;\n\n$yellow-100: tint-color($yellow, 80%) !default;\n$yellow-200: tint-color($yellow, 60%) !default;\n$yellow-300: tint-color($yellow, 40%) !default;\n$yellow-400: tint-color($yellow, 20%) !default;\n$yellow-500: $yellow !default;\n$yellow-600: shade-color($yellow, 20%) !default;\n$yellow-700: shade-color($yellow, 40%) !default;\n$yellow-800: shade-color($yellow, 60%) !default;\n$yellow-900: shade-color($yellow, 80%) !default;\n\n$green-100: tint-color($green, 80%) !default;\n$green-200: tint-color($green, 60%) !default;\n$green-300: tint-color($green, 40%) !default;\n$green-400: tint-color($green, 20%) !default;\n$green-500: $green !default;\n$green-600: shade-color($green, 20%) !default;\n$green-700: shade-color($green, 40%) !default;\n$green-800: shade-color($green, 60%) !default;\n$green-900: shade-color($green, 80%) !default;\n\n$teal-100: tint-color($teal, 80%) !default;\n$teal-200: tint-color($teal, 60%) !default;\n$teal-300: tint-color($teal, 40%) !default;\n$teal-400: tint-color($teal, 20%) !default;\n$teal-500: $teal !default;\n$teal-600: shade-color($teal, 20%) !default;\n$teal-700: shade-color($teal, 40%) !default;\n$teal-800: shade-color($teal, 60%) !default;\n$teal-900: shade-color($teal, 80%) !default;\n\n$cyan-100: tint-color($cyan, 80%) !default;\n$cyan-200: tint-color($cyan, 60%) !default;\n$cyan-300: tint-color($cyan, 40%) !default;\n$cyan-400: tint-color($cyan, 20%) !default;\n$cyan-500: $cyan !default;\n$cyan-600: shade-color($cyan, 20%) !default;\n$cyan-700: shade-color($cyan, 40%) !default;\n$cyan-800: shade-color($cyan, 60%) !default;\n$cyan-900: shade-color($cyan, 80%) !default;\n\n$blues: (\n \"blue-100\": $blue-100,\n \"blue-200\": $blue-200,\n \"blue-300\": $blue-300,\n \"blue-400\": $blue-400,\n \"blue-500\": $blue-500,\n \"blue-600\": $blue-600,\n \"blue-700\": $blue-700,\n \"blue-800\": $blue-800,\n \"blue-900\": $blue-900\n) !default;\n\n$indigos: (\n \"indigo-100\": $indigo-100,\n \"indigo-200\": $indigo-200,\n \"indigo-300\": $indigo-300,\n \"indigo-400\": $indigo-400,\n \"indigo-500\": $indigo-500,\n \"indigo-600\": $indigo-600,\n \"indigo-700\": $indigo-700,\n \"indigo-800\": $indigo-800,\n \"indigo-900\": $indigo-900\n) !default;\n\n$purples: (\n \"purple-100\": $purple-100,\n \"purple-200\": $purple-200,\n \"purple-300\": $purple-300,\n \"purple-400\": $purple-400,\n \"purple-500\": $purple-500,\n \"purple-600\": $purple-600,\n \"purple-700\": $purple-700,\n \"purple-800\": $purple-800,\n \"purple-900\": $purple-900\n) !default;\n\n$pinks: (\n \"pink-100\": $pink-100,\n \"pink-200\": $pink-200,\n \"pink-300\": $pink-300,\n \"pink-400\": $pink-400,\n \"pink-500\": $pink-500,\n \"pink-600\": $pink-600,\n \"pink-700\": $pink-700,\n \"pink-800\": $pink-800,\n \"pink-900\": $pink-900\n) !default;\n\n$reds: (\n \"red-100\": $red-100,\n \"red-200\": $red-200,\n \"red-300\": $red-300,\n \"red-400\": $red-400,\n \"red-500\": $red-500,\n \"red-600\": $red-600,\n \"red-700\": $red-700,\n \"red-800\": $red-800,\n \"red-900\": $red-900\n) !default;\n\n$oranges: (\n \"orange-100\": $orange-100,\n \"orange-200\": $orange-200,\n \"orange-300\": $orange-300,\n \"orange-400\": $orange-400,\n \"orange-500\": $orange-500,\n \"orange-600\": $orange-600,\n \"orange-700\": $orange-700,\n \"orange-800\": $orange-800,\n \"orange-900\": $orange-900\n) !default;\n\n$yellows: (\n \"yellow-100\": $yellow-100,\n \"yellow-200\": $yellow-200,\n \"yellow-300\": $yellow-300,\n \"yellow-400\": $yellow-400,\n \"yellow-500\": $yellow-500,\n \"yellow-600\": $yellow-600,\n \"yellow-700\": $yellow-700,\n \"yellow-800\": $yellow-800,\n \"yellow-900\": $yellow-900\n) !default;\n\n$greens: (\n \"green-100\": $green-100,\n \"green-200\": $green-200,\n \"green-300\": $green-300,\n \"green-400\": $green-400,\n \"green-500\": $green-500,\n \"green-600\": $green-600,\n \"green-700\": $green-700,\n \"green-800\": $green-800,\n \"green-900\": $green-900\n) !default;\n\n$teals: (\n \"teal-100\": $teal-100,\n \"teal-200\": $teal-200,\n \"teal-300\": $teal-300,\n \"teal-400\": $teal-400,\n \"teal-500\": $teal-500,\n \"teal-600\": $teal-600,\n \"teal-700\": $teal-700,\n \"teal-800\": $teal-800,\n \"teal-900\": $teal-900\n) !default;\n\n$cyans: (\n \"cyan-100\": $cyan-100,\n \"cyan-200\": $cyan-200,\n \"cyan-300\": $cyan-300,\n \"cyan-400\": $cyan-400,\n \"cyan-500\": $cyan-500,\n \"cyan-600\": $cyan-600,\n \"cyan-700\": $cyan-700,\n \"cyan-800\": $cyan-800,\n \"cyan-900\": $cyan-900\n) !default;\n// fusv-enable\n\n// scss-docs-start theme-color-variables\n$primary: $blue !default;\n$secondary: $gray-600 !default;\n$success: $green !default;\n$info: $cyan !default;\n$warning: $yellow !default;\n$danger: $red !default;\n$light: $gray-100 !default;\n$dark: $gray-900 !default;\n// scss-docs-end theme-color-variables\n\n// scss-docs-start theme-colors-map\n$theme-colors: (\n \"primary\": $primary,\n \"secondary\": $secondary,\n \"success\": $success,\n \"info\": $info,\n \"warning\": $warning,\n \"danger\": $danger,\n \"light\": $light,\n \"dark\": $dark\n) !default;\n// scss-docs-end theme-colors-map\n\n// scss-docs-start theme-text-variables\n$primary-text-emphasis: shade-color($primary, 60%) !default;\n$secondary-text-emphasis: shade-color($secondary, 60%) !default;\n$success-text-emphasis: shade-color($success, 60%) !default;\n$info-text-emphasis: shade-color($info, 60%) !default;\n$warning-text-emphasis: shade-color($warning, 60%) !default;\n$danger-text-emphasis: shade-color($danger, 60%) !default;\n$light-text-emphasis: $gray-700 !default;\n$dark-text-emphasis: $gray-700 !default;\n// scss-docs-end theme-text-variables\n\n// scss-docs-start theme-bg-subtle-variables\n$primary-bg-subtle: tint-color($primary, 80%) !default;\n$secondary-bg-subtle: tint-color($secondary, 80%) !default;\n$success-bg-subtle: tint-color($success, 80%) !default;\n$info-bg-subtle: tint-color($info, 80%) !default;\n$warning-bg-subtle: tint-color($warning, 80%) !default;\n$danger-bg-subtle: tint-color($danger, 80%) !default;\n$light-bg-subtle: mix($gray-100, $white) !default;\n$dark-bg-subtle: $gray-400 !default;\n// scss-docs-end theme-bg-subtle-variables\n\n// scss-docs-start theme-border-subtle-variables\n$primary-border-subtle: tint-color($primary, 60%) !default;\n$secondary-border-subtle: tint-color($secondary, 60%) !default;\n$success-border-subtle: tint-color($success, 60%) !default;\n$info-border-subtle: tint-color($info, 60%) !default;\n$warning-border-subtle: tint-color($warning, 60%) !default;\n$danger-border-subtle: tint-color($danger, 60%) !default;\n$light-border-subtle: $gray-200 !default;\n$dark-border-subtle: $gray-500 !default;\n// scss-docs-end theme-border-subtle-variables\n\n// Characters which are escaped by the escape-svg function\n$escaped-characters: (\n (\"<\", \"%3c\"),\n (\">\", \"%3e\"),\n (\"#\", \"%23\"),\n (\"(\", \"%28\"),\n (\")\", \"%29\"),\n) !default;\n\n// Options\n//\n// Quickly modify global styling by enabling or disabling optional features.\n\n$enable-caret: true !default;\n$enable-rounded: true !default;\n$enable-shadows: false !default;\n$enable-gradients: false !default;\n$enable-transitions: true !default;\n$enable-reduced-motion: true !default;\n$enable-smooth-scroll: true !default;\n$enable-grid-classes: true !default;\n$enable-container-classes: true !default;\n$enable-cssgrid: false !default;\n$enable-button-pointers: true !default;\n$enable-rfs: true !default;\n$enable-validation-icons: true !default;\n$enable-negative-margins: false !default;\n$enable-deprecation-messages: true !default;\n$enable-important-utilities: true !default;\n\n$enable-dark-mode: true !default;\n$color-mode-type: data !default; // `data` or `media-query`\n\n// Prefix for :root CSS variables\n\n$variable-prefix: bs- !default; // Deprecated in v5.2.0 for the shorter `$prefix`\n$prefix: $variable-prefix !default;\n\n// Gradient\n//\n// The gradient which is added to components if `$enable-gradients` is `true`\n// This gradient is also added to elements with `.bg-gradient`\n// scss-docs-start variable-gradient\n$gradient: linear-gradient(180deg, rgba($white, .15), rgba($white, 0)) !default;\n// scss-docs-end variable-gradient\n\n// Spacing\n//\n// Control the default styling of most Bootstrap elements by modifying these\n// variables. Mostly focused on spacing.\n// You can add more entries to the $spacers map, should you need more variation.\n\n// scss-docs-start spacer-variables-maps\n$spacer: 1rem !default;\n$spacers: (\n 0: 0,\n 1: $spacer * .25,\n 2: $spacer * .5,\n 3: $spacer,\n 4: $spacer * 1.5,\n 5: $spacer * 3,\n) !default;\n// scss-docs-end spacer-variables-maps\n\n// Position\n//\n// Define the edge positioning anchors of the position utilities.\n\n// scss-docs-start position-map\n$position-values: (\n 0: 0,\n 50: 50%,\n 100: 100%\n) !default;\n// scss-docs-end position-map\n\n// Body\n//\n// Settings for the `` element.\n\n$body-text-align: null !default;\n$body-color: $gray-900 !default;\n$body-bg: $white !default;\n\n$body-secondary-color: rgba($body-color, .75) !default;\n$body-secondary-bg: $gray-200 !default;\n\n$body-tertiary-color: rgba($body-color, .5) !default;\n$body-tertiary-bg: $gray-100 !default;\n\n$body-emphasis-color: $black !default;\n\n// Links\n//\n// Style anchor elements.\n\n$link-color: $primary !default;\n$link-decoration: underline !default;\n$link-shade-percentage: 20% !default;\n$link-hover-color: shift-color($link-color, $link-shade-percentage) !default;\n$link-hover-decoration: null !default;\n\n$stretched-link-pseudo-element: after !default;\n$stretched-link-z-index: 1 !default;\n\n// Icon links\n// scss-docs-start icon-link-variables\n$icon-link-gap: .375rem !default;\n$icon-link-underline-offset: .25em !default;\n$icon-link-icon-size: 1em !default;\n$icon-link-icon-transition: .2s ease-in-out transform !default;\n$icon-link-icon-transform: translate3d(.25em, 0, 0) !default;\n// scss-docs-end icon-link-variables\n\n// Paragraphs\n//\n// Style p element.\n\n$paragraph-margin-bottom: 1rem !default;\n\n\n// Grid breakpoints\n//\n// Define the minimum dimensions at which your layout will change,\n// adapting to different screen sizes, for use in media queries.\n\n// scss-docs-start grid-breakpoints\n$grid-breakpoints: (\n xs: 0,\n sm: 576px,\n md: 768px,\n lg: 992px,\n xl: 1200px,\n xxl: 1400px\n) !default;\n// scss-docs-end grid-breakpoints\n\n@include _assert-ascending($grid-breakpoints, \"$grid-breakpoints\");\n@include _assert-starts-at-zero($grid-breakpoints, \"$grid-breakpoints\");\n\n\n// Grid containers\n//\n// Define the maximum width of `.container` for different screen sizes.\n\n// scss-docs-start container-max-widths\n$container-max-widths: (\n sm: 540px,\n md: 720px,\n lg: 960px,\n xl: 1140px,\n xxl: 1320px\n) !default;\n// scss-docs-end container-max-widths\n\n@include _assert-ascending($container-max-widths, \"$container-max-widths\");\n\n\n// Grid columns\n//\n// Set the number of columns and specify the width of the gutters.\n\n$grid-columns: 12 !default;\n$grid-gutter-width: 1.5rem !default;\n$grid-row-columns: 6 !default;\n\n// Container padding\n\n$container-padding-x: $grid-gutter-width !default;\n\n\n// Components\n//\n// Define common padding and border radius sizes and more.\n\n// scss-docs-start border-variables\n$border-width: 1px !default;\n$border-widths: (\n 1: 1px,\n 2: 2px,\n 3: 3px,\n 4: 4px,\n 5: 5px\n) !default;\n$border-style: solid !default;\n$border-color: $gray-300 !default;\n$border-color-translucent: rgba($black, .175) !default;\n// scss-docs-end border-variables\n\n// scss-docs-start border-radius-variables\n$border-radius: .375rem !default;\n$border-radius-sm: .25rem !default;\n$border-radius-lg: .5rem !default;\n$border-radius-xl: 1rem !default;\n$border-radius-xxl: 2rem !default;\n$border-radius-pill: 50rem !default;\n// scss-docs-end border-radius-variables\n// fusv-disable\n$border-radius-2xl: $border-radius-xxl !default; // Deprecated in v5.3.0\n// fusv-enable\n\n// scss-docs-start box-shadow-variables\n$box-shadow: 0 .5rem 1rem rgba($black, .15) !default;\n$box-shadow-sm: 0 .125rem .25rem rgba($black, .075) !default;\n$box-shadow-lg: 0 1rem 3rem rgba($black, .175) !default;\n$box-shadow-inset: inset 0 1px 2px rgba($black, .075) !default;\n// scss-docs-end box-shadow-variables\n\n$component-active-color: $white !default;\n$component-active-bg: $primary !default;\n\n// scss-docs-start focus-ring-variables\n$focus-ring-width: .25rem !default;\n$focus-ring-opacity: .25 !default;\n$focus-ring-color: rgba($primary, $focus-ring-opacity) !default;\n$focus-ring-blur: 0 !default;\n$focus-ring-box-shadow: 0 0 $focus-ring-blur $focus-ring-width $focus-ring-color !default;\n// scss-docs-end focus-ring-variables\n\n// scss-docs-start caret-variables\n$caret-width: .3em !default;\n$caret-vertical-align: $caret-width * .85 !default;\n$caret-spacing: $caret-width * .85 !default;\n// scss-docs-end caret-variables\n\n$transition-base: all .2s ease-in-out !default;\n$transition-fade: opacity .15s linear !default;\n// scss-docs-start collapse-transition\n$transition-collapse: height .35s ease !default;\n$transition-collapse-width: width .35s ease !default;\n// scss-docs-end collapse-transition\n\n// stylelint-disable function-disallowed-list\n// scss-docs-start aspect-ratios\n$aspect-ratios: (\n \"1x1\": 100%,\n \"4x3\": calc(3 / 4 * 100%),\n \"16x9\": calc(9 / 16 * 100%),\n \"21x9\": calc(9 / 21 * 100%)\n) !default;\n// scss-docs-end aspect-ratios\n// stylelint-enable function-disallowed-list\n\n// Typography\n//\n// Font, line-height, and color for body text, headings, and more.\n\n// scss-docs-start font-variables\n// stylelint-disable value-keyword-case\n$font-family-sans-serif: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", \"Liberation Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\" !default;\n$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace !default;\n// stylelint-enable value-keyword-case\n$font-family-base: var(--#{$prefix}font-sans-serif) !default;\n$font-family-code: var(--#{$prefix}font-monospace) !default;\n\n// $font-size-root affects the value of `rem`, which is used for as well font sizes, paddings, and margins\n// $font-size-base affects the font size of the body text\n$font-size-root: null !default;\n$font-size-base: 1rem !default; // Assumes the browser default, typically `16px`\n$font-size-sm: $font-size-base * .875 !default;\n$font-size-lg: $font-size-base * 1.25 !default;\n\n$font-weight-lighter: lighter !default;\n$font-weight-light: 300 !default;\n$font-weight-normal: 400 !default;\n$font-weight-medium: 500 !default;\n$font-weight-semibold: 600 !default;\n$font-weight-bold: 700 !default;\n$font-weight-bolder: bolder !default;\n\n$font-weight-base: $font-weight-normal !default;\n\n$line-height-base: 1.5 !default;\n$line-height-sm: 1.25 !default;\n$line-height-lg: 2 !default;\n\n$h1-font-size: $font-size-base * 2.5 !default;\n$h2-font-size: $font-size-base * 2 !default;\n$h3-font-size: $font-size-base * 1.75 !default;\n$h4-font-size: $font-size-base * 1.5 !default;\n$h5-font-size: $font-size-base * 1.25 !default;\n$h6-font-size: $font-size-base !default;\n// scss-docs-end font-variables\n\n// scss-docs-start font-sizes\n$font-sizes: (\n 1: $h1-font-size,\n 2: $h2-font-size,\n 3: $h3-font-size,\n 4: $h4-font-size,\n 5: $h5-font-size,\n 6: $h6-font-size\n) !default;\n// scss-docs-end font-sizes\n\n// scss-docs-start headings-variables\n$headings-margin-bottom: $spacer * .5 !default;\n$headings-font-family: null !default;\n$headings-font-style: null !default;\n$headings-font-weight: 500 !default;\n$headings-line-height: 1.2 !default;\n$headings-color: inherit !default;\n// scss-docs-end headings-variables\n\n// scss-docs-start display-headings\n$display-font-sizes: (\n 1: 5rem,\n 2: 4.5rem,\n 3: 4rem,\n 4: 3.5rem,\n 5: 3rem,\n 6: 2.5rem\n) !default;\n\n$display-font-family: null !default;\n$display-font-style: null !default;\n$display-font-weight: 300 !default;\n$display-line-height: $headings-line-height !default;\n// scss-docs-end display-headings\n\n// scss-docs-start type-variables\n$lead-font-size: $font-size-base * 1.25 !default;\n$lead-font-weight: 300 !default;\n\n$small-font-size: .875em !default;\n\n$sub-sup-font-size: .75em !default;\n\n// fusv-disable\n$text-muted: var(--#{$prefix}secondary-color) !default; // Deprecated in 5.3.0\n// fusv-enable\n\n$initialism-font-size: $small-font-size !default;\n\n$blockquote-margin-y: $spacer !default;\n$blockquote-font-size: $font-size-base * 1.25 !default;\n$blockquote-footer-color: $gray-600 !default;\n$blockquote-footer-font-size: $small-font-size !default;\n\n$hr-margin-y: $spacer !default;\n$hr-color: inherit !default;\n\n// fusv-disable\n$hr-bg-color: null !default; // Deprecated in v5.2.0\n$hr-height: null !default; // Deprecated in v5.2.0\n// fusv-enable\n\n$hr-border-color: null !default; // Allows for inherited colors\n$hr-border-width: var(--#{$prefix}border-width) !default;\n$hr-opacity: .25 !default;\n\n// scss-docs-start vr-variables\n$vr-border-width: var(--#{$prefix}border-width) !default;\n// scss-docs-end vr-variables\n\n$legend-margin-bottom: .5rem !default;\n$legend-font-size: 1.5rem !default;\n$legend-font-weight: null !default;\n\n$dt-font-weight: $font-weight-bold !default;\n\n$list-inline-padding: .5rem !default;\n\n$mark-padding: .1875em !default;\n$mark-color: $body-color !default;\n$mark-bg: $yellow-100 !default;\n// scss-docs-end type-variables\n\n\n// Tables\n//\n// Customizes the `.table` component with basic values, each used across all table variations.\n\n// scss-docs-start table-variables\n$table-cell-padding-y: .5rem !default;\n$table-cell-padding-x: .5rem !default;\n$table-cell-padding-y-sm: .25rem !default;\n$table-cell-padding-x-sm: .25rem !default;\n\n$table-cell-vertical-align: top !default;\n\n$table-color: var(--#{$prefix}emphasis-color) !default;\n$table-bg: var(--#{$prefix}body-bg) !default;\n$table-accent-bg: transparent !default;\n\n$table-th-font-weight: null !default;\n\n$table-striped-color: $table-color !default;\n$table-striped-bg-factor: .05 !default;\n$table-striped-bg: rgba(var(--#{$prefix}emphasis-color-rgb), $table-striped-bg-factor) !default;\n\n$table-active-color: $table-color !default;\n$table-active-bg-factor: .1 !default;\n$table-active-bg: rgba(var(--#{$prefix}emphasis-color-rgb), $table-active-bg-factor) !default;\n\n$table-hover-color: $table-color !default;\n$table-hover-bg-factor: .075 !default;\n$table-hover-bg: rgba(var(--#{$prefix}emphasis-color-rgb), $table-hover-bg-factor) !default;\n\n$table-border-factor: .2 !default;\n$table-border-width: var(--#{$prefix}border-width) !default;\n$table-border-color: var(--#{$prefix}border-color) !default;\n\n$table-striped-order: odd !default;\n$table-striped-columns-order: even !default;\n\n$table-group-separator-color: currentcolor !default;\n\n$table-caption-color: var(--#{$prefix}secondary-color) !default;\n\n$table-bg-scale: -80% !default;\n// scss-docs-end table-variables\n\n// scss-docs-start table-loop\n$table-variants: (\n \"primary\": shift-color($primary, $table-bg-scale),\n \"secondary\": shift-color($secondary, $table-bg-scale),\n \"success\": shift-color($success, $table-bg-scale),\n \"info\": shift-color($info, $table-bg-scale),\n \"warning\": shift-color($warning, $table-bg-scale),\n \"danger\": shift-color($danger, $table-bg-scale),\n \"light\": $light,\n \"dark\": $dark,\n) !default;\n// scss-docs-end table-loop\n\n\n// Buttons + Forms\n//\n// Shared variables that are reassigned to `$input-` and `$btn-` specific variables.\n\n// scss-docs-start input-btn-variables\n$input-btn-padding-y: .375rem !default;\n$input-btn-padding-x: .75rem !default;\n$input-btn-font-family: null !default;\n$input-btn-font-size: $font-size-base !default;\n$input-btn-line-height: $line-height-base !default;\n\n$input-btn-focus-width: $focus-ring-width !default;\n$input-btn-focus-color-opacity: $focus-ring-opacity !default;\n$input-btn-focus-color: $focus-ring-color !default;\n$input-btn-focus-blur: $focus-ring-blur !default;\n$input-btn-focus-box-shadow: $focus-ring-box-shadow !default;\n\n$input-btn-padding-y-sm: .25rem !default;\n$input-btn-padding-x-sm: .5rem !default;\n$input-btn-font-size-sm: $font-size-sm !default;\n\n$input-btn-padding-y-lg: .5rem !default;\n$input-btn-padding-x-lg: 1rem !default;\n$input-btn-font-size-lg: $font-size-lg !default;\n\n$input-btn-border-width: var(--#{$prefix}border-width) !default;\n// scss-docs-end input-btn-variables\n\n\n// Buttons\n//\n// For each of Bootstrap's buttons, define text, background, and border color.\n\n// scss-docs-start btn-variables\n$btn-color: var(--#{$prefix}body-color) !default;\n$btn-padding-y: $input-btn-padding-y !default;\n$btn-padding-x: $input-btn-padding-x !default;\n$btn-font-family: $input-btn-font-family !default;\n$btn-font-size: $input-btn-font-size !default;\n$btn-line-height: $input-btn-line-height !default;\n$btn-white-space: null !default; // Set to `nowrap` to prevent text wrapping\n\n$btn-padding-y-sm: $input-btn-padding-y-sm !default;\n$btn-padding-x-sm: $input-btn-padding-x-sm !default;\n$btn-font-size-sm: $input-btn-font-size-sm !default;\n\n$btn-padding-y-lg: $input-btn-padding-y-lg !default;\n$btn-padding-x-lg: $input-btn-padding-x-lg !default;\n$btn-font-size-lg: $input-btn-font-size-lg !default;\n\n$btn-border-width: $input-btn-border-width !default;\n\n$btn-font-weight: $font-weight-normal !default;\n$btn-box-shadow: inset 0 1px 0 rgba($white, .15), 0 1px 1px rgba($black, .075) !default;\n$btn-focus-width: $input-btn-focus-width !default;\n$btn-focus-box-shadow: $input-btn-focus-box-shadow !default;\n$btn-disabled-opacity: .65 !default;\n$btn-active-box-shadow: inset 0 3px 5px rgba($black, .125) !default;\n\n$btn-link-color: var(--#{$prefix}link-color) !default;\n$btn-link-hover-color: var(--#{$prefix}link-hover-color) !default;\n$btn-link-disabled-color: $gray-600 !default;\n$btn-link-focus-shadow-rgb: to-rgb(mix(color-contrast($link-color), $link-color, 15%)) !default;\n\n// Allows for customizing button radius independently from global border radius\n$btn-border-radius: var(--#{$prefix}border-radius) !default;\n$btn-border-radius-sm: var(--#{$prefix}border-radius-sm) !default;\n$btn-border-radius-lg: var(--#{$prefix}border-radius-lg) !default;\n\n$btn-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;\n\n$btn-hover-bg-shade-amount: 15% !default;\n$btn-hover-bg-tint-amount: 15% !default;\n$btn-hover-border-shade-amount: 20% !default;\n$btn-hover-border-tint-amount: 10% !default;\n$btn-active-bg-shade-amount: 20% !default;\n$btn-active-bg-tint-amount: 20% !default;\n$btn-active-border-shade-amount: 25% !default;\n$btn-active-border-tint-amount: 10% !default;\n// scss-docs-end btn-variables\n\n\n// Forms\n\n// scss-docs-start form-text-variables\n$form-text-margin-top: .25rem !default;\n$form-text-font-size: $small-font-size !default;\n$form-text-font-style: null !default;\n$form-text-font-weight: null !default;\n$form-text-color: var(--#{$prefix}secondary-color) !default;\n// scss-docs-end form-text-variables\n\n// scss-docs-start form-label-variables\n$form-label-margin-bottom: .5rem !default;\n$form-label-font-size: null !default;\n$form-label-font-style: null !default;\n$form-label-font-weight: null !default;\n$form-label-color: null !default;\n// scss-docs-end form-label-variables\n\n// scss-docs-start form-input-variables\n$input-padding-y: $input-btn-padding-y !default;\n$input-padding-x: $input-btn-padding-x !default;\n$input-font-family: $input-btn-font-family !default;\n$input-font-size: $input-btn-font-size !default;\n$input-font-weight: $font-weight-base !default;\n$input-line-height: $input-btn-line-height !default;\n\n$input-padding-y-sm: $input-btn-padding-y-sm !default;\n$input-padding-x-sm: $input-btn-padding-x-sm !default;\n$input-font-size-sm: $input-btn-font-size-sm !default;\n\n$input-padding-y-lg: $input-btn-padding-y-lg !default;\n$input-padding-x-lg: $input-btn-padding-x-lg !default;\n$input-font-size-lg: $input-btn-font-size-lg !default;\n\n$input-bg: var(--#{$prefix}body-bg) !default;\n$input-disabled-color: null !default;\n$input-disabled-bg: var(--#{$prefix}secondary-bg) !default;\n$input-disabled-border-color: null !default;\n\n$input-color: var(--#{$prefix}body-color) !default;\n$input-border-color: var(--#{$prefix}border-color) !default;\n$input-border-width: $input-btn-border-width !default;\n$input-box-shadow: var(--#{$prefix}box-shadow-inset) !default;\n\n$input-border-radius: var(--#{$prefix}border-radius) !default;\n$input-border-radius-sm: var(--#{$prefix}border-radius-sm) !default;\n$input-border-radius-lg: var(--#{$prefix}border-radius-lg) !default;\n\n$input-focus-bg: $input-bg !default;\n$input-focus-border-color: tint-color($component-active-bg, 50%) !default;\n$input-focus-color: $input-color !default;\n$input-focus-width: $input-btn-focus-width !default;\n$input-focus-box-shadow: $input-btn-focus-box-shadow !default;\n\n$input-placeholder-color: var(--#{$prefix}secondary-color) !default;\n$input-plaintext-color: var(--#{$prefix}body-color) !default;\n\n$input-height-border: calc(#{$input-border-width} * 2) !default; // stylelint-disable-line function-disallowed-list\n\n$input-height-inner: add($input-line-height * 1em, $input-padding-y * 2) !default;\n$input-height-inner-half: add($input-line-height * .5em, $input-padding-y) !default;\n$input-height-inner-quarter: add($input-line-height * .25em, $input-padding-y * .5) !default;\n\n$input-height: add($input-line-height * 1em, add($input-padding-y * 2, $input-height-border, false)) !default;\n$input-height-sm: add($input-line-height * 1em, add($input-padding-y-sm * 2, $input-height-border, false)) !default;\n$input-height-lg: add($input-line-height * 1em, add($input-padding-y-lg * 2, $input-height-border, false)) !default;\n\n$input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;\n\n$form-color-width: 3rem !default;\n// scss-docs-end form-input-variables\n\n// scss-docs-start form-check-variables\n$form-check-input-width: 1em !default;\n$form-check-min-height: $font-size-base * $line-height-base !default;\n$form-check-padding-start: $form-check-input-width + .5em !default;\n$form-check-margin-bottom: .125rem !default;\n$form-check-label-color: null !default;\n$form-check-label-cursor: null !default;\n$form-check-transition: null !default;\n\n$form-check-input-active-filter: brightness(90%) !default;\n\n$form-check-input-bg: $input-bg !default;\n$form-check-input-border: var(--#{$prefix}border-width) solid var(--#{$prefix}border-color) !default;\n$form-check-input-border-radius: .25em !default;\n$form-check-radio-border-radius: 50% !default;\n$form-check-input-focus-border: $input-focus-border-color !default;\n$form-check-input-focus-box-shadow: $focus-ring-box-shadow !default;\n\n$form-check-input-checked-color: $component-active-color !default;\n$form-check-input-checked-bg-color: $component-active-bg !default;\n$form-check-input-checked-border-color: $form-check-input-checked-bg-color !default;\n$form-check-input-checked-bg-image: url(\"data:image/svg+xml,\") !default;\n$form-check-radio-checked-bg-image: url(\"data:image/svg+xml,\") !default;\n\n$form-check-input-indeterminate-color: $component-active-color !default;\n$form-check-input-indeterminate-bg-color: $component-active-bg !default;\n$form-check-input-indeterminate-border-color: $form-check-input-indeterminate-bg-color !default;\n$form-check-input-indeterminate-bg-image: url(\"data:image/svg+xml,\") !default;\n\n$form-check-input-disabled-opacity: .5 !default;\n$form-check-label-disabled-opacity: $form-check-input-disabled-opacity !default;\n$form-check-btn-check-disabled-opacity: $btn-disabled-opacity !default;\n\n$form-check-inline-margin-end: 1rem !default;\n// scss-docs-end form-check-variables\n\n// scss-docs-start form-switch-variables\n$form-switch-color: rgba($black, .25) !default;\n$form-switch-width: 2em !default;\n$form-switch-padding-start: $form-switch-width + .5em !default;\n$form-switch-bg-image: url(\"data:image/svg+xml,\") !default;\n$form-switch-border-radius: $form-switch-width !default;\n$form-switch-transition: background-position .15s ease-in-out !default;\n\n$form-switch-focus-color: $input-focus-border-color !default;\n$form-switch-focus-bg-image: url(\"data:image/svg+xml,\") !default;\n\n$form-switch-checked-color: $component-active-color !default;\n$form-switch-checked-bg-image: url(\"data:image/svg+xml,\") !default;\n$form-switch-checked-bg-position: right center !default;\n// scss-docs-end form-switch-variables\n\n// scss-docs-start input-group-variables\n$input-group-addon-padding-y: $input-padding-y !default;\n$input-group-addon-padding-x: $input-padding-x !default;\n$input-group-addon-font-weight: $input-font-weight !default;\n$input-group-addon-color: $input-color !default;\n$input-group-addon-bg: var(--#{$prefix}tertiary-bg) !default;\n$input-group-addon-border-color: $input-border-color !default;\n// scss-docs-end input-group-variables\n\n// scss-docs-start form-select-variables\n$form-select-padding-y: $input-padding-y !default;\n$form-select-padding-x: $input-padding-x !default;\n$form-select-font-family: $input-font-family !default;\n$form-select-font-size: $input-font-size !default;\n$form-select-indicator-padding: $form-select-padding-x * 3 !default; // Extra padding for background-image\n$form-select-font-weight: $input-font-weight !default;\n$form-select-line-height: $input-line-height !default;\n$form-select-color: $input-color !default;\n$form-select-bg: $input-bg !default;\n$form-select-disabled-color: null !default;\n$form-select-disabled-bg: $input-disabled-bg !default;\n$form-select-disabled-border-color: $input-disabled-border-color !default;\n$form-select-bg-position: right $form-select-padding-x center !default;\n$form-select-bg-size: 16px 12px !default; // In pixels because image dimensions\n$form-select-indicator-color: $gray-800 !default;\n$form-select-indicator: url(\"data:image/svg+xml,\") !default;\n\n$form-select-feedback-icon-padding-end: $form-select-padding-x * 2.5 + $form-select-indicator-padding !default;\n$form-select-feedback-icon-position: center right $form-select-indicator-padding !default;\n$form-select-feedback-icon-size: $input-height-inner-half $input-height-inner-half !default;\n\n$form-select-border-width: $input-border-width !default;\n$form-select-border-color: $input-border-color !default;\n$form-select-border-radius: $input-border-radius !default;\n$form-select-box-shadow: var(--#{$prefix}box-shadow-inset) !default;\n\n$form-select-focus-border-color: $input-focus-border-color !default;\n$form-select-focus-width: $input-focus-width !default;\n$form-select-focus-box-shadow: 0 0 0 $form-select-focus-width $input-btn-focus-color !default;\n\n$form-select-padding-y-sm: $input-padding-y-sm !default;\n$form-select-padding-x-sm: $input-padding-x-sm !default;\n$form-select-font-size-sm: $input-font-size-sm !default;\n$form-select-border-radius-sm: $input-border-radius-sm !default;\n\n$form-select-padding-y-lg: $input-padding-y-lg !default;\n$form-select-padding-x-lg: $input-padding-x-lg !default;\n$form-select-font-size-lg: $input-font-size-lg !default;\n$form-select-border-radius-lg: $input-border-radius-lg !default;\n\n$form-select-transition: $input-transition !default;\n// scss-docs-end form-select-variables\n\n// scss-docs-start form-range-variables\n$form-range-track-width: 100% !default;\n$form-range-track-height: .5rem !default;\n$form-range-track-cursor: pointer !default;\n$form-range-track-bg: var(--#{$prefix}secondary-bg) !default;\n$form-range-track-border-radius: 1rem !default;\n$form-range-track-box-shadow: var(--#{$prefix}box-shadow-inset) !default;\n\n$form-range-thumb-width: 1rem !default;\n$form-range-thumb-height: $form-range-thumb-width !default;\n$form-range-thumb-bg: $component-active-bg !default;\n$form-range-thumb-border: 0 !default;\n$form-range-thumb-border-radius: 1rem !default;\n$form-range-thumb-box-shadow: 0 .1rem .25rem rgba($black, .1) !default;\n$form-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-focus-box-shadow !default;\n$form-range-thumb-focus-box-shadow-width: $input-focus-width !default; // For focus box shadow issue in Edge\n$form-range-thumb-active-bg: tint-color($component-active-bg, 70%) !default;\n$form-range-thumb-disabled-bg: var(--#{$prefix}secondary-color) !default;\n$form-range-thumb-transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;\n// scss-docs-end form-range-variables\n\n// scss-docs-start form-file-variables\n$form-file-button-color: $input-color !default;\n$form-file-button-bg: var(--#{$prefix}tertiary-bg) !default;\n$form-file-button-hover-bg: var(--#{$prefix}secondary-bg) !default;\n// scss-docs-end form-file-variables\n\n// scss-docs-start form-floating-variables\n$form-floating-height: add(3.5rem, $input-height-border) !default;\n$form-floating-line-height: 1.25 !default;\n$form-floating-padding-x: $input-padding-x !default;\n$form-floating-padding-y: 1rem !default;\n$form-floating-input-padding-t: 1.625rem !default;\n$form-floating-input-padding-b: .625rem !default;\n$form-floating-label-height: 1.5em !default;\n$form-floating-label-opacity: .65 !default;\n$form-floating-label-transform: scale(.85) translateY(-.5rem) translateX(.15rem) !default;\n$form-floating-label-disabled-color: $gray-600 !default;\n$form-floating-transition: opacity .1s ease-in-out, transform .1s ease-in-out !default;\n// scss-docs-end form-floating-variables\n\n// Form validation\n\n// scss-docs-start form-feedback-variables\n$form-feedback-margin-top: $form-text-margin-top !default;\n$form-feedback-font-size: $form-text-font-size !default;\n$form-feedback-font-style: $form-text-font-style !default;\n$form-feedback-valid-color: $success !default;\n$form-feedback-invalid-color: $danger !default;\n\n$form-feedback-icon-valid-color: $form-feedback-valid-color !default;\n$form-feedback-icon-valid: url(\"data:image/svg+xml,\") !default;\n$form-feedback-icon-invalid-color: $form-feedback-invalid-color !default;\n$form-feedback-icon-invalid: url(\"data:image/svg+xml,\") !default;\n// scss-docs-end form-feedback-variables\n\n// scss-docs-start form-validation-colors\n$form-valid-color: $form-feedback-valid-color !default;\n$form-valid-border-color: $form-feedback-valid-color !default;\n$form-invalid-color: $form-feedback-invalid-color !default;\n$form-invalid-border-color: $form-feedback-invalid-color !default;\n// scss-docs-end form-validation-colors\n\n// scss-docs-start form-validation-states\n$form-validation-states: (\n \"valid\": (\n \"color\": var(--#{$prefix}form-valid-color),\n \"icon\": $form-feedback-icon-valid,\n \"tooltip-color\": #fff,\n \"tooltip-bg-color\": var(--#{$prefix}success),\n \"focus-box-shadow\": 0 0 $input-btn-focus-blur $input-focus-width rgba(var(--#{$prefix}success-rgb), $input-btn-focus-color-opacity),\n \"border-color\": var(--#{$prefix}form-valid-border-color),\n ),\n \"invalid\": (\n \"color\": var(--#{$prefix}form-invalid-color),\n \"icon\": $form-feedback-icon-invalid,\n \"tooltip-color\": #fff,\n \"tooltip-bg-color\": var(--#{$prefix}danger),\n \"focus-box-shadow\": 0 0 $input-btn-focus-blur $input-focus-width rgba(var(--#{$prefix}danger-rgb), $input-btn-focus-color-opacity),\n \"border-color\": var(--#{$prefix}form-invalid-border-color),\n )\n) !default;\n// scss-docs-end form-validation-states\n\n// Z-index master list\n//\n// Warning: Avoid customizing these values. They're used for a bird's eye view\n// of components dependent on the z-axis and are designed to all work together.\n\n// scss-docs-start zindex-stack\n$zindex-dropdown: 1000 !default;\n$zindex-sticky: 1020 !default;\n$zindex-fixed: 1030 !default;\n$zindex-offcanvas-backdrop: 1040 !default;\n$zindex-offcanvas: 1045 !default;\n$zindex-modal-backdrop: 1050 !default;\n$zindex-modal: 1055 !default;\n$zindex-popover: 1070 !default;\n$zindex-tooltip: 1080 !default;\n$zindex-toast: 1090 !default;\n// scss-docs-end zindex-stack\n\n// scss-docs-start zindex-levels-map\n$zindex-levels: (\n n1: -1,\n 0: 0,\n 1: 1,\n 2: 2,\n 3: 3\n) !default;\n// scss-docs-end zindex-levels-map\n\n\n// Navs\n\n// scss-docs-start nav-variables\n$nav-link-padding-y: .5rem !default;\n$nav-link-padding-x: 1rem !default;\n$nav-link-font-size: null !default;\n$nav-link-font-weight: null !default;\n$nav-link-color: var(--#{$prefix}link-color) !default;\n$nav-link-hover-color: var(--#{$prefix}link-hover-color) !default;\n$nav-link-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out !default;\n$nav-link-disabled-color: var(--#{$prefix}secondary-color) !default;\n$nav-link-focus-box-shadow: $focus-ring-box-shadow !default;\n\n$nav-tabs-border-color: var(--#{$prefix}border-color) !default;\n$nav-tabs-border-width: var(--#{$prefix}border-width) !default;\n$nav-tabs-border-radius: var(--#{$prefix}border-radius) !default;\n$nav-tabs-link-hover-border-color: var(--#{$prefix}secondary-bg) var(--#{$prefix}secondary-bg) $nav-tabs-border-color !default;\n$nav-tabs-link-active-color: var(--#{$prefix}emphasis-color) !default;\n$nav-tabs-link-active-bg: var(--#{$prefix}body-bg) !default;\n$nav-tabs-link-active-border-color: var(--#{$prefix}border-color) var(--#{$prefix}border-color) $nav-tabs-link-active-bg !default;\n\n$nav-pills-border-radius: var(--#{$prefix}border-radius) !default;\n$nav-pills-link-active-color: $component-active-color !default;\n$nav-pills-link-active-bg: $component-active-bg !default;\n\n$nav-underline-gap: 1rem !default;\n$nav-underline-border-width: .125rem !default;\n$nav-underline-link-active-color: var(--#{$prefix}emphasis-color) !default;\n// scss-docs-end nav-variables\n\n\n// Navbar\n\n// scss-docs-start navbar-variables\n$navbar-padding-y: $spacer * .5 !default;\n$navbar-padding-x: null !default;\n\n$navbar-nav-link-padding-x: .5rem !default;\n\n$navbar-brand-font-size: $font-size-lg !default;\n// Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link\n$nav-link-height: $font-size-base * $line-height-base + $nav-link-padding-y * 2 !default;\n$navbar-brand-height: $navbar-brand-font-size * $line-height-base !default;\n$navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) * .5 !default;\n$navbar-brand-margin-end: 1rem !default;\n\n$navbar-toggler-padding-y: .25rem !default;\n$navbar-toggler-padding-x: .75rem !default;\n$navbar-toggler-font-size: $font-size-lg !default;\n$navbar-toggler-border-radius: $btn-border-radius !default;\n$navbar-toggler-focus-width: $btn-focus-width !default;\n$navbar-toggler-transition: box-shadow .15s ease-in-out !default;\n\n$navbar-light-color: rgba(var(--#{$prefix}emphasis-color-rgb), .65) !default;\n$navbar-light-hover-color: rgba(var(--#{$prefix}emphasis-color-rgb), .8) !default;\n$navbar-light-active-color: rgba(var(--#{$prefix}emphasis-color-rgb), 1) !default;\n$navbar-light-disabled-color: rgba(var(--#{$prefix}emphasis-color-rgb), .3) !default;\n$navbar-light-icon-color: rgba($body-color, .75) !default;\n$navbar-light-toggler-icon-bg: url(\"data:image/svg+xml,\") !default;\n$navbar-light-toggler-border-color: rgba(var(--#{$prefix}emphasis-color-rgb), .15) !default;\n$navbar-light-brand-color: $navbar-light-active-color !default;\n$navbar-light-brand-hover-color: $navbar-light-active-color !default;\n// scss-docs-end navbar-variables\n\n// scss-docs-start navbar-dark-variables\n$navbar-dark-color: rgba($white, .55) !default;\n$navbar-dark-hover-color: rgba($white, .75) !default;\n$navbar-dark-active-color: $white !default;\n$navbar-dark-disabled-color: rgba($white, .25) !default;\n$navbar-dark-icon-color: $navbar-dark-color !default;\n$navbar-dark-toggler-icon-bg: url(\"data:image/svg+xml,\") !default;\n$navbar-dark-toggler-border-color: rgba($white, .1) !default;\n$navbar-dark-brand-color: $navbar-dark-active-color !default;\n$navbar-dark-brand-hover-color: $navbar-dark-active-color !default;\n// scss-docs-end navbar-dark-variables\n\n\n// Dropdowns\n//\n// Dropdown menu container and contents.\n\n// scss-docs-start dropdown-variables\n$dropdown-min-width: 10rem !default;\n$dropdown-padding-x: 0 !default;\n$dropdown-padding-y: .5rem !default;\n$dropdown-spacer: .125rem !default;\n$dropdown-font-size: $font-size-base !default;\n$dropdown-color: var(--#{$prefix}body-color) !default;\n$dropdown-bg: var(--#{$prefix}body-bg) !default;\n$dropdown-border-color: var(--#{$prefix}border-color-translucent) !default;\n$dropdown-border-radius: var(--#{$prefix}border-radius) !default;\n$dropdown-border-width: var(--#{$prefix}border-width) !default;\n$dropdown-inner-border-radius: calc(#{$dropdown-border-radius} - #{$dropdown-border-width}) !default; // stylelint-disable-line function-disallowed-list\n$dropdown-divider-bg: $dropdown-border-color !default;\n$dropdown-divider-margin-y: $spacer * .5 !default;\n$dropdown-box-shadow: var(--#{$prefix}box-shadow) !default;\n\n$dropdown-link-color: var(--#{$prefix}body-color) !default;\n$dropdown-link-hover-color: $dropdown-link-color !default;\n$dropdown-link-hover-bg: var(--#{$prefix}tertiary-bg) !default;\n\n$dropdown-link-active-color: $component-active-color !default;\n$dropdown-link-active-bg: $component-active-bg !default;\n\n$dropdown-link-disabled-color: var(--#{$prefix}tertiary-color) !default;\n\n$dropdown-item-padding-y: $spacer * .25 !default;\n$dropdown-item-padding-x: $spacer !default;\n\n$dropdown-header-color: $gray-600 !default;\n$dropdown-header-padding-x: $dropdown-item-padding-x !default;\n$dropdown-header-padding-y: $dropdown-padding-y !default;\n// fusv-disable\n$dropdown-header-padding: $dropdown-header-padding-y $dropdown-header-padding-x !default; // Deprecated in v5.2.0\n// fusv-enable\n// scss-docs-end dropdown-variables\n\n// scss-docs-start dropdown-dark-variables\n$dropdown-dark-color: $gray-300 !default;\n$dropdown-dark-bg: $gray-800 !default;\n$dropdown-dark-border-color: $dropdown-border-color !default;\n$dropdown-dark-divider-bg: $dropdown-divider-bg !default;\n$dropdown-dark-box-shadow: null !default;\n$dropdown-dark-link-color: $dropdown-dark-color !default;\n$dropdown-dark-link-hover-color: $white !default;\n$dropdown-dark-link-hover-bg: rgba($white, .15) !default;\n$dropdown-dark-link-active-color: $dropdown-link-active-color !default;\n$dropdown-dark-link-active-bg: $dropdown-link-active-bg !default;\n$dropdown-dark-link-disabled-color: $gray-500 !default;\n$dropdown-dark-header-color: $gray-500 !default;\n// scss-docs-end dropdown-dark-variables\n\n\n// Pagination\n\n// scss-docs-start pagination-variables\n$pagination-padding-y: .375rem !default;\n$pagination-padding-x: .75rem !default;\n$pagination-padding-y-sm: .25rem !default;\n$pagination-padding-x-sm: .5rem !default;\n$pagination-padding-y-lg: .75rem !default;\n$pagination-padding-x-lg: 1.5rem !default;\n\n$pagination-font-size: $font-size-base !default;\n\n$pagination-color: var(--#{$prefix}link-color) !default;\n$pagination-bg: var(--#{$prefix}body-bg) !default;\n$pagination-border-radius: var(--#{$prefix}border-radius) !default;\n$pagination-border-width: var(--#{$prefix}border-width) !default;\n$pagination-margin-start: calc(#{$pagination-border-width} * -1) !default; // stylelint-disable-line function-disallowed-list\n$pagination-border-color: var(--#{$prefix}border-color) !default;\n\n$pagination-focus-color: var(--#{$prefix}link-hover-color) !default;\n$pagination-focus-bg: var(--#{$prefix}secondary-bg) !default;\n$pagination-focus-box-shadow: $focus-ring-box-shadow !default;\n$pagination-focus-outline: 0 !default;\n\n$pagination-hover-color: var(--#{$prefix}link-hover-color) !default;\n$pagination-hover-bg: var(--#{$prefix}tertiary-bg) !default;\n$pagination-hover-border-color: var(--#{$prefix}border-color) !default; // Todo in v6: remove this?\n\n$pagination-active-color: $component-active-color !default;\n$pagination-active-bg: $component-active-bg !default;\n$pagination-active-border-color: $component-active-bg !default;\n\n$pagination-disabled-color: var(--#{$prefix}secondary-color) !default;\n$pagination-disabled-bg: var(--#{$prefix}secondary-bg) !default;\n$pagination-disabled-border-color: var(--#{$prefix}border-color) !default;\n\n$pagination-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;\n\n$pagination-border-radius-sm: var(--#{$prefix}border-radius-sm) !default;\n$pagination-border-radius-lg: var(--#{$prefix}border-radius-lg) !default;\n// scss-docs-end pagination-variables\n\n\n// Placeholders\n\n// scss-docs-start placeholders\n$placeholder-opacity-max: .5 !default;\n$placeholder-opacity-min: .2 !default;\n// scss-docs-end placeholders\n\n// Cards\n\n// scss-docs-start card-variables\n$card-spacer-y: $spacer !default;\n$card-spacer-x: $spacer !default;\n$card-title-spacer-y: $spacer * .5 !default;\n$card-title-color: null !default;\n$card-subtitle-color: null !default;\n$card-border-width: var(--#{$prefix}border-width) !default;\n$card-border-color: var(--#{$prefix}border-color-translucent) !default;\n$card-border-radius: var(--#{$prefix}border-radius) !default;\n$card-box-shadow: null !default;\n$card-inner-border-radius: subtract($card-border-radius, $card-border-width) !default;\n$card-cap-padding-y: $card-spacer-y * .5 !default;\n$card-cap-padding-x: $card-spacer-x !default;\n$card-cap-bg: rgba(var(--#{$prefix}body-color-rgb), .03) !default;\n$card-cap-color: null !default;\n$card-height: null !default;\n$card-color: null !default;\n$card-bg: var(--#{$prefix}body-bg) !default;\n$card-img-overlay-padding: $spacer !default;\n$card-group-margin: $grid-gutter-width * .5 !default;\n// scss-docs-end card-variables\n\n// Accordion\n\n// scss-docs-start accordion-variables\n$accordion-padding-y: 1rem !default;\n$accordion-padding-x: 1.25rem !default;\n$accordion-color: var(--#{$prefix}body-color) !default;\n$accordion-bg: var(--#{$prefix}body-bg) !default;\n$accordion-border-width: var(--#{$prefix}border-width) !default;\n$accordion-border-color: var(--#{$prefix}border-color) !default;\n$accordion-border-radius: var(--#{$prefix}border-radius) !default;\n$accordion-inner-border-radius: subtract($accordion-border-radius, $accordion-border-width) !default;\n\n$accordion-body-padding-y: $accordion-padding-y !default;\n$accordion-body-padding-x: $accordion-padding-x !default;\n\n$accordion-button-padding-y: $accordion-padding-y !default;\n$accordion-button-padding-x: $accordion-padding-x !default;\n$accordion-button-color: var(--#{$prefix}body-color) !default;\n$accordion-button-bg: var(--#{$prefix}accordion-bg) !default;\n$accordion-transition: $btn-transition, border-radius .15s ease !default;\n$accordion-button-active-bg: var(--#{$prefix}primary-bg-subtle) !default;\n$accordion-button-active-color: var(--#{$prefix}primary-text-emphasis) !default;\n\n// fusv-disable\n$accordion-button-focus-border-color: $input-focus-border-color !default; // Deprecated in v5.3.3\n// fusv-enable\n$accordion-button-focus-box-shadow: $btn-focus-box-shadow !default;\n\n$accordion-icon-width: 1.25rem !default;\n$accordion-icon-color: $body-color !default;\n$accordion-icon-active-color: $primary-text-emphasis !default;\n$accordion-icon-transition: transform .2s ease-in-out !default;\n$accordion-icon-transform: rotate(-180deg) !default;\n\n$accordion-button-icon: url(\"data:image/svg+xml,\") !default;\n$accordion-button-active-icon: url(\"data:image/svg+xml,\") !default;\n// scss-docs-end accordion-variables\n\n// Tooltips\n\n// scss-docs-start tooltip-variables\n$tooltip-font-size: $font-size-sm !default;\n$tooltip-max-width: 200px !default;\n$tooltip-color: var(--#{$prefix}body-bg) !default;\n$tooltip-bg: var(--#{$prefix}emphasis-color) !default;\n$tooltip-border-radius: var(--#{$prefix}border-radius) !default;\n$tooltip-opacity: .9 !default;\n$tooltip-padding-y: $spacer * .25 !default;\n$tooltip-padding-x: $spacer * .5 !default;\n$tooltip-margin: null !default; // TODO: remove this in v6\n\n$tooltip-arrow-width: .8rem !default;\n$tooltip-arrow-height: .4rem !default;\n// fusv-disable\n$tooltip-arrow-color: null !default; // Deprecated in Bootstrap 5.2.0 for CSS variables\n// fusv-enable\n// scss-docs-end tooltip-variables\n\n// Form tooltips must come after regular tooltips\n// scss-docs-start tooltip-feedback-variables\n$form-feedback-tooltip-padding-y: $tooltip-padding-y !default;\n$form-feedback-tooltip-padding-x: $tooltip-padding-x !default;\n$form-feedback-tooltip-font-size: $tooltip-font-size !default;\n$form-feedback-tooltip-line-height: null !default;\n$form-feedback-tooltip-opacity: $tooltip-opacity !default;\n$form-feedback-tooltip-border-radius: $tooltip-border-radius !default;\n// scss-docs-end tooltip-feedback-variables\n\n\n// Popovers\n\n// scss-docs-start popover-variables\n$popover-font-size: $font-size-sm !default;\n$popover-bg: var(--#{$prefix}body-bg) !default;\n$popover-max-width: 276px !default;\n$popover-border-width: var(--#{$prefix}border-width) !default;\n$popover-border-color: var(--#{$prefix}border-color-translucent) !default;\n$popover-border-radius: var(--#{$prefix}border-radius-lg) !default;\n$popover-inner-border-radius: calc(#{$popover-border-radius} - #{$popover-border-width}) !default; // stylelint-disable-line function-disallowed-list\n$popover-box-shadow: var(--#{$prefix}box-shadow) !default;\n\n$popover-header-font-size: $font-size-base !default;\n$popover-header-bg: var(--#{$prefix}secondary-bg) !default;\n$popover-header-color: $headings-color !default;\n$popover-header-padding-y: .5rem !default;\n$popover-header-padding-x: $spacer !default;\n\n$popover-body-color: var(--#{$prefix}body-color) !default;\n$popover-body-padding-y: $spacer !default;\n$popover-body-padding-x: $spacer !default;\n\n$popover-arrow-width: 1rem !default;\n$popover-arrow-height: .5rem !default;\n// scss-docs-end popover-variables\n\n// fusv-disable\n// Deprecated in Bootstrap 5.2.0 for CSS variables\n$popover-arrow-color: $popover-bg !default;\n$popover-arrow-outer-color: var(--#{$prefix}border-color-translucent) !default;\n// fusv-enable\n\n\n// Toasts\n\n// scss-docs-start toast-variables\n$toast-max-width: 350px !default;\n$toast-padding-x: .75rem !default;\n$toast-padding-y: .5rem !default;\n$toast-font-size: .875rem !default;\n$toast-color: null !default;\n$toast-background-color: rgba(var(--#{$prefix}body-bg-rgb), .85) !default;\n$toast-border-width: var(--#{$prefix}border-width) !default;\n$toast-border-color: var(--#{$prefix}border-color-translucent) !default;\n$toast-border-radius: var(--#{$prefix}border-radius) !default;\n$toast-box-shadow: var(--#{$prefix}box-shadow) !default;\n$toast-spacing: $container-padding-x !default;\n\n$toast-header-color: var(--#{$prefix}secondary-color) !default;\n$toast-header-background-color: rgba(var(--#{$prefix}body-bg-rgb), .85) !default;\n$toast-header-border-color: $toast-border-color !default;\n// scss-docs-end toast-variables\n\n\n// Badges\n\n// scss-docs-start badge-variables\n$badge-font-size: .75em !default;\n$badge-font-weight: $font-weight-bold !default;\n$badge-color: $white !default;\n$badge-padding-y: .35em !default;\n$badge-padding-x: .65em !default;\n$badge-border-radius: var(--#{$prefix}border-radius) !default;\n// scss-docs-end badge-variables\n\n\n// Modals\n\n// scss-docs-start modal-variables\n$modal-inner-padding: $spacer !default;\n\n$modal-footer-margin-between: .5rem !default;\n\n$modal-dialog-margin: .5rem !default;\n$modal-dialog-margin-y-sm-up: 1.75rem !default;\n\n$modal-title-line-height: $line-height-base !default;\n\n$modal-content-color: null !default;\n$modal-content-bg: var(--#{$prefix}body-bg) !default;\n$modal-content-border-color: var(--#{$prefix}border-color-translucent) !default;\n$modal-content-border-width: var(--#{$prefix}border-width) !default;\n$modal-content-border-radius: var(--#{$prefix}border-radius-lg) !default;\n$modal-content-inner-border-radius: subtract($modal-content-border-radius, $modal-content-border-width) !default;\n$modal-content-box-shadow-xs: var(--#{$prefix}box-shadow-sm) !default;\n$modal-content-box-shadow-sm-up: var(--#{$prefix}box-shadow) !default;\n\n$modal-backdrop-bg: $black !default;\n$modal-backdrop-opacity: .5 !default;\n\n$modal-header-border-color: var(--#{$prefix}border-color) !default;\n$modal-header-border-width: $modal-content-border-width !default;\n$modal-header-padding-y: $modal-inner-padding !default;\n$modal-header-padding-x: $modal-inner-padding !default;\n$modal-header-padding: $modal-header-padding-y $modal-header-padding-x !default; // Keep this for backwards compatibility\n\n$modal-footer-bg: null !default;\n$modal-footer-border-color: $modal-header-border-color !default;\n$modal-footer-border-width: $modal-header-border-width !default;\n\n$modal-sm: 300px !default;\n$modal-md: 500px !default;\n$modal-lg: 800px !default;\n$modal-xl: 1140px !default;\n\n$modal-fade-transform: translate(0, -50px) !default;\n$modal-show-transform: none !default;\n$modal-transition: transform .3s ease-out !default;\n$modal-scale-transform: scale(1.02) !default;\n// scss-docs-end modal-variables\n\n\n// Alerts\n//\n// Define alert colors, border radius, and padding.\n\n// scss-docs-start alert-variables\n$alert-padding-y: $spacer !default;\n$alert-padding-x: $spacer !default;\n$alert-margin-bottom: 1rem !default;\n$alert-border-radius: var(--#{$prefix}border-radius) !default;\n$alert-link-font-weight: $font-weight-bold !default;\n$alert-border-width: var(--#{$prefix}border-width) !default;\n$alert-dismissible-padding-r: $alert-padding-x * 3 !default; // 3x covers width of x plus default padding on either side\n// scss-docs-end alert-variables\n\n// fusv-disable\n$alert-bg-scale: -80% !default; // Deprecated in v5.2.0, to be removed in v6\n$alert-border-scale: -70% !default; // Deprecated in v5.2.0, to be removed in v6\n$alert-color-scale: 40% !default; // Deprecated in v5.2.0, to be removed in v6\n// fusv-enable\n\n// Progress bars\n\n// scss-docs-start progress-variables\n$progress-height: 1rem !default;\n$progress-font-size: $font-size-base * .75 !default;\n$progress-bg: var(--#{$prefix}secondary-bg) !default;\n$progress-border-radius: var(--#{$prefix}border-radius) !default;\n$progress-box-shadow: var(--#{$prefix}box-shadow-inset) !default;\n$progress-bar-color: $white !default;\n$progress-bar-bg: $primary !default;\n$progress-bar-animation-timing: 1s linear infinite !default;\n$progress-bar-transition: width .6s ease !default;\n// scss-docs-end progress-variables\n\n\n// List group\n\n// scss-docs-start list-group-variables\n$list-group-color: var(--#{$prefix}body-color) !default;\n$list-group-bg: var(--#{$prefix}body-bg) !default;\n$list-group-border-color: var(--#{$prefix}border-color) !default;\n$list-group-border-width: var(--#{$prefix}border-width) !default;\n$list-group-border-radius: var(--#{$prefix}border-radius) !default;\n\n$list-group-item-padding-y: $spacer * .5 !default;\n$list-group-item-padding-x: $spacer !default;\n// fusv-disable\n$list-group-item-bg-scale: -80% !default; // Deprecated in v5.3.0\n$list-group-item-color-scale: 40% !default; // Deprecated in v5.3.0\n// fusv-enable\n\n$list-group-hover-bg: var(--#{$prefix}tertiary-bg) !default;\n$list-group-active-color: $component-active-color !default;\n$list-group-active-bg: $component-active-bg !default;\n$list-group-active-border-color: $list-group-active-bg !default;\n\n$list-group-disabled-color: var(--#{$prefix}secondary-color) !default;\n$list-group-disabled-bg: $list-group-bg !default;\n\n$list-group-action-color: var(--#{$prefix}secondary-color) !default;\n$list-group-action-hover-color: var(--#{$prefix}emphasis-color) !default;\n\n$list-group-action-active-color: var(--#{$prefix}body-color) !default;\n$list-group-action-active-bg: var(--#{$prefix}secondary-bg) !default;\n// scss-docs-end list-group-variables\n\n\n// Image thumbnails\n\n// scss-docs-start thumbnail-variables\n$thumbnail-padding: .25rem !default;\n$thumbnail-bg: var(--#{$prefix}body-bg) !default;\n$thumbnail-border-width: var(--#{$prefix}border-width) !default;\n$thumbnail-border-color: var(--#{$prefix}border-color) !default;\n$thumbnail-border-radius: var(--#{$prefix}border-radius) !default;\n$thumbnail-box-shadow: var(--#{$prefix}box-shadow-sm) !default;\n// scss-docs-end thumbnail-variables\n\n\n// Figures\n\n// scss-docs-start figure-variables\n$figure-caption-font-size: $small-font-size !default;\n$figure-caption-color: var(--#{$prefix}secondary-color) !default;\n// scss-docs-end figure-variables\n\n\n// Breadcrumbs\n\n// scss-docs-start breadcrumb-variables\n$breadcrumb-font-size: null !default;\n$breadcrumb-padding-y: 0 !default;\n$breadcrumb-padding-x: 0 !default;\n$breadcrumb-item-padding-x: .5rem !default;\n$breadcrumb-margin-bottom: 1rem !default;\n$breadcrumb-bg: null !default;\n$breadcrumb-divider-color: var(--#{$prefix}secondary-color) !default;\n$breadcrumb-active-color: var(--#{$prefix}secondary-color) !default;\n$breadcrumb-divider: quote(\"/\") !default;\n$breadcrumb-divider-flipped: $breadcrumb-divider !default;\n$breadcrumb-border-radius: null !default;\n// scss-docs-end breadcrumb-variables\n\n// Carousel\n\n// scss-docs-start carousel-variables\n$carousel-control-color: $white !default;\n$carousel-control-width: 15% !default;\n$carousel-control-opacity: .5 !default;\n$carousel-control-hover-opacity: .9 !default;\n$carousel-control-transition: opacity .15s ease !default;\n\n$carousel-indicator-width: 30px !default;\n$carousel-indicator-height: 3px !default;\n$carousel-indicator-hit-area-height: 10px !default;\n$carousel-indicator-spacer: 3px !default;\n$carousel-indicator-opacity: .5 !default;\n$carousel-indicator-active-bg: $white !default;\n$carousel-indicator-active-opacity: 1 !default;\n$carousel-indicator-transition: opacity .6s ease !default;\n\n$carousel-caption-width: 70% !default;\n$carousel-caption-color: $white !default;\n$carousel-caption-padding-y: 1.25rem !default;\n$carousel-caption-spacer: 1.25rem !default;\n\n$carousel-control-icon-width: 2rem !default;\n\n$carousel-control-prev-icon-bg: url(\"data:image/svg+xml,\") !default;\n$carousel-control-next-icon-bg: url(\"data:image/svg+xml,\") !default;\n\n$carousel-transition-duration: .6s !default;\n$carousel-transition: transform $carousel-transition-duration ease-in-out !default; // Define transform transition first if using multiple transitions (e.g., `transform 2s ease, opacity .5s ease-out`)\n// scss-docs-end carousel-variables\n\n// scss-docs-start carousel-dark-variables\n$carousel-dark-indicator-active-bg: $black !default;\n$carousel-dark-caption-color: $black !default;\n$carousel-dark-control-icon-filter: invert(1) grayscale(100) !default;\n// scss-docs-end carousel-dark-variables\n\n\n// Spinners\n\n// scss-docs-start spinner-variables\n$spinner-width: 2rem !default;\n$spinner-height: $spinner-width !default;\n$spinner-vertical-align: -.125em !default;\n$spinner-border-width: .25em !default;\n$spinner-animation-speed: .75s !default;\n\n$spinner-width-sm: 1rem !default;\n$spinner-height-sm: $spinner-width-sm !default;\n$spinner-border-width-sm: .2em !default;\n// scss-docs-end spinner-variables\n\n\n// Close\n\n// scss-docs-start close-variables\n$btn-close-width: 1em !default;\n$btn-close-height: $btn-close-width !default;\n$btn-close-padding-x: .25em !default;\n$btn-close-padding-y: $btn-close-padding-x !default;\n$btn-close-color: $black !default;\n$btn-close-bg: url(\"data:image/svg+xml,\") !default;\n$btn-close-focus-shadow: $focus-ring-box-shadow !default;\n$btn-close-opacity: .5 !default;\n$btn-close-hover-opacity: .75 !default;\n$btn-close-focus-opacity: 1 !default;\n$btn-close-disabled-opacity: .25 !default;\n$btn-close-white-filter: invert(1) grayscale(100%) brightness(200%) !default;\n// scss-docs-end close-variables\n\n\n// Offcanvas\n\n// scss-docs-start offcanvas-variables\n$offcanvas-padding-y: $modal-inner-padding !default;\n$offcanvas-padding-x: $modal-inner-padding !default;\n$offcanvas-horizontal-width: 400px !default;\n$offcanvas-vertical-height: 30vh !default;\n$offcanvas-transition-duration: .3s !default;\n$offcanvas-border-color: $modal-content-border-color !default;\n$offcanvas-border-width: $modal-content-border-width !default;\n$offcanvas-title-line-height: $modal-title-line-height !default;\n$offcanvas-bg-color: var(--#{$prefix}body-bg) !default;\n$offcanvas-color: var(--#{$prefix}body-color) !default;\n$offcanvas-box-shadow: $modal-content-box-shadow-xs !default;\n$offcanvas-backdrop-bg: $modal-backdrop-bg !default;\n$offcanvas-backdrop-opacity: $modal-backdrop-opacity !default;\n// scss-docs-end offcanvas-variables\n\n// Code\n\n$code-font-size: $small-font-size !default;\n$code-color: $pink !default;\n\n$kbd-padding-y: .1875rem !default;\n$kbd-padding-x: .375rem !default;\n$kbd-font-size: $code-font-size !default;\n$kbd-color: var(--#{$prefix}body-bg) !default;\n$kbd-bg: var(--#{$prefix}body-color) !default;\n$nested-kbd-font-weight: null !default; // Deprecated in v5.2.0, removing in v6\n\n$pre-color: null !default;\n\n@import \"variables-dark\"; // TODO: can be removed safely in v6, only here to avoid breaking changes in v5.3\n","// Row\n//\n// Rows contain your columns.\n\n:root {\n @each $name, $value in $grid-breakpoints {\n --#{$prefix}breakpoint-#{$name}: #{$value};\n }\n}\n\n@if $enable-grid-classes {\n .row {\n @include make-row();\n\n > * {\n @include make-col-ready();\n }\n }\n}\n\n@if $enable-cssgrid {\n .grid {\n display: grid;\n grid-template-rows: repeat(var(--#{$prefix}rows, 1), 1fr);\n grid-template-columns: repeat(var(--#{$prefix}columns, #{$grid-columns}), 1fr);\n gap: var(--#{$prefix}gap, #{$grid-gutter-width});\n\n @include make-cssgrid();\n }\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n@if $enable-grid-classes {\n @include make-grid-columns();\n}\n","// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n@mixin make-row($gutter: $grid-gutter-width) {\n --#{$prefix}gutter-x: #{$gutter};\n --#{$prefix}gutter-y: 0;\n display: flex;\n flex-wrap: wrap;\n // TODO: Revisit calc order after https://github.com/react-bootstrap/react-bootstrap/issues/6039 is fixed\n margin-top: calc(-1 * var(--#{$prefix}gutter-y)); // stylelint-disable-line function-disallowed-list\n margin-right: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list\n margin-left: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list\n}\n\n@mixin make-col-ready() {\n // Add box sizing if only the grid is loaded\n box-sizing: if(variable-exists(include-column-box-sizing) and $include-column-box-sizing, border-box, null);\n // Prevent columns from becoming too narrow when at smaller grid tiers by\n // always setting `width: 100%;`. This works because we set the width\n // later on to override this initial width.\n flex-shrink: 0;\n width: 100%;\n max-width: 100%; // Prevent `.col-auto`, `.col` (& responsive variants) from breaking out the grid\n padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n margin-top: var(--#{$prefix}gutter-y);\n}\n\n@mixin make-col($size: false, $columns: $grid-columns) {\n @if $size {\n flex: 0 0 auto;\n width: percentage(divide($size, $columns));\n\n } @else {\n flex: 1 1 0;\n max-width: 100%;\n }\n}\n\n@mixin make-col-auto() {\n flex: 0 0 auto;\n width: auto;\n}\n\n@mixin make-col-offset($size, $columns: $grid-columns) {\n $num: divide($size, $columns);\n margin-left: if($num == 0, 0, percentage($num));\n}\n\n// Row columns\n//\n// Specify on a parent element(e.g., .row) to force immediate children into NN\n// number of columns. Supports wrapping to new lines, but does not do a Masonry\n// style grid.\n@mixin row-cols($count) {\n > * {\n flex: 0 0 auto;\n width: percentage(divide(1, $count));\n }\n}\n\n// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `$grid-columns`.\n\n@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) {\n @each $breakpoint in map-keys($breakpoints) {\n $infix: breakpoint-infix($breakpoint, $breakpoints);\n\n @include media-breakpoint-up($breakpoint, $breakpoints) {\n // Provide basic `.col-{bp}` classes for equal-width flexbox columns\n .col#{$infix} {\n flex: 1 0 0%; // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4\n }\n\n .row-cols#{$infix}-auto > * {\n @include make-col-auto();\n }\n\n @if $grid-row-columns > 0 {\n @for $i from 1 through $grid-row-columns {\n .row-cols#{$infix}-#{$i} {\n @include row-cols($i);\n }\n }\n }\n\n .col#{$infix}-auto {\n @include make-col-auto();\n }\n\n @if $columns > 0 {\n @for $i from 1 through $columns {\n .col#{$infix}-#{$i} {\n @include make-col($i, $columns);\n }\n }\n\n // `$columns - 1` because offsetting by the width of an entire row isn't possible\n @for $i from 0 through ($columns - 1) {\n @if not ($infix == \"\" and $i == 0) { // Avoid emitting useless .offset-0\n .offset#{$infix}-#{$i} {\n @include make-col-offset($i, $columns);\n }\n }\n }\n }\n\n // Gutters\n //\n // Make use of `.g-*`, `.gx-*` or `.gy-*` utilities to change spacing between the columns.\n @each $key, $value in $gutters {\n .g#{$infix}-#{$key},\n .gx#{$infix}-#{$key} {\n --#{$prefix}gutter-x: #{$value};\n }\n\n .g#{$infix}-#{$key},\n .gy#{$infix}-#{$key} {\n --#{$prefix}gutter-y: #{$value};\n }\n }\n }\n }\n}\n\n@mixin make-cssgrid($columns: $grid-columns, $breakpoints: $grid-breakpoints) {\n @each $breakpoint in map-keys($breakpoints) {\n $infix: breakpoint-infix($breakpoint, $breakpoints);\n\n @include media-breakpoint-up($breakpoint, $breakpoints) {\n @if $columns > 0 {\n @for $i from 1 through $columns {\n .g-col#{$infix}-#{$i} {\n grid-column: auto / span $i;\n }\n }\n\n // Start with `1` because `0` is an invalid value.\n // Ends with `$columns - 1` because offsetting by the width of an entire row isn't possible.\n @for $i from 1 through ($columns - 1) {\n .g-start#{$infix}-#{$i} {\n grid-column-start: $i;\n }\n }\n }\n }\n }\n}\n","// Utility generator\n// Used to generate utilities & print utilities\n@mixin generate-utility($utility, $infix: \"\", $is-rfs-media-query: false) {\n $values: map-get($utility, values);\n\n // If the values are a list or string, convert it into a map\n @if type-of($values) == \"string\" or type-of(nth($values, 1)) != \"list\" {\n $values: zip($values, $values);\n }\n\n @each $key, $value in $values {\n $properties: map-get($utility, property);\n\n // Multiple properties are possible, for example with vertical or horizontal margins or paddings\n @if type-of($properties) == \"string\" {\n $properties: append((), $properties);\n }\n\n // Use custom class if present\n $property-class: if(map-has-key($utility, class), map-get($utility, class), nth($properties, 1));\n $property-class: if($property-class == null, \"\", $property-class);\n\n // Use custom CSS variable name if present, otherwise default to `class`\n $css-variable-name: if(map-has-key($utility, css-variable-name), map-get($utility, css-variable-name), map-get($utility, class));\n\n // State params to generate pseudo-classes\n $state: if(map-has-key($utility, state), map-get($utility, state), ());\n\n $infix: if($property-class == \"\" and str-slice($infix, 1, 1) == \"-\", str-slice($infix, 2), $infix);\n\n // Don't prefix if value key is null (e.g. with shadow class)\n $property-class-modifier: if($key, if($property-class == \"\" and $infix == \"\", \"\", \"-\") + $key, \"\");\n\n @if map-get($utility, rfs) {\n // Inside the media query\n @if $is-rfs-media-query {\n $val: rfs-value($value);\n\n // Do not render anything if fluid and non fluid values are the same\n $value: if($val == rfs-fluid-value($value), null, $val);\n }\n @else {\n $value: rfs-fluid-value($value);\n }\n }\n\n $is-css-var: map-get($utility, css-var);\n $is-local-vars: map-get($utility, local-vars);\n $is-rtl: map-get($utility, rtl);\n\n @if $value != null {\n @if $is-rtl == false {\n /* rtl:begin:remove */\n }\n\n @if $is-css-var {\n .#{$property-class + $infix + $property-class-modifier} {\n --#{$prefix}#{$css-variable-name}: #{$value};\n }\n\n @each $pseudo in $state {\n .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {\n --#{$prefix}#{$css-variable-name}: #{$value};\n }\n }\n } @else {\n .#{$property-class + $infix + $property-class-modifier} {\n @each $property in $properties {\n @if $is-local-vars {\n @each $local-var, $variable in $is-local-vars {\n --#{$prefix}#{$local-var}: #{$variable};\n }\n }\n #{$property}: $value if($enable-important-utilities, !important, null);\n }\n }\n\n @each $pseudo in $state {\n .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {\n @each $property in $properties {\n @if $is-local-vars {\n @each $local-var, $variable in $is-local-vars {\n --#{$prefix}#{$local-var}: #{$variable};\n }\n }\n #{$property}: $value if($enable-important-utilities, !important, null);\n }\n }\n }\n }\n\n @if $is-rtl == false {\n /* rtl:end:remove */\n }\n }\n }\n}\n","// Loop over each breakpoint\n@each $breakpoint in map-keys($grid-breakpoints) {\n\n // Generate media query if needed\n @include media-breakpoint-up($breakpoint) {\n $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\n\n // Loop over each utility property\n @each $key, $utility in $utilities {\n // The utility can be disabled with `false`, thus check if the utility is a map first\n // Only proceed if responsive media queries are enabled or if it's the base media query\n @if type-of($utility) == \"map\" and (map-get($utility, responsive) or $infix == \"\") {\n @include generate-utility($utility, $infix);\n }\n }\n }\n}\n\n// RFS rescaling\n@media (min-width: $rfs-mq-value) {\n @each $breakpoint in map-keys($grid-breakpoints) {\n $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\n\n @if (map-get($grid-breakpoints, $breakpoint) < $rfs-breakpoint) {\n // Loop over each utility property\n @each $key, $utility in $utilities {\n // The utility can be disabled with `false`, thus check if the utility is a map first\n // Only proceed if responsive media queries are enabled or if it's the base media query\n @if type-of($utility) == \"map\" and map-get($utility, rfs) and (map-get($utility, responsive) or $infix == \"\") {\n @include generate-utility($utility, $infix, true);\n }\n }\n }\n }\n}\n\n\n// Print utilities\n@media print {\n @each $key, $utility in $utilities {\n // The utility can be disabled with `false`, thus check if the utility is a map first\n // Then check if the utility needs print styles\n @if type-of($utility) == \"map\" and map-get($utility, print) == true {\n @include generate-utility($utility, \"-print\");\n }\n }\n}\n"]} \ No newline at end of file diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css new file mode 100644 index 0000000..49b843b --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css @@ -0,0 +1,6 @@ +/*! + * Bootstrap Grid v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{--bs-gutter-x:1.5rem;--bs-gutter-y:0;width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}:root{--bs-breakpoint-xs:0;--bs-breakpoint-sm:576px;--bs-breakpoint-md:768px;--bs-breakpoint-lg:992px;--bs-breakpoint-xl:1200px;--bs-breakpoint-xxl:1400px}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{box-sizing:border-box;flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.66666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.66666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.66666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.66666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.66666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.66666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-inline-grid{display:inline-grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}@media (min-width:576px){.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-inline-grid{display:inline-grid!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:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}}@media (min-width:768px){.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-inline-grid{display:inline-grid!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:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}}@media (min-width:992px){.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-inline-grid{display:inline-grid!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:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}}@media (min-width:1200px){.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-inline-grid{display:inline-grid!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:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}}@media (min-width:1400px){.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-inline-grid{display:inline-grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-inline-grid{display:inline-grid!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:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} +/*# sourceMappingURL=bootstrap-grid.min.css.map */ \ No newline at end of file diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map new file mode 100644 index 0000000..a0db8b5 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../scss/mixins/_banner.scss","../../scss/_containers.scss","dist/css/bootstrap-grid.css","../../scss/mixins/_container.scss","../../scss/mixins/_breakpoints.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/mixins/_utilities.scss","../../scss/utilities/_api.scss"],"names":[],"mappings":"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","sourcesContent":["@mixin bsBanner($file) {\n /*!\n * Bootstrap #{$file} v5.3.3 (https://getbootstrap.com/)\n * Copyright 2011-2024 The Bootstrap Authors\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n}\n","// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n@if $enable-container-classes {\n // Single container class with breakpoint max-widths\n .container,\n // 100% wide container at all breakpoints\n .container-fluid {\n @include make-container();\n }\n\n // Responsive containers that are 100% wide until a breakpoint\n @each $breakpoint, $container-max-width in $container-max-widths {\n .container-#{$breakpoint} {\n @extend .container-fluid;\n }\n\n @include media-breakpoint-up($breakpoint, $grid-breakpoints) {\n %responsive-container-#{$breakpoint} {\n max-width: $container-max-width;\n }\n\n // Extend each breakpoint which is smaller or equal to the current breakpoint\n $extend-breakpoint: true;\n\n @each $name, $width in $grid-breakpoints {\n @if ($extend-breakpoint) {\n .container#{breakpoint-infix($name, $grid-breakpoints)} {\n @extend %responsive-container-#{$breakpoint};\n }\n\n // Once the current breakpoint is reached, stop extending\n @if ($breakpoint == $name) {\n $extend-breakpoint: false;\n }\n }\n }\n }\n }\n}\n","/*!\n * Bootstrap Grid v5.3.3 (https://getbootstrap.com/)\n * Copyright 2011-2024 The Bootstrap Authors\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n.container,\n.container-fluid,\n.container-xxl,\n.container-xl,\n.container-lg,\n.container-md,\n.container-sm {\n --bs-gutter-x: 1.5rem;\n --bs-gutter-y: 0;\n width: 100%;\n padding-right: calc(var(--bs-gutter-x) * 0.5);\n padding-left: calc(var(--bs-gutter-x) * 0.5);\n margin-right: auto;\n margin-left: auto;\n}\n\n@media (min-width: 576px) {\n .container-sm, .container {\n max-width: 540px;\n }\n}\n@media (min-width: 768px) {\n .container-md, .container-sm, .container {\n max-width: 720px;\n }\n}\n@media (min-width: 992px) {\n .container-lg, .container-md, .container-sm, .container {\n max-width: 960px;\n }\n}\n@media (min-width: 1200px) {\n .container-xl, .container-lg, .container-md, .container-sm, .container {\n max-width: 1140px;\n }\n}\n@media (min-width: 1400px) {\n .container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container {\n max-width: 1320px;\n }\n}\n:root {\n --bs-breakpoint-xs: 0;\n --bs-breakpoint-sm: 576px;\n --bs-breakpoint-md: 768px;\n --bs-breakpoint-lg: 992px;\n --bs-breakpoint-xl: 1200px;\n --bs-breakpoint-xxl: 1400px;\n}\n\n.row {\n --bs-gutter-x: 1.5rem;\n --bs-gutter-y: 0;\n display: flex;\n flex-wrap: wrap;\n margin-top: calc(-1 * var(--bs-gutter-y));\n margin-right: calc(-0.5 * var(--bs-gutter-x));\n margin-left: calc(-0.5 * var(--bs-gutter-x));\n}\n.row > * {\n box-sizing: border-box;\n flex-shrink: 0;\n width: 100%;\n max-width: 100%;\n padding-right: calc(var(--bs-gutter-x) * 0.5);\n padding-left: calc(var(--bs-gutter-x) * 0.5);\n margin-top: var(--bs-gutter-y);\n}\n\n.col {\n flex: 1 0 0%;\n}\n\n.row-cols-auto > * {\n flex: 0 0 auto;\n width: auto;\n}\n\n.row-cols-1 > * {\n flex: 0 0 auto;\n width: 100%;\n}\n\n.row-cols-2 > * {\n flex: 0 0 auto;\n width: 50%;\n}\n\n.row-cols-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n}\n\n.row-cols-4 > * {\n flex: 0 0 auto;\n width: 25%;\n}\n\n.row-cols-5 > * {\n flex: 0 0 auto;\n width: 20%;\n}\n\n.row-cols-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n}\n\n.col-auto {\n flex: 0 0 auto;\n width: auto;\n}\n\n.col-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n}\n\n.col-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n}\n\n.col-3 {\n flex: 0 0 auto;\n width: 25%;\n}\n\n.col-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n}\n\n.col-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n}\n\n.col-6 {\n flex: 0 0 auto;\n width: 50%;\n}\n\n.col-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n}\n\n.col-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n}\n\n.col-9 {\n flex: 0 0 auto;\n width: 75%;\n}\n\n.col-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n}\n\n.col-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n}\n\n.col-12 {\n flex: 0 0 auto;\n width: 100%;\n}\n\n.offset-1 {\n margin-left: 8.33333333%;\n}\n\n.offset-2 {\n margin-left: 16.66666667%;\n}\n\n.offset-3 {\n margin-left: 25%;\n}\n\n.offset-4 {\n margin-left: 33.33333333%;\n}\n\n.offset-5 {\n margin-left: 41.66666667%;\n}\n\n.offset-6 {\n margin-left: 50%;\n}\n\n.offset-7 {\n margin-left: 58.33333333%;\n}\n\n.offset-8 {\n margin-left: 66.66666667%;\n}\n\n.offset-9 {\n margin-left: 75%;\n}\n\n.offset-10 {\n margin-left: 83.33333333%;\n}\n\n.offset-11 {\n margin-left: 91.66666667%;\n}\n\n.g-0,\n.gx-0 {\n --bs-gutter-x: 0;\n}\n\n.g-0,\n.gy-0 {\n --bs-gutter-y: 0;\n}\n\n.g-1,\n.gx-1 {\n --bs-gutter-x: 0.25rem;\n}\n\n.g-1,\n.gy-1 {\n --bs-gutter-y: 0.25rem;\n}\n\n.g-2,\n.gx-2 {\n --bs-gutter-x: 0.5rem;\n}\n\n.g-2,\n.gy-2 {\n --bs-gutter-y: 0.5rem;\n}\n\n.g-3,\n.gx-3 {\n --bs-gutter-x: 1rem;\n}\n\n.g-3,\n.gy-3 {\n --bs-gutter-y: 1rem;\n}\n\n.g-4,\n.gx-4 {\n --bs-gutter-x: 1.5rem;\n}\n\n.g-4,\n.gy-4 {\n --bs-gutter-y: 1.5rem;\n}\n\n.g-5,\n.gx-5 {\n --bs-gutter-x: 3rem;\n}\n\n.g-5,\n.gy-5 {\n --bs-gutter-y: 3rem;\n}\n\n@media (min-width: 576px) {\n .col-sm {\n flex: 1 0 0%;\n }\n .row-cols-sm-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-sm-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-sm-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-sm-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-sm-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-sm-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-sm-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-sm-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-sm-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-sm-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-sm-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-sm-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-sm-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-sm-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-sm-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-sm-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-sm-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-sm-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-sm-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-sm-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-sm-0 {\n margin-left: 0;\n }\n .offset-sm-1 {\n margin-left: 8.33333333%;\n }\n .offset-sm-2 {\n margin-left: 16.66666667%;\n }\n .offset-sm-3 {\n margin-left: 25%;\n }\n .offset-sm-4 {\n margin-left: 33.33333333%;\n }\n .offset-sm-5 {\n margin-left: 41.66666667%;\n }\n .offset-sm-6 {\n margin-left: 50%;\n }\n .offset-sm-7 {\n margin-left: 58.33333333%;\n }\n .offset-sm-8 {\n margin-left: 66.66666667%;\n }\n .offset-sm-9 {\n margin-left: 75%;\n }\n .offset-sm-10 {\n margin-left: 83.33333333%;\n }\n .offset-sm-11 {\n margin-left: 91.66666667%;\n }\n .g-sm-0,\n .gx-sm-0 {\n --bs-gutter-x: 0;\n }\n .g-sm-0,\n .gy-sm-0 {\n --bs-gutter-y: 0;\n }\n .g-sm-1,\n .gx-sm-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-sm-1,\n .gy-sm-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-sm-2,\n .gx-sm-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-sm-2,\n .gy-sm-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-sm-3,\n .gx-sm-3 {\n --bs-gutter-x: 1rem;\n }\n .g-sm-3,\n .gy-sm-3 {\n --bs-gutter-y: 1rem;\n }\n .g-sm-4,\n .gx-sm-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-sm-4,\n .gy-sm-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-sm-5,\n .gx-sm-5 {\n --bs-gutter-x: 3rem;\n }\n .g-sm-5,\n .gy-sm-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 768px) {\n .col-md {\n flex: 1 0 0%;\n }\n .row-cols-md-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-md-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-md-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-md-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-md-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-md-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-md-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-md-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-md-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-md-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-md-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-md-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-md-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-md-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-md-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-md-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-md-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-md-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-md-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-md-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-md-0 {\n margin-left: 0;\n }\n .offset-md-1 {\n margin-left: 8.33333333%;\n }\n .offset-md-2 {\n margin-left: 16.66666667%;\n }\n .offset-md-3 {\n margin-left: 25%;\n }\n .offset-md-4 {\n margin-left: 33.33333333%;\n }\n .offset-md-5 {\n margin-left: 41.66666667%;\n }\n .offset-md-6 {\n margin-left: 50%;\n }\n .offset-md-7 {\n margin-left: 58.33333333%;\n }\n .offset-md-8 {\n margin-left: 66.66666667%;\n }\n .offset-md-9 {\n margin-left: 75%;\n }\n .offset-md-10 {\n margin-left: 83.33333333%;\n }\n .offset-md-11 {\n margin-left: 91.66666667%;\n }\n .g-md-0,\n .gx-md-0 {\n --bs-gutter-x: 0;\n }\n .g-md-0,\n .gy-md-0 {\n --bs-gutter-y: 0;\n }\n .g-md-1,\n .gx-md-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-md-1,\n .gy-md-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-md-2,\n .gx-md-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-md-2,\n .gy-md-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-md-3,\n .gx-md-3 {\n --bs-gutter-x: 1rem;\n }\n .g-md-3,\n .gy-md-3 {\n --bs-gutter-y: 1rem;\n }\n .g-md-4,\n .gx-md-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-md-4,\n .gy-md-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-md-5,\n .gx-md-5 {\n --bs-gutter-x: 3rem;\n }\n .g-md-5,\n .gy-md-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 992px) {\n .col-lg {\n flex: 1 0 0%;\n }\n .row-cols-lg-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-lg-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-lg-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-lg-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-lg-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-lg-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-lg-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-lg-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-lg-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-lg-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-lg-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-lg-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-lg-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-lg-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-lg-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-lg-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-lg-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-lg-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-lg-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-lg-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-lg-0 {\n margin-left: 0;\n }\n .offset-lg-1 {\n margin-left: 8.33333333%;\n }\n .offset-lg-2 {\n margin-left: 16.66666667%;\n }\n .offset-lg-3 {\n margin-left: 25%;\n }\n .offset-lg-4 {\n margin-left: 33.33333333%;\n }\n .offset-lg-5 {\n margin-left: 41.66666667%;\n }\n .offset-lg-6 {\n margin-left: 50%;\n }\n .offset-lg-7 {\n margin-left: 58.33333333%;\n }\n .offset-lg-8 {\n margin-left: 66.66666667%;\n }\n .offset-lg-9 {\n margin-left: 75%;\n }\n .offset-lg-10 {\n margin-left: 83.33333333%;\n }\n .offset-lg-11 {\n margin-left: 91.66666667%;\n }\n .g-lg-0,\n .gx-lg-0 {\n --bs-gutter-x: 0;\n }\n .g-lg-0,\n .gy-lg-0 {\n --bs-gutter-y: 0;\n }\n .g-lg-1,\n .gx-lg-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-lg-1,\n .gy-lg-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-lg-2,\n .gx-lg-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-lg-2,\n .gy-lg-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-lg-3,\n .gx-lg-3 {\n --bs-gutter-x: 1rem;\n }\n .g-lg-3,\n .gy-lg-3 {\n --bs-gutter-y: 1rem;\n }\n .g-lg-4,\n .gx-lg-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-lg-4,\n .gy-lg-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-lg-5,\n .gx-lg-5 {\n --bs-gutter-x: 3rem;\n }\n .g-lg-5,\n .gy-lg-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 1200px) {\n .col-xl {\n flex: 1 0 0%;\n }\n .row-cols-xl-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-xl-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-xl-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-xl-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-xl-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-xl-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-xl-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xl-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-xl-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-xl-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xl-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-xl-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-xl-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-xl-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-xl-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-xl-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-xl-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-xl-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-xl-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-xl-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-xl-0 {\n margin-left: 0;\n }\n .offset-xl-1 {\n margin-left: 8.33333333%;\n }\n .offset-xl-2 {\n margin-left: 16.66666667%;\n }\n .offset-xl-3 {\n margin-left: 25%;\n }\n .offset-xl-4 {\n margin-left: 33.33333333%;\n }\n .offset-xl-5 {\n margin-left: 41.66666667%;\n }\n .offset-xl-6 {\n margin-left: 50%;\n }\n .offset-xl-7 {\n margin-left: 58.33333333%;\n }\n .offset-xl-8 {\n margin-left: 66.66666667%;\n }\n .offset-xl-9 {\n margin-left: 75%;\n }\n .offset-xl-10 {\n margin-left: 83.33333333%;\n }\n .offset-xl-11 {\n margin-left: 91.66666667%;\n }\n .g-xl-0,\n .gx-xl-0 {\n --bs-gutter-x: 0;\n }\n .g-xl-0,\n .gy-xl-0 {\n --bs-gutter-y: 0;\n }\n .g-xl-1,\n .gx-xl-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-xl-1,\n .gy-xl-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-xl-2,\n .gx-xl-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-xl-2,\n .gy-xl-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-xl-3,\n .gx-xl-3 {\n --bs-gutter-x: 1rem;\n }\n .g-xl-3,\n .gy-xl-3 {\n --bs-gutter-y: 1rem;\n }\n .g-xl-4,\n .gx-xl-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-xl-4,\n .gy-xl-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-xl-5,\n .gx-xl-5 {\n --bs-gutter-x: 3rem;\n }\n .g-xl-5,\n .gy-xl-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 1400px) {\n .col-xxl {\n flex: 1 0 0%;\n }\n .row-cols-xxl-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-xxl-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-xxl-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-xxl-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-xxl-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-xxl-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-xxl-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xxl-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-xxl-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-xxl-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xxl-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-xxl-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-xxl-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-xxl-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-xxl-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-xxl-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-xxl-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-xxl-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-xxl-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-xxl-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-xxl-0 {\n margin-left: 0;\n }\n .offset-xxl-1 {\n margin-left: 8.33333333%;\n }\n .offset-xxl-2 {\n margin-left: 16.66666667%;\n }\n .offset-xxl-3 {\n margin-left: 25%;\n }\n .offset-xxl-4 {\n margin-left: 33.33333333%;\n }\n .offset-xxl-5 {\n margin-left: 41.66666667%;\n }\n .offset-xxl-6 {\n margin-left: 50%;\n }\n .offset-xxl-7 {\n margin-left: 58.33333333%;\n }\n .offset-xxl-8 {\n margin-left: 66.66666667%;\n }\n .offset-xxl-9 {\n margin-left: 75%;\n }\n .offset-xxl-10 {\n margin-left: 83.33333333%;\n }\n .offset-xxl-11 {\n margin-left: 91.66666667%;\n }\n .g-xxl-0,\n .gx-xxl-0 {\n --bs-gutter-x: 0;\n }\n .g-xxl-0,\n .gy-xxl-0 {\n --bs-gutter-y: 0;\n }\n .g-xxl-1,\n .gx-xxl-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-xxl-1,\n .gy-xxl-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-xxl-2,\n .gx-xxl-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-xxl-2,\n .gy-xxl-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-xxl-3,\n .gx-xxl-3 {\n --bs-gutter-x: 1rem;\n }\n .g-xxl-3,\n .gy-xxl-3 {\n --bs-gutter-y: 1rem;\n }\n .g-xxl-4,\n .gx-xxl-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-xxl-4,\n .gy-xxl-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-xxl-5,\n .gx-xxl-5 {\n --bs-gutter-x: 3rem;\n }\n .g-xxl-5,\n .gy-xxl-5 {\n --bs-gutter-y: 3rem;\n }\n}\n.d-inline {\n display: inline !important;\n}\n\n.d-inline-block {\n display: inline-block !important;\n}\n\n.d-block {\n display: block !important;\n}\n\n.d-grid {\n display: grid !important;\n}\n\n.d-inline-grid {\n display: inline-grid !important;\n}\n\n.d-table {\n display: table !important;\n}\n\n.d-table-row {\n display: table-row !important;\n}\n\n.d-table-cell {\n display: table-cell !important;\n}\n\n.d-flex {\n display: flex !important;\n}\n\n.d-inline-flex {\n display: inline-flex !important;\n}\n\n.d-none {\n display: none !important;\n}\n\n.flex-fill {\n flex: 1 1 auto !important;\n}\n\n.flex-row {\n flex-direction: row !important;\n}\n\n.flex-column {\n flex-direction: column !important;\n}\n\n.flex-row-reverse {\n flex-direction: row-reverse !important;\n}\n\n.flex-column-reverse {\n flex-direction: column-reverse !important;\n}\n\n.flex-grow-0 {\n flex-grow: 0 !important;\n}\n\n.flex-grow-1 {\n flex-grow: 1 !important;\n}\n\n.flex-shrink-0 {\n flex-shrink: 0 !important;\n}\n\n.flex-shrink-1 {\n flex-shrink: 1 !important;\n}\n\n.flex-wrap {\n flex-wrap: wrap !important;\n}\n\n.flex-nowrap {\n flex-wrap: nowrap !important;\n}\n\n.flex-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n}\n\n.justify-content-start {\n justify-content: flex-start !important;\n}\n\n.justify-content-end {\n justify-content: flex-end !important;\n}\n\n.justify-content-center {\n justify-content: center !important;\n}\n\n.justify-content-between {\n justify-content: space-between !important;\n}\n\n.justify-content-around {\n justify-content: space-around !important;\n}\n\n.justify-content-evenly {\n justify-content: space-evenly !important;\n}\n\n.align-items-start {\n align-items: flex-start !important;\n}\n\n.align-items-end {\n align-items: flex-end !important;\n}\n\n.align-items-center {\n align-items: center !important;\n}\n\n.align-items-baseline {\n align-items: baseline !important;\n}\n\n.align-items-stretch {\n align-items: stretch !important;\n}\n\n.align-content-start {\n align-content: flex-start !important;\n}\n\n.align-content-end {\n align-content: flex-end !important;\n}\n\n.align-content-center {\n align-content: center !important;\n}\n\n.align-content-between {\n align-content: space-between !important;\n}\n\n.align-content-around {\n align-content: space-around !important;\n}\n\n.align-content-stretch {\n align-content: stretch !important;\n}\n\n.align-self-auto {\n align-self: auto !important;\n}\n\n.align-self-start {\n align-self: flex-start !important;\n}\n\n.align-self-end {\n align-self: flex-end !important;\n}\n\n.align-self-center {\n align-self: center !important;\n}\n\n.align-self-baseline {\n align-self: baseline !important;\n}\n\n.align-self-stretch {\n align-self: stretch !important;\n}\n\n.order-first {\n order: -1 !important;\n}\n\n.order-0 {\n order: 0 !important;\n}\n\n.order-1 {\n order: 1 !important;\n}\n\n.order-2 {\n order: 2 !important;\n}\n\n.order-3 {\n order: 3 !important;\n}\n\n.order-4 {\n order: 4 !important;\n}\n\n.order-5 {\n order: 5 !important;\n}\n\n.order-last {\n order: 6 !important;\n}\n\n.m-0 {\n margin: 0 !important;\n}\n\n.m-1 {\n margin: 0.25rem !important;\n}\n\n.m-2 {\n margin: 0.5rem !important;\n}\n\n.m-3 {\n margin: 1rem !important;\n}\n\n.m-4 {\n margin: 1.5rem !important;\n}\n\n.m-5 {\n margin: 3rem !important;\n}\n\n.m-auto {\n margin: auto !important;\n}\n\n.mx-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n}\n\n.mx-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n}\n\n.mx-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n}\n\n.mx-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n}\n\n.mx-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n}\n\n.mx-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n}\n\n.mx-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n}\n\n.my-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n.my-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n}\n\n.my-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n}\n\n.my-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n}\n\n.my-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n}\n\n.my-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n}\n\n.my-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n}\n\n.mt-0 {\n margin-top: 0 !important;\n}\n\n.mt-1 {\n margin-top: 0.25rem !important;\n}\n\n.mt-2 {\n margin-top: 0.5rem !important;\n}\n\n.mt-3 {\n margin-top: 1rem !important;\n}\n\n.mt-4 {\n margin-top: 1.5rem !important;\n}\n\n.mt-5 {\n margin-top: 3rem !important;\n}\n\n.mt-auto {\n margin-top: auto !important;\n}\n\n.me-0 {\n margin-right: 0 !important;\n}\n\n.me-1 {\n margin-right: 0.25rem !important;\n}\n\n.me-2 {\n margin-right: 0.5rem !important;\n}\n\n.me-3 {\n margin-right: 1rem !important;\n}\n\n.me-4 {\n margin-right: 1.5rem !important;\n}\n\n.me-5 {\n margin-right: 3rem !important;\n}\n\n.me-auto {\n margin-right: auto !important;\n}\n\n.mb-0 {\n margin-bottom: 0 !important;\n}\n\n.mb-1 {\n margin-bottom: 0.25rem !important;\n}\n\n.mb-2 {\n margin-bottom: 0.5rem !important;\n}\n\n.mb-3 {\n margin-bottom: 1rem !important;\n}\n\n.mb-4 {\n margin-bottom: 1.5rem !important;\n}\n\n.mb-5 {\n margin-bottom: 3rem !important;\n}\n\n.mb-auto {\n margin-bottom: auto !important;\n}\n\n.ms-0 {\n margin-left: 0 !important;\n}\n\n.ms-1 {\n margin-left: 0.25rem !important;\n}\n\n.ms-2 {\n margin-left: 0.5rem !important;\n}\n\n.ms-3 {\n margin-left: 1rem !important;\n}\n\n.ms-4 {\n margin-left: 1.5rem !important;\n}\n\n.ms-5 {\n margin-left: 3rem !important;\n}\n\n.ms-auto {\n margin-left: auto !important;\n}\n\n.p-0 {\n padding: 0 !important;\n}\n\n.p-1 {\n padding: 0.25rem !important;\n}\n\n.p-2 {\n padding: 0.5rem !important;\n}\n\n.p-3 {\n padding: 1rem !important;\n}\n\n.p-4 {\n padding: 1.5rem !important;\n}\n\n.p-5 {\n padding: 3rem !important;\n}\n\n.px-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n}\n\n.px-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n}\n\n.px-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n}\n\n.px-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n}\n\n.px-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n}\n\n.px-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n}\n\n.py-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n}\n\n.py-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n}\n\n.py-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n}\n\n.py-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n}\n\n.py-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n}\n\n.py-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n}\n\n.pt-0 {\n padding-top: 0 !important;\n}\n\n.pt-1 {\n padding-top: 0.25rem !important;\n}\n\n.pt-2 {\n padding-top: 0.5rem !important;\n}\n\n.pt-3 {\n padding-top: 1rem !important;\n}\n\n.pt-4 {\n padding-top: 1.5rem !important;\n}\n\n.pt-5 {\n padding-top: 3rem !important;\n}\n\n.pe-0 {\n padding-right: 0 !important;\n}\n\n.pe-1 {\n padding-right: 0.25rem !important;\n}\n\n.pe-2 {\n padding-right: 0.5rem !important;\n}\n\n.pe-3 {\n padding-right: 1rem !important;\n}\n\n.pe-4 {\n padding-right: 1.5rem !important;\n}\n\n.pe-5 {\n padding-right: 3rem !important;\n}\n\n.pb-0 {\n padding-bottom: 0 !important;\n}\n\n.pb-1 {\n padding-bottom: 0.25rem !important;\n}\n\n.pb-2 {\n padding-bottom: 0.5rem !important;\n}\n\n.pb-3 {\n padding-bottom: 1rem !important;\n}\n\n.pb-4 {\n padding-bottom: 1.5rem !important;\n}\n\n.pb-5 {\n padding-bottom: 3rem !important;\n}\n\n.ps-0 {\n padding-left: 0 !important;\n}\n\n.ps-1 {\n padding-left: 0.25rem !important;\n}\n\n.ps-2 {\n padding-left: 0.5rem !important;\n}\n\n.ps-3 {\n padding-left: 1rem !important;\n}\n\n.ps-4 {\n padding-left: 1.5rem !important;\n}\n\n.ps-5 {\n padding-left: 3rem !important;\n}\n\n@media (min-width: 576px) {\n .d-sm-inline {\n display: inline !important;\n }\n .d-sm-inline-block {\n display: inline-block !important;\n }\n .d-sm-block {\n display: block !important;\n }\n .d-sm-grid {\n display: grid !important;\n }\n .d-sm-inline-grid {\n display: inline-grid !important;\n }\n .d-sm-table {\n display: table !important;\n }\n .d-sm-table-row {\n display: table-row !important;\n }\n .d-sm-table-cell {\n display: table-cell !important;\n }\n .d-sm-flex {\n display: flex !important;\n }\n .d-sm-inline-flex {\n display: inline-flex !important;\n }\n .d-sm-none {\n display: none !important;\n }\n .flex-sm-fill {\n flex: 1 1 auto !important;\n }\n .flex-sm-row {\n flex-direction: row !important;\n }\n .flex-sm-column {\n flex-direction: column !important;\n }\n .flex-sm-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-sm-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-sm-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-sm-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-sm-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-sm-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-sm-wrap {\n flex-wrap: wrap !important;\n }\n .flex-sm-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-sm-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-sm-start {\n justify-content: flex-start !important;\n }\n .justify-content-sm-end {\n justify-content: flex-end !important;\n }\n .justify-content-sm-center {\n justify-content: center !important;\n }\n .justify-content-sm-between {\n justify-content: space-between !important;\n }\n .justify-content-sm-around {\n justify-content: space-around !important;\n }\n .justify-content-sm-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-sm-start {\n align-items: flex-start !important;\n }\n .align-items-sm-end {\n align-items: flex-end !important;\n }\n .align-items-sm-center {\n align-items: center !important;\n }\n .align-items-sm-baseline {\n align-items: baseline !important;\n }\n .align-items-sm-stretch {\n align-items: stretch !important;\n }\n .align-content-sm-start {\n align-content: flex-start !important;\n }\n .align-content-sm-end {\n align-content: flex-end !important;\n }\n .align-content-sm-center {\n align-content: center !important;\n }\n .align-content-sm-between {\n align-content: space-between !important;\n }\n .align-content-sm-around {\n align-content: space-around !important;\n }\n .align-content-sm-stretch {\n align-content: stretch !important;\n }\n .align-self-sm-auto {\n align-self: auto !important;\n }\n .align-self-sm-start {\n align-self: flex-start !important;\n }\n .align-self-sm-end {\n align-self: flex-end !important;\n }\n .align-self-sm-center {\n align-self: center !important;\n }\n .align-self-sm-baseline {\n align-self: baseline !important;\n }\n .align-self-sm-stretch {\n align-self: stretch !important;\n }\n .order-sm-first {\n order: -1 !important;\n }\n .order-sm-0 {\n order: 0 !important;\n }\n .order-sm-1 {\n order: 1 !important;\n }\n .order-sm-2 {\n order: 2 !important;\n }\n .order-sm-3 {\n order: 3 !important;\n }\n .order-sm-4 {\n order: 4 !important;\n }\n .order-sm-5 {\n order: 5 !important;\n }\n .order-sm-last {\n order: 6 !important;\n }\n .m-sm-0 {\n margin: 0 !important;\n }\n .m-sm-1 {\n margin: 0.25rem !important;\n }\n .m-sm-2 {\n margin: 0.5rem !important;\n }\n .m-sm-3 {\n margin: 1rem !important;\n }\n .m-sm-4 {\n margin: 1.5rem !important;\n }\n .m-sm-5 {\n margin: 3rem !important;\n }\n .m-sm-auto {\n margin: auto !important;\n }\n .mx-sm-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-sm-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-sm-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-sm-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-sm-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-sm-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-sm-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-sm-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-sm-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-sm-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-sm-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-sm-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-sm-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-sm-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-sm-0 {\n margin-top: 0 !important;\n }\n .mt-sm-1 {\n margin-top: 0.25rem !important;\n }\n .mt-sm-2 {\n margin-top: 0.5rem !important;\n }\n .mt-sm-3 {\n margin-top: 1rem !important;\n }\n .mt-sm-4 {\n margin-top: 1.5rem !important;\n }\n .mt-sm-5 {\n margin-top: 3rem !important;\n }\n .mt-sm-auto {\n margin-top: auto !important;\n }\n .me-sm-0 {\n margin-right: 0 !important;\n }\n .me-sm-1 {\n margin-right: 0.25rem !important;\n }\n .me-sm-2 {\n margin-right: 0.5rem !important;\n }\n .me-sm-3 {\n margin-right: 1rem !important;\n }\n .me-sm-4 {\n margin-right: 1.5rem !important;\n }\n .me-sm-5 {\n margin-right: 3rem !important;\n }\n .me-sm-auto {\n margin-right: auto !important;\n }\n .mb-sm-0 {\n margin-bottom: 0 !important;\n }\n .mb-sm-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-sm-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-sm-3 {\n margin-bottom: 1rem !important;\n }\n .mb-sm-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-sm-5 {\n margin-bottom: 3rem !important;\n }\n .mb-sm-auto {\n margin-bottom: auto !important;\n }\n .ms-sm-0 {\n margin-left: 0 !important;\n }\n .ms-sm-1 {\n margin-left: 0.25rem !important;\n }\n .ms-sm-2 {\n margin-left: 0.5rem !important;\n }\n .ms-sm-3 {\n margin-left: 1rem !important;\n }\n .ms-sm-4 {\n margin-left: 1.5rem !important;\n }\n .ms-sm-5 {\n margin-left: 3rem !important;\n }\n .ms-sm-auto {\n margin-left: auto !important;\n }\n .p-sm-0 {\n padding: 0 !important;\n }\n .p-sm-1 {\n padding: 0.25rem !important;\n }\n .p-sm-2 {\n padding: 0.5rem !important;\n }\n .p-sm-3 {\n padding: 1rem !important;\n }\n .p-sm-4 {\n padding: 1.5rem !important;\n }\n .p-sm-5 {\n padding: 3rem !important;\n }\n .px-sm-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-sm-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-sm-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-sm-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-sm-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-sm-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-sm-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-sm-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-sm-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-sm-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-sm-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-sm-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-sm-0 {\n padding-top: 0 !important;\n }\n .pt-sm-1 {\n padding-top: 0.25rem !important;\n }\n .pt-sm-2 {\n padding-top: 0.5rem !important;\n }\n .pt-sm-3 {\n padding-top: 1rem !important;\n }\n .pt-sm-4 {\n padding-top: 1.5rem !important;\n }\n .pt-sm-5 {\n padding-top: 3rem !important;\n }\n .pe-sm-0 {\n padding-right: 0 !important;\n }\n .pe-sm-1 {\n padding-right: 0.25rem !important;\n }\n .pe-sm-2 {\n padding-right: 0.5rem !important;\n }\n .pe-sm-3 {\n padding-right: 1rem !important;\n }\n .pe-sm-4 {\n padding-right: 1.5rem !important;\n }\n .pe-sm-5 {\n padding-right: 3rem !important;\n }\n .pb-sm-0 {\n padding-bottom: 0 !important;\n }\n .pb-sm-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-sm-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-sm-3 {\n padding-bottom: 1rem !important;\n }\n .pb-sm-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-sm-5 {\n padding-bottom: 3rem !important;\n }\n .ps-sm-0 {\n padding-left: 0 !important;\n }\n .ps-sm-1 {\n padding-left: 0.25rem !important;\n }\n .ps-sm-2 {\n padding-left: 0.5rem !important;\n }\n .ps-sm-3 {\n padding-left: 1rem !important;\n }\n .ps-sm-4 {\n padding-left: 1.5rem !important;\n }\n .ps-sm-5 {\n padding-left: 3rem !important;\n }\n}\n@media (min-width: 768px) {\n .d-md-inline {\n display: inline !important;\n }\n .d-md-inline-block {\n display: inline-block !important;\n }\n .d-md-block {\n display: block !important;\n }\n .d-md-grid {\n display: grid !important;\n }\n .d-md-inline-grid {\n display: inline-grid !important;\n }\n .d-md-table {\n display: table !important;\n }\n .d-md-table-row {\n display: table-row !important;\n }\n .d-md-table-cell {\n display: table-cell !important;\n }\n .d-md-flex {\n display: flex !important;\n }\n .d-md-inline-flex {\n display: inline-flex !important;\n }\n .d-md-none {\n display: none !important;\n }\n .flex-md-fill {\n flex: 1 1 auto !important;\n }\n .flex-md-row {\n flex-direction: row !important;\n }\n .flex-md-column {\n flex-direction: column !important;\n }\n .flex-md-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-md-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-md-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-md-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-md-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-md-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-md-wrap {\n flex-wrap: wrap !important;\n }\n .flex-md-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-md-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-md-start {\n justify-content: flex-start !important;\n }\n .justify-content-md-end {\n justify-content: flex-end !important;\n }\n .justify-content-md-center {\n justify-content: center !important;\n }\n .justify-content-md-between {\n justify-content: space-between !important;\n }\n .justify-content-md-around {\n justify-content: space-around !important;\n }\n .justify-content-md-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-md-start {\n align-items: flex-start !important;\n }\n .align-items-md-end {\n align-items: flex-end !important;\n }\n .align-items-md-center {\n align-items: center !important;\n }\n .align-items-md-baseline {\n align-items: baseline !important;\n }\n .align-items-md-stretch {\n align-items: stretch !important;\n }\n .align-content-md-start {\n align-content: flex-start !important;\n }\n .align-content-md-end {\n align-content: flex-end !important;\n }\n .align-content-md-center {\n align-content: center !important;\n }\n .align-content-md-between {\n align-content: space-between !important;\n }\n .align-content-md-around {\n align-content: space-around !important;\n }\n .align-content-md-stretch {\n align-content: stretch !important;\n }\n .align-self-md-auto {\n align-self: auto !important;\n }\n .align-self-md-start {\n align-self: flex-start !important;\n }\n .align-self-md-end {\n align-self: flex-end !important;\n }\n .align-self-md-center {\n align-self: center !important;\n }\n .align-self-md-baseline {\n align-self: baseline !important;\n }\n .align-self-md-stretch {\n align-self: stretch !important;\n }\n .order-md-first {\n order: -1 !important;\n }\n .order-md-0 {\n order: 0 !important;\n }\n .order-md-1 {\n order: 1 !important;\n }\n .order-md-2 {\n order: 2 !important;\n }\n .order-md-3 {\n order: 3 !important;\n }\n .order-md-4 {\n order: 4 !important;\n }\n .order-md-5 {\n order: 5 !important;\n }\n .order-md-last {\n order: 6 !important;\n }\n .m-md-0 {\n margin: 0 !important;\n }\n .m-md-1 {\n margin: 0.25rem !important;\n }\n .m-md-2 {\n margin: 0.5rem !important;\n }\n .m-md-3 {\n margin: 1rem !important;\n }\n .m-md-4 {\n margin: 1.5rem !important;\n }\n .m-md-5 {\n margin: 3rem !important;\n }\n .m-md-auto {\n margin: auto !important;\n }\n .mx-md-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-md-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-md-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-md-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-md-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-md-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-md-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-md-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-md-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-md-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-md-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-md-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-md-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-md-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-md-0 {\n margin-top: 0 !important;\n }\n .mt-md-1 {\n margin-top: 0.25rem !important;\n }\n .mt-md-2 {\n margin-top: 0.5rem !important;\n }\n .mt-md-3 {\n margin-top: 1rem !important;\n }\n .mt-md-4 {\n margin-top: 1.5rem !important;\n }\n .mt-md-5 {\n margin-top: 3rem !important;\n }\n .mt-md-auto {\n margin-top: auto !important;\n }\n .me-md-0 {\n margin-right: 0 !important;\n }\n .me-md-1 {\n margin-right: 0.25rem !important;\n }\n .me-md-2 {\n margin-right: 0.5rem !important;\n }\n .me-md-3 {\n margin-right: 1rem !important;\n }\n .me-md-4 {\n margin-right: 1.5rem !important;\n }\n .me-md-5 {\n margin-right: 3rem !important;\n }\n .me-md-auto {\n margin-right: auto !important;\n }\n .mb-md-0 {\n margin-bottom: 0 !important;\n }\n .mb-md-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-md-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-md-3 {\n margin-bottom: 1rem !important;\n }\n .mb-md-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-md-5 {\n margin-bottom: 3rem !important;\n }\n .mb-md-auto {\n margin-bottom: auto !important;\n }\n .ms-md-0 {\n margin-left: 0 !important;\n }\n .ms-md-1 {\n margin-left: 0.25rem !important;\n }\n .ms-md-2 {\n margin-left: 0.5rem !important;\n }\n .ms-md-3 {\n margin-left: 1rem !important;\n }\n .ms-md-4 {\n margin-left: 1.5rem !important;\n }\n .ms-md-5 {\n margin-left: 3rem !important;\n }\n .ms-md-auto {\n margin-left: auto !important;\n }\n .p-md-0 {\n padding: 0 !important;\n }\n .p-md-1 {\n padding: 0.25rem !important;\n }\n .p-md-2 {\n padding: 0.5rem !important;\n }\n .p-md-3 {\n padding: 1rem !important;\n }\n .p-md-4 {\n padding: 1.5rem !important;\n }\n .p-md-5 {\n padding: 3rem !important;\n }\n .px-md-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-md-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-md-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-md-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-md-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-md-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-md-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-md-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-md-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-md-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-md-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-md-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-md-0 {\n padding-top: 0 !important;\n }\n .pt-md-1 {\n padding-top: 0.25rem !important;\n }\n .pt-md-2 {\n padding-top: 0.5rem !important;\n }\n .pt-md-3 {\n padding-top: 1rem !important;\n }\n .pt-md-4 {\n padding-top: 1.5rem !important;\n }\n .pt-md-5 {\n padding-top: 3rem !important;\n }\n .pe-md-0 {\n padding-right: 0 !important;\n }\n .pe-md-1 {\n padding-right: 0.25rem !important;\n }\n .pe-md-2 {\n padding-right: 0.5rem !important;\n }\n .pe-md-3 {\n padding-right: 1rem !important;\n }\n .pe-md-4 {\n padding-right: 1.5rem !important;\n }\n .pe-md-5 {\n padding-right: 3rem !important;\n }\n .pb-md-0 {\n padding-bottom: 0 !important;\n }\n .pb-md-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-md-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-md-3 {\n padding-bottom: 1rem !important;\n }\n .pb-md-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-md-5 {\n padding-bottom: 3rem !important;\n }\n .ps-md-0 {\n padding-left: 0 !important;\n }\n .ps-md-1 {\n padding-left: 0.25rem !important;\n }\n .ps-md-2 {\n padding-left: 0.5rem !important;\n }\n .ps-md-3 {\n padding-left: 1rem !important;\n }\n .ps-md-4 {\n padding-left: 1.5rem !important;\n }\n .ps-md-5 {\n padding-left: 3rem !important;\n }\n}\n@media (min-width: 992px) {\n .d-lg-inline {\n display: inline !important;\n }\n .d-lg-inline-block {\n display: inline-block !important;\n }\n .d-lg-block {\n display: block !important;\n }\n .d-lg-grid {\n display: grid !important;\n }\n .d-lg-inline-grid {\n display: inline-grid !important;\n }\n .d-lg-table {\n display: table !important;\n }\n .d-lg-table-row {\n display: table-row !important;\n }\n .d-lg-table-cell {\n display: table-cell !important;\n }\n .d-lg-flex {\n display: flex !important;\n }\n .d-lg-inline-flex {\n display: inline-flex !important;\n }\n .d-lg-none {\n display: none !important;\n }\n .flex-lg-fill {\n flex: 1 1 auto !important;\n }\n .flex-lg-row {\n flex-direction: row !important;\n }\n .flex-lg-column {\n flex-direction: column !important;\n }\n .flex-lg-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-lg-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-lg-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-lg-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-lg-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-lg-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-lg-wrap {\n flex-wrap: wrap !important;\n }\n .flex-lg-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-lg-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-lg-start {\n justify-content: flex-start !important;\n }\n .justify-content-lg-end {\n justify-content: flex-end !important;\n }\n .justify-content-lg-center {\n justify-content: center !important;\n }\n .justify-content-lg-between {\n justify-content: space-between !important;\n }\n .justify-content-lg-around {\n justify-content: space-around !important;\n }\n .justify-content-lg-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-lg-start {\n align-items: flex-start !important;\n }\n .align-items-lg-end {\n align-items: flex-end !important;\n }\n .align-items-lg-center {\n align-items: center !important;\n }\n .align-items-lg-baseline {\n align-items: baseline !important;\n }\n .align-items-lg-stretch {\n align-items: stretch !important;\n }\n .align-content-lg-start {\n align-content: flex-start !important;\n }\n .align-content-lg-end {\n align-content: flex-end !important;\n }\n .align-content-lg-center {\n align-content: center !important;\n }\n .align-content-lg-between {\n align-content: space-between !important;\n }\n .align-content-lg-around {\n align-content: space-around !important;\n }\n .align-content-lg-stretch {\n align-content: stretch !important;\n }\n .align-self-lg-auto {\n align-self: auto !important;\n }\n .align-self-lg-start {\n align-self: flex-start !important;\n }\n .align-self-lg-end {\n align-self: flex-end !important;\n }\n .align-self-lg-center {\n align-self: center !important;\n }\n .align-self-lg-baseline {\n align-self: baseline !important;\n }\n .align-self-lg-stretch {\n align-self: stretch !important;\n }\n .order-lg-first {\n order: -1 !important;\n }\n .order-lg-0 {\n order: 0 !important;\n }\n .order-lg-1 {\n order: 1 !important;\n }\n .order-lg-2 {\n order: 2 !important;\n }\n .order-lg-3 {\n order: 3 !important;\n }\n .order-lg-4 {\n order: 4 !important;\n }\n .order-lg-5 {\n order: 5 !important;\n }\n .order-lg-last {\n order: 6 !important;\n }\n .m-lg-0 {\n margin: 0 !important;\n }\n .m-lg-1 {\n margin: 0.25rem !important;\n }\n .m-lg-2 {\n margin: 0.5rem !important;\n }\n .m-lg-3 {\n margin: 1rem !important;\n }\n .m-lg-4 {\n margin: 1.5rem !important;\n }\n .m-lg-5 {\n margin: 3rem !important;\n }\n .m-lg-auto {\n margin: auto !important;\n }\n .mx-lg-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-lg-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-lg-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-lg-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-lg-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-lg-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-lg-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-lg-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-lg-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-lg-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-lg-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-lg-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-lg-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-lg-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-lg-0 {\n margin-top: 0 !important;\n }\n .mt-lg-1 {\n margin-top: 0.25rem !important;\n }\n .mt-lg-2 {\n margin-top: 0.5rem !important;\n }\n .mt-lg-3 {\n margin-top: 1rem !important;\n }\n .mt-lg-4 {\n margin-top: 1.5rem !important;\n }\n .mt-lg-5 {\n margin-top: 3rem !important;\n }\n .mt-lg-auto {\n margin-top: auto !important;\n }\n .me-lg-0 {\n margin-right: 0 !important;\n }\n .me-lg-1 {\n margin-right: 0.25rem !important;\n }\n .me-lg-2 {\n margin-right: 0.5rem !important;\n }\n .me-lg-3 {\n margin-right: 1rem !important;\n }\n .me-lg-4 {\n margin-right: 1.5rem !important;\n }\n .me-lg-5 {\n margin-right: 3rem !important;\n }\n .me-lg-auto {\n margin-right: auto !important;\n }\n .mb-lg-0 {\n margin-bottom: 0 !important;\n }\n .mb-lg-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-lg-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-lg-3 {\n margin-bottom: 1rem !important;\n }\n .mb-lg-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-lg-5 {\n margin-bottom: 3rem !important;\n }\n .mb-lg-auto {\n margin-bottom: auto !important;\n }\n .ms-lg-0 {\n margin-left: 0 !important;\n }\n .ms-lg-1 {\n margin-left: 0.25rem !important;\n }\n .ms-lg-2 {\n margin-left: 0.5rem !important;\n }\n .ms-lg-3 {\n margin-left: 1rem !important;\n }\n .ms-lg-4 {\n margin-left: 1.5rem !important;\n }\n .ms-lg-5 {\n margin-left: 3rem !important;\n }\n .ms-lg-auto {\n margin-left: auto !important;\n }\n .p-lg-0 {\n padding: 0 !important;\n }\n .p-lg-1 {\n padding: 0.25rem !important;\n }\n .p-lg-2 {\n padding: 0.5rem !important;\n }\n .p-lg-3 {\n padding: 1rem !important;\n }\n .p-lg-4 {\n padding: 1.5rem !important;\n }\n .p-lg-5 {\n padding: 3rem !important;\n }\n .px-lg-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-lg-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-lg-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-lg-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-lg-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-lg-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-lg-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-lg-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-lg-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-lg-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-lg-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-lg-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-lg-0 {\n padding-top: 0 !important;\n }\n .pt-lg-1 {\n padding-top: 0.25rem !important;\n }\n .pt-lg-2 {\n padding-top: 0.5rem !important;\n }\n .pt-lg-3 {\n padding-top: 1rem !important;\n }\n .pt-lg-4 {\n padding-top: 1.5rem !important;\n }\n .pt-lg-5 {\n padding-top: 3rem !important;\n }\n .pe-lg-0 {\n padding-right: 0 !important;\n }\n .pe-lg-1 {\n padding-right: 0.25rem !important;\n }\n .pe-lg-2 {\n padding-right: 0.5rem !important;\n }\n .pe-lg-3 {\n padding-right: 1rem !important;\n }\n .pe-lg-4 {\n padding-right: 1.5rem !important;\n }\n .pe-lg-5 {\n padding-right: 3rem !important;\n }\n .pb-lg-0 {\n padding-bottom: 0 !important;\n }\n .pb-lg-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-lg-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-lg-3 {\n padding-bottom: 1rem !important;\n }\n .pb-lg-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-lg-5 {\n padding-bottom: 3rem !important;\n }\n .ps-lg-0 {\n padding-left: 0 !important;\n }\n .ps-lg-1 {\n padding-left: 0.25rem !important;\n }\n .ps-lg-2 {\n padding-left: 0.5rem !important;\n }\n .ps-lg-3 {\n padding-left: 1rem !important;\n }\n .ps-lg-4 {\n padding-left: 1.5rem !important;\n }\n .ps-lg-5 {\n padding-left: 3rem !important;\n }\n}\n@media (min-width: 1200px) {\n .d-xl-inline {\n display: inline !important;\n }\n .d-xl-inline-block {\n display: inline-block !important;\n }\n .d-xl-block {\n display: block !important;\n }\n .d-xl-grid {\n display: grid !important;\n }\n .d-xl-inline-grid {\n display: inline-grid !important;\n }\n .d-xl-table {\n display: table !important;\n }\n .d-xl-table-row {\n display: table-row !important;\n }\n .d-xl-table-cell {\n display: table-cell !important;\n }\n .d-xl-flex {\n display: flex !important;\n }\n .d-xl-inline-flex {\n display: inline-flex !important;\n }\n .d-xl-none {\n display: none !important;\n }\n .flex-xl-fill {\n flex: 1 1 auto !important;\n }\n .flex-xl-row {\n flex-direction: row !important;\n }\n .flex-xl-column {\n flex-direction: column !important;\n }\n .flex-xl-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-xl-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-xl-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-xl-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-xl-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-xl-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-xl-wrap {\n flex-wrap: wrap !important;\n }\n .flex-xl-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-xl-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-xl-start {\n justify-content: flex-start !important;\n }\n .justify-content-xl-end {\n justify-content: flex-end !important;\n }\n .justify-content-xl-center {\n justify-content: center !important;\n }\n .justify-content-xl-between {\n justify-content: space-between !important;\n }\n .justify-content-xl-around {\n justify-content: space-around !important;\n }\n .justify-content-xl-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-xl-start {\n align-items: flex-start !important;\n }\n .align-items-xl-end {\n align-items: flex-end !important;\n }\n .align-items-xl-center {\n align-items: center !important;\n }\n .align-items-xl-baseline {\n align-items: baseline !important;\n }\n .align-items-xl-stretch {\n align-items: stretch !important;\n }\n .align-content-xl-start {\n align-content: flex-start !important;\n }\n .align-content-xl-end {\n align-content: flex-end !important;\n }\n .align-content-xl-center {\n align-content: center !important;\n }\n .align-content-xl-between {\n align-content: space-between !important;\n }\n .align-content-xl-around {\n align-content: space-around !important;\n }\n .align-content-xl-stretch {\n align-content: stretch !important;\n }\n .align-self-xl-auto {\n align-self: auto !important;\n }\n .align-self-xl-start {\n align-self: flex-start !important;\n }\n .align-self-xl-end {\n align-self: flex-end !important;\n }\n .align-self-xl-center {\n align-self: center !important;\n }\n .align-self-xl-baseline {\n align-self: baseline !important;\n }\n .align-self-xl-stretch {\n align-self: stretch !important;\n }\n .order-xl-first {\n order: -1 !important;\n }\n .order-xl-0 {\n order: 0 !important;\n }\n .order-xl-1 {\n order: 1 !important;\n }\n .order-xl-2 {\n order: 2 !important;\n }\n .order-xl-3 {\n order: 3 !important;\n }\n .order-xl-4 {\n order: 4 !important;\n }\n .order-xl-5 {\n order: 5 !important;\n }\n .order-xl-last {\n order: 6 !important;\n }\n .m-xl-0 {\n margin: 0 !important;\n }\n .m-xl-1 {\n margin: 0.25rem !important;\n }\n .m-xl-2 {\n margin: 0.5rem !important;\n }\n .m-xl-3 {\n margin: 1rem !important;\n }\n .m-xl-4 {\n margin: 1.5rem !important;\n }\n .m-xl-5 {\n margin: 3rem !important;\n }\n .m-xl-auto {\n margin: auto !important;\n }\n .mx-xl-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-xl-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-xl-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-xl-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-xl-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-xl-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-xl-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-xl-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-xl-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-xl-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-xl-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-xl-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-xl-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-xl-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-xl-0 {\n margin-top: 0 !important;\n }\n .mt-xl-1 {\n margin-top: 0.25rem !important;\n }\n .mt-xl-2 {\n margin-top: 0.5rem !important;\n }\n .mt-xl-3 {\n margin-top: 1rem !important;\n }\n .mt-xl-4 {\n margin-top: 1.5rem !important;\n }\n .mt-xl-5 {\n margin-top: 3rem !important;\n }\n .mt-xl-auto {\n margin-top: auto !important;\n }\n .me-xl-0 {\n margin-right: 0 !important;\n }\n .me-xl-1 {\n margin-right: 0.25rem !important;\n }\n .me-xl-2 {\n margin-right: 0.5rem !important;\n }\n .me-xl-3 {\n margin-right: 1rem !important;\n }\n .me-xl-4 {\n margin-right: 1.5rem !important;\n }\n .me-xl-5 {\n margin-right: 3rem !important;\n }\n .me-xl-auto {\n margin-right: auto !important;\n }\n .mb-xl-0 {\n margin-bottom: 0 !important;\n }\n .mb-xl-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-xl-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-xl-3 {\n margin-bottom: 1rem !important;\n }\n .mb-xl-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-xl-5 {\n margin-bottom: 3rem !important;\n }\n .mb-xl-auto {\n margin-bottom: auto !important;\n }\n .ms-xl-0 {\n margin-left: 0 !important;\n }\n .ms-xl-1 {\n margin-left: 0.25rem !important;\n }\n .ms-xl-2 {\n margin-left: 0.5rem !important;\n }\n .ms-xl-3 {\n margin-left: 1rem !important;\n }\n .ms-xl-4 {\n margin-left: 1.5rem !important;\n }\n .ms-xl-5 {\n margin-left: 3rem !important;\n }\n .ms-xl-auto {\n margin-left: auto !important;\n }\n .p-xl-0 {\n padding: 0 !important;\n }\n .p-xl-1 {\n padding: 0.25rem !important;\n }\n .p-xl-2 {\n padding: 0.5rem !important;\n }\n .p-xl-3 {\n padding: 1rem !important;\n }\n .p-xl-4 {\n padding: 1.5rem !important;\n }\n .p-xl-5 {\n padding: 3rem !important;\n }\n .px-xl-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-xl-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-xl-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-xl-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-xl-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-xl-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-xl-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-xl-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-xl-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-xl-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-xl-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-xl-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-xl-0 {\n padding-top: 0 !important;\n }\n .pt-xl-1 {\n padding-top: 0.25rem !important;\n }\n .pt-xl-2 {\n padding-top: 0.5rem !important;\n }\n .pt-xl-3 {\n padding-top: 1rem !important;\n }\n .pt-xl-4 {\n padding-top: 1.5rem !important;\n }\n .pt-xl-5 {\n padding-top: 3rem !important;\n }\n .pe-xl-0 {\n padding-right: 0 !important;\n }\n .pe-xl-1 {\n padding-right: 0.25rem !important;\n }\n .pe-xl-2 {\n padding-right: 0.5rem !important;\n }\n .pe-xl-3 {\n padding-right: 1rem !important;\n }\n .pe-xl-4 {\n padding-right: 1.5rem !important;\n }\n .pe-xl-5 {\n padding-right: 3rem !important;\n }\n .pb-xl-0 {\n padding-bottom: 0 !important;\n }\n .pb-xl-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-xl-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-xl-3 {\n padding-bottom: 1rem !important;\n }\n .pb-xl-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-xl-5 {\n padding-bottom: 3rem !important;\n }\n .ps-xl-0 {\n padding-left: 0 !important;\n }\n .ps-xl-1 {\n padding-left: 0.25rem !important;\n }\n .ps-xl-2 {\n padding-left: 0.5rem !important;\n }\n .ps-xl-3 {\n padding-left: 1rem !important;\n }\n .ps-xl-4 {\n padding-left: 1.5rem !important;\n }\n .ps-xl-5 {\n padding-left: 3rem !important;\n }\n}\n@media (min-width: 1400px) {\n .d-xxl-inline {\n display: inline !important;\n }\n .d-xxl-inline-block {\n display: inline-block !important;\n }\n .d-xxl-block {\n display: block !important;\n }\n .d-xxl-grid {\n display: grid !important;\n }\n .d-xxl-inline-grid {\n display: inline-grid !important;\n }\n .d-xxl-table {\n display: table !important;\n }\n .d-xxl-table-row {\n display: table-row !important;\n }\n .d-xxl-table-cell {\n display: table-cell !important;\n }\n .d-xxl-flex {\n display: flex !important;\n }\n .d-xxl-inline-flex {\n display: inline-flex !important;\n }\n .d-xxl-none {\n display: none !important;\n }\n .flex-xxl-fill {\n flex: 1 1 auto !important;\n }\n .flex-xxl-row {\n flex-direction: row !important;\n }\n .flex-xxl-column {\n flex-direction: column !important;\n }\n .flex-xxl-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-xxl-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-xxl-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-xxl-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-xxl-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-xxl-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-xxl-wrap {\n flex-wrap: wrap !important;\n }\n .flex-xxl-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-xxl-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-xxl-start {\n justify-content: flex-start !important;\n }\n .justify-content-xxl-end {\n justify-content: flex-end !important;\n }\n .justify-content-xxl-center {\n justify-content: center !important;\n }\n .justify-content-xxl-between {\n justify-content: space-between !important;\n }\n .justify-content-xxl-around {\n justify-content: space-around !important;\n }\n .justify-content-xxl-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-xxl-start {\n align-items: flex-start !important;\n }\n .align-items-xxl-end {\n align-items: flex-end !important;\n }\n .align-items-xxl-center {\n align-items: center !important;\n }\n .align-items-xxl-baseline {\n align-items: baseline !important;\n }\n .align-items-xxl-stretch {\n align-items: stretch !important;\n }\n .align-content-xxl-start {\n align-content: flex-start !important;\n }\n .align-content-xxl-end {\n align-content: flex-end !important;\n }\n .align-content-xxl-center {\n align-content: center !important;\n }\n .align-content-xxl-between {\n align-content: space-between !important;\n }\n .align-content-xxl-around {\n align-content: space-around !important;\n }\n .align-content-xxl-stretch {\n align-content: stretch !important;\n }\n .align-self-xxl-auto {\n align-self: auto !important;\n }\n .align-self-xxl-start {\n align-self: flex-start !important;\n }\n .align-self-xxl-end {\n align-self: flex-end !important;\n }\n .align-self-xxl-center {\n align-self: center !important;\n }\n .align-self-xxl-baseline {\n align-self: baseline !important;\n }\n .align-self-xxl-stretch {\n align-self: stretch !important;\n }\n .order-xxl-first {\n order: -1 !important;\n }\n .order-xxl-0 {\n order: 0 !important;\n }\n .order-xxl-1 {\n order: 1 !important;\n }\n .order-xxl-2 {\n order: 2 !important;\n }\n .order-xxl-3 {\n order: 3 !important;\n }\n .order-xxl-4 {\n order: 4 !important;\n }\n .order-xxl-5 {\n order: 5 !important;\n }\n .order-xxl-last {\n order: 6 !important;\n }\n .m-xxl-0 {\n margin: 0 !important;\n }\n .m-xxl-1 {\n margin: 0.25rem !important;\n }\n .m-xxl-2 {\n margin: 0.5rem !important;\n }\n .m-xxl-3 {\n margin: 1rem !important;\n }\n .m-xxl-4 {\n margin: 1.5rem !important;\n }\n .m-xxl-5 {\n margin: 3rem !important;\n }\n .m-xxl-auto {\n margin: auto !important;\n }\n .mx-xxl-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-xxl-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-xxl-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-xxl-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-xxl-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-xxl-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-xxl-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-xxl-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-xxl-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-xxl-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-xxl-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-xxl-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-xxl-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-xxl-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-xxl-0 {\n margin-top: 0 !important;\n }\n .mt-xxl-1 {\n margin-top: 0.25rem !important;\n }\n .mt-xxl-2 {\n margin-top: 0.5rem !important;\n }\n .mt-xxl-3 {\n margin-top: 1rem !important;\n }\n .mt-xxl-4 {\n margin-top: 1.5rem !important;\n }\n .mt-xxl-5 {\n margin-top: 3rem !important;\n }\n .mt-xxl-auto {\n margin-top: auto !important;\n }\n .me-xxl-0 {\n margin-right: 0 !important;\n }\n .me-xxl-1 {\n margin-right: 0.25rem !important;\n }\n .me-xxl-2 {\n margin-right: 0.5rem !important;\n }\n .me-xxl-3 {\n margin-right: 1rem !important;\n }\n .me-xxl-4 {\n margin-right: 1.5rem !important;\n }\n .me-xxl-5 {\n margin-right: 3rem !important;\n }\n .me-xxl-auto {\n margin-right: auto !important;\n }\n .mb-xxl-0 {\n margin-bottom: 0 !important;\n }\n .mb-xxl-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-xxl-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-xxl-3 {\n margin-bottom: 1rem !important;\n }\n .mb-xxl-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-xxl-5 {\n margin-bottom: 3rem !important;\n }\n .mb-xxl-auto {\n margin-bottom: auto !important;\n }\n .ms-xxl-0 {\n margin-left: 0 !important;\n }\n .ms-xxl-1 {\n margin-left: 0.25rem !important;\n }\n .ms-xxl-2 {\n margin-left: 0.5rem !important;\n }\n .ms-xxl-3 {\n margin-left: 1rem !important;\n }\n .ms-xxl-4 {\n margin-left: 1.5rem !important;\n }\n .ms-xxl-5 {\n margin-left: 3rem !important;\n }\n .ms-xxl-auto {\n margin-left: auto !important;\n }\n .p-xxl-0 {\n padding: 0 !important;\n }\n .p-xxl-1 {\n padding: 0.25rem !important;\n }\n .p-xxl-2 {\n padding: 0.5rem !important;\n }\n .p-xxl-3 {\n padding: 1rem !important;\n }\n .p-xxl-4 {\n padding: 1.5rem !important;\n }\n .p-xxl-5 {\n padding: 3rem !important;\n }\n .px-xxl-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-xxl-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-xxl-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-xxl-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-xxl-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-xxl-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-xxl-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-xxl-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-xxl-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-xxl-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-xxl-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-xxl-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-xxl-0 {\n padding-top: 0 !important;\n }\n .pt-xxl-1 {\n padding-top: 0.25rem !important;\n }\n .pt-xxl-2 {\n padding-top: 0.5rem !important;\n }\n .pt-xxl-3 {\n padding-top: 1rem !important;\n }\n .pt-xxl-4 {\n padding-top: 1.5rem !important;\n }\n .pt-xxl-5 {\n padding-top: 3rem !important;\n }\n .pe-xxl-0 {\n padding-right: 0 !important;\n }\n .pe-xxl-1 {\n padding-right: 0.25rem !important;\n }\n .pe-xxl-2 {\n padding-right: 0.5rem !important;\n }\n .pe-xxl-3 {\n padding-right: 1rem !important;\n }\n .pe-xxl-4 {\n padding-right: 1.5rem !important;\n }\n .pe-xxl-5 {\n padding-right: 3rem !important;\n }\n .pb-xxl-0 {\n padding-bottom: 0 !important;\n }\n .pb-xxl-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-xxl-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-xxl-3 {\n padding-bottom: 1rem !important;\n }\n .pb-xxl-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-xxl-5 {\n padding-bottom: 3rem !important;\n }\n .ps-xxl-0 {\n padding-left: 0 !important;\n }\n .ps-xxl-1 {\n padding-left: 0.25rem !important;\n }\n .ps-xxl-2 {\n padding-left: 0.5rem !important;\n }\n .ps-xxl-3 {\n padding-left: 1rem !important;\n }\n .ps-xxl-4 {\n padding-left: 1.5rem !important;\n }\n .ps-xxl-5 {\n padding-left: 3rem !important;\n }\n}\n@media print {\n .d-print-inline {\n display: inline !important;\n }\n .d-print-inline-block {\n display: inline-block !important;\n }\n .d-print-block {\n display: block !important;\n }\n .d-print-grid {\n display: grid !important;\n }\n .d-print-inline-grid {\n display: inline-grid !important;\n }\n .d-print-table {\n display: table !important;\n }\n .d-print-table-row {\n display: table-row !important;\n }\n .d-print-table-cell {\n display: table-cell !important;\n }\n .d-print-flex {\n display: flex !important;\n }\n .d-print-inline-flex {\n display: inline-flex !important;\n }\n .d-print-none {\n display: none !important;\n }\n}\n\n/*# sourceMappingURL=bootstrap-grid.css.map */","// Container mixins\n\n@mixin make-container($gutter: $container-padding-x) {\n --#{$prefix}gutter-x: #{$gutter};\n --#{$prefix}gutter-y: 0;\n width: 100%;\n padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n margin-right: auto;\n margin-left: auto;\n}\n","// Breakpoint viewport sizes and media queries.\n//\n// Breakpoints are defined as a map of (name: minimum width), order from small to large:\n//\n// (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)\n//\n// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default.\n\n// Name of the next breakpoint, or null for the last breakpoint.\n//\n// >> breakpoint-next(sm)\n// md\n// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// md\n// >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl xxl))\n// md\n@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) {\n $n: index($breakpoint-names, $name);\n @if not $n {\n @error \"breakpoint `#{$name}` not found in `#{$breakpoints}`\";\n }\n @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null);\n}\n\n// Minimum breakpoint width. Null for the smallest (first) breakpoint.\n//\n// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// 576px\n@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {\n $min: map-get($breakpoints, $name);\n @return if($min != 0, $min, null);\n}\n\n// Maximum breakpoint width.\n// The maximum value is reduced by 0.02px to work around the limitations of\n// `min-` and `max-` prefixes and viewports with fractional widths.\n// See https://www.w3.org/TR/mediaqueries-4/#mq-min-max\n// Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari.\n// See https://bugs.webkit.org/show_bug.cgi?id=178261\n//\n// >> breakpoint-max(md, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// 767.98px\n@function breakpoint-max($name, $breakpoints: $grid-breakpoints) {\n $max: map-get($breakpoints, $name);\n @return if($max and $max > 0, $max - .02, null);\n}\n\n// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front.\n// Useful for making responsive utilities.\n//\n// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// \"\" (Returns a blank string)\n// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// \"-sm\"\n@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) {\n @return if(breakpoint-min($name, $breakpoints) == null, \"\", \"-#{$name}\");\n}\n\n// Media of at least the minimum breakpoint width. No query for the smallest breakpoint.\n// Makes the @content apply to the given breakpoint and wider.\n@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($name, $breakpoints);\n @if $min {\n @media (min-width: $min) {\n @content;\n }\n } @else {\n @content;\n }\n}\n\n// Media of at most the maximum breakpoint width. No query for the largest breakpoint.\n// Makes the @content apply to the given breakpoint and narrower.\n@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) {\n $max: breakpoint-max($name, $breakpoints);\n @if $max {\n @media (max-width: $max) {\n @content;\n }\n } @else {\n @content;\n }\n}\n\n// Media that spans multiple breakpoint widths.\n// Makes the @content apply between the min and max breakpoints\n@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($lower, $breakpoints);\n $max: breakpoint-max($upper, $breakpoints);\n\n @if $min != null and $max != null {\n @media (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else if $max == null {\n @include media-breakpoint-up($lower, $breakpoints) {\n @content;\n }\n } @else if $min == null {\n @include media-breakpoint-down($upper, $breakpoints) {\n @content;\n }\n }\n}\n\n// Media between the breakpoint's minimum and maximum widths.\n// No minimum for the smallest breakpoint, and no maximum for the largest one.\n// Makes the @content apply only to the given breakpoint, not viewports any wider or narrower.\n@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($name, $breakpoints);\n $next: breakpoint-next($name, $breakpoints);\n $max: breakpoint-max($next, $breakpoints);\n\n @if $min != null and $max != null {\n @media (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else if $max == null {\n @include media-breakpoint-up($name, $breakpoints) {\n @content;\n }\n } @else if $min == null {\n @include media-breakpoint-down($next, $breakpoints) {\n @content;\n }\n }\n}\n","// Row\n//\n// Rows contain your columns.\n\n:root {\n @each $name, $value in $grid-breakpoints {\n --#{$prefix}breakpoint-#{$name}: #{$value};\n }\n}\n\n@if $enable-grid-classes {\n .row {\n @include make-row();\n\n > * {\n @include make-col-ready();\n }\n }\n}\n\n@if $enable-cssgrid {\n .grid {\n display: grid;\n grid-template-rows: repeat(var(--#{$prefix}rows, 1), 1fr);\n grid-template-columns: repeat(var(--#{$prefix}columns, #{$grid-columns}), 1fr);\n gap: var(--#{$prefix}gap, #{$grid-gutter-width});\n\n @include make-cssgrid();\n }\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n@if $enable-grid-classes {\n @include make-grid-columns();\n}\n","// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n@mixin make-row($gutter: $grid-gutter-width) {\n --#{$prefix}gutter-x: #{$gutter};\n --#{$prefix}gutter-y: 0;\n display: flex;\n flex-wrap: wrap;\n // TODO: Revisit calc order after https://github.com/react-bootstrap/react-bootstrap/issues/6039 is fixed\n margin-top: calc(-1 * var(--#{$prefix}gutter-y)); // stylelint-disable-line function-disallowed-list\n margin-right: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list\n margin-left: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list\n}\n\n@mixin make-col-ready() {\n // Add box sizing if only the grid is loaded\n box-sizing: if(variable-exists(include-column-box-sizing) and $include-column-box-sizing, border-box, null);\n // Prevent columns from becoming too narrow when at smaller grid tiers by\n // always setting `width: 100%;`. This works because we set the width\n // later on to override this initial width.\n flex-shrink: 0;\n width: 100%;\n max-width: 100%; // Prevent `.col-auto`, `.col` (& responsive variants) from breaking out the grid\n padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n margin-top: var(--#{$prefix}gutter-y);\n}\n\n@mixin make-col($size: false, $columns: $grid-columns) {\n @if $size {\n flex: 0 0 auto;\n width: percentage(divide($size, $columns));\n\n } @else {\n flex: 1 1 0;\n max-width: 100%;\n }\n}\n\n@mixin make-col-auto() {\n flex: 0 0 auto;\n width: auto;\n}\n\n@mixin make-col-offset($size, $columns: $grid-columns) {\n $num: divide($size, $columns);\n margin-left: if($num == 0, 0, percentage($num));\n}\n\n// Row columns\n//\n// Specify on a parent element(e.g., .row) to force immediate children into NN\n// number of columns. Supports wrapping to new lines, but does not do a Masonry\n// style grid.\n@mixin row-cols($count) {\n > * {\n flex: 0 0 auto;\n width: percentage(divide(1, $count));\n }\n}\n\n// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `$grid-columns`.\n\n@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) {\n @each $breakpoint in map-keys($breakpoints) {\n $infix: breakpoint-infix($breakpoint, $breakpoints);\n\n @include media-breakpoint-up($breakpoint, $breakpoints) {\n // Provide basic `.col-{bp}` classes for equal-width flexbox columns\n .col#{$infix} {\n flex: 1 0 0%; // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4\n }\n\n .row-cols#{$infix}-auto > * {\n @include make-col-auto();\n }\n\n @if $grid-row-columns > 0 {\n @for $i from 1 through $grid-row-columns {\n .row-cols#{$infix}-#{$i} {\n @include row-cols($i);\n }\n }\n }\n\n .col#{$infix}-auto {\n @include make-col-auto();\n }\n\n @if $columns > 0 {\n @for $i from 1 through $columns {\n .col#{$infix}-#{$i} {\n @include make-col($i, $columns);\n }\n }\n\n // `$columns - 1` because offsetting by the width of an entire row isn't possible\n @for $i from 0 through ($columns - 1) {\n @if not ($infix == \"\" and $i == 0) { // Avoid emitting useless .offset-0\n .offset#{$infix}-#{$i} {\n @include make-col-offset($i, $columns);\n }\n }\n }\n }\n\n // Gutters\n //\n // Make use of `.g-*`, `.gx-*` or `.gy-*` utilities to change spacing between the columns.\n @each $key, $value in $gutters {\n .g#{$infix}-#{$key},\n .gx#{$infix}-#{$key} {\n --#{$prefix}gutter-x: #{$value};\n }\n\n .g#{$infix}-#{$key},\n .gy#{$infix}-#{$key} {\n --#{$prefix}gutter-y: #{$value};\n }\n }\n }\n }\n}\n\n@mixin make-cssgrid($columns: $grid-columns, $breakpoints: $grid-breakpoints) {\n @each $breakpoint in map-keys($breakpoints) {\n $infix: breakpoint-infix($breakpoint, $breakpoints);\n\n @include media-breakpoint-up($breakpoint, $breakpoints) {\n @if $columns > 0 {\n @for $i from 1 through $columns {\n .g-col#{$infix}-#{$i} {\n grid-column: auto / span $i;\n }\n }\n\n // Start with `1` because `0` is an invalid value.\n // Ends with `$columns - 1` because offsetting by the width of an entire row isn't possible.\n @for $i from 1 through ($columns - 1) {\n .g-start#{$infix}-#{$i} {\n grid-column-start: $i;\n }\n }\n }\n }\n }\n}\n","// Utility generator\n// Used to generate utilities & print utilities\n@mixin generate-utility($utility, $infix: \"\", $is-rfs-media-query: false) {\n $values: map-get($utility, values);\n\n // If the values are a list or string, convert it into a map\n @if type-of($values) == \"string\" or type-of(nth($values, 1)) != \"list\" {\n $values: zip($values, $values);\n }\n\n @each $key, $value in $values {\n $properties: map-get($utility, property);\n\n // Multiple properties are possible, for example with vertical or horizontal margins or paddings\n @if type-of($properties) == \"string\" {\n $properties: append((), $properties);\n }\n\n // Use custom class if present\n $property-class: if(map-has-key($utility, class), map-get($utility, class), nth($properties, 1));\n $property-class: if($property-class == null, \"\", $property-class);\n\n // Use custom CSS variable name if present, otherwise default to `class`\n $css-variable-name: if(map-has-key($utility, css-variable-name), map-get($utility, css-variable-name), map-get($utility, class));\n\n // State params to generate pseudo-classes\n $state: if(map-has-key($utility, state), map-get($utility, state), ());\n\n $infix: if($property-class == \"\" and str-slice($infix, 1, 1) == \"-\", str-slice($infix, 2), $infix);\n\n // Don't prefix if value key is null (e.g. with shadow class)\n $property-class-modifier: if($key, if($property-class == \"\" and $infix == \"\", \"\", \"-\") + $key, \"\");\n\n @if map-get($utility, rfs) {\n // Inside the media query\n @if $is-rfs-media-query {\n $val: rfs-value($value);\n\n // Do not render anything if fluid and non fluid values are the same\n $value: if($val == rfs-fluid-value($value), null, $val);\n }\n @else {\n $value: rfs-fluid-value($value);\n }\n }\n\n $is-css-var: map-get($utility, css-var);\n $is-local-vars: map-get($utility, local-vars);\n $is-rtl: map-get($utility, rtl);\n\n @if $value != null {\n @if $is-rtl == false {\n /* rtl:begin:remove */\n }\n\n @if $is-css-var {\n .#{$property-class + $infix + $property-class-modifier} {\n --#{$prefix}#{$css-variable-name}: #{$value};\n }\n\n @each $pseudo in $state {\n .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {\n --#{$prefix}#{$css-variable-name}: #{$value};\n }\n }\n } @else {\n .#{$property-class + $infix + $property-class-modifier} {\n @each $property in $properties {\n @if $is-local-vars {\n @each $local-var, $variable in $is-local-vars {\n --#{$prefix}#{$local-var}: #{$variable};\n }\n }\n #{$property}: $value if($enable-important-utilities, !important, null);\n }\n }\n\n @each $pseudo in $state {\n .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {\n @each $property in $properties {\n @if $is-local-vars {\n @each $local-var, $variable in $is-local-vars {\n --#{$prefix}#{$local-var}: #{$variable};\n }\n }\n #{$property}: $value if($enable-important-utilities, !important, null);\n }\n }\n }\n }\n\n @if $is-rtl == false {\n /* rtl:end:remove */\n }\n }\n }\n}\n","// Loop over each breakpoint\n@each $breakpoint in map-keys($grid-breakpoints) {\n\n // Generate media query if needed\n @include media-breakpoint-up($breakpoint) {\n $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\n\n // Loop over each utility property\n @each $key, $utility in $utilities {\n // The utility can be disabled with `false`, thus check if the utility is a map first\n // Only proceed if responsive media queries are enabled or if it's the base media query\n @if type-of($utility) == \"map\" and (map-get($utility, responsive) or $infix == \"\") {\n @include generate-utility($utility, $infix);\n }\n }\n }\n}\n\n// RFS rescaling\n@media (min-width: $rfs-mq-value) {\n @each $breakpoint in map-keys($grid-breakpoints) {\n $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\n\n @if (map-get($grid-breakpoints, $breakpoint) < $rfs-breakpoint) {\n // Loop over each utility property\n @each $key, $utility in $utilities {\n // The utility can be disabled with `false`, thus check if the utility is a map first\n // Only proceed if responsive media queries are enabled or if it's the base media query\n @if type-of($utility) == \"map\" and map-get($utility, rfs) and (map-get($utility, responsive) or $infix == \"\") {\n @include generate-utility($utility, $infix, true);\n }\n }\n }\n }\n}\n\n\n// Print utilities\n@media print {\n @each $key, $utility in $utilities {\n // The utility can be disabled with `false`, thus check if the utility is a map first\n // Then check if the utility needs print styles\n @if type-of($utility) == \"map\" and map-get($utility, print) == true {\n @include generate-utility($utility, \"-print\");\n }\n }\n}\n"]} \ No newline at end of file diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css new file mode 100644 index 0000000..1a5d656 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css @@ -0,0 +1,4084 @@ +/*! + * Bootstrap Grid v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +.container, +.container-fluid, +.container-xxl, +.container-xl, +.container-lg, +.container-md, +.container-sm { + --bs-gutter-x: 1.5rem; + --bs-gutter-y: 0; + width: 100%; + padding-left: calc(var(--bs-gutter-x) * 0.5); + padding-right: calc(var(--bs-gutter-x) * 0.5); + margin-left: auto; + margin-right: auto; +} + +@media (min-width: 576px) { + .container-sm, .container { + max-width: 540px; + } +} +@media (min-width: 768px) { + .container-md, .container-sm, .container { + max-width: 720px; + } +} +@media (min-width: 992px) { + .container-lg, .container-md, .container-sm, .container { + max-width: 960px; + } +} +@media (min-width: 1200px) { + .container-xl, .container-lg, .container-md, .container-sm, .container { + max-width: 1140px; + } +} +@media (min-width: 1400px) { + .container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container { + max-width: 1320px; + } +} +:root { + --bs-breakpoint-xs: 0; + --bs-breakpoint-sm: 576px; + --bs-breakpoint-md: 768px; + --bs-breakpoint-lg: 992px; + --bs-breakpoint-xl: 1200px; + --bs-breakpoint-xxl: 1400px; +} + +.row { + --bs-gutter-x: 1.5rem; + --bs-gutter-y: 0; + display: flex; + flex-wrap: wrap; + margin-top: calc(-1 * var(--bs-gutter-y)); + margin-left: calc(-0.5 * var(--bs-gutter-x)); + margin-right: calc(-0.5 * var(--bs-gutter-x)); +} +.row > * { + box-sizing: border-box; + flex-shrink: 0; + width: 100%; + max-width: 100%; + padding-left: calc(var(--bs-gutter-x) * 0.5); + padding-right: calc(var(--bs-gutter-x) * 0.5); + margin-top: var(--bs-gutter-y); +} + +.col { + flex: 1 0 0%; +} + +.row-cols-auto > * { + flex: 0 0 auto; + width: auto; +} + +.row-cols-1 > * { + flex: 0 0 auto; + width: 100%; +} + +.row-cols-2 > * { + flex: 0 0 auto; + width: 50%; +} + +.row-cols-3 > * { + flex: 0 0 auto; + width: 33.33333333%; +} + +.row-cols-4 > * { + flex: 0 0 auto; + width: 25%; +} + +.row-cols-5 > * { + flex: 0 0 auto; + width: 20%; +} + +.row-cols-6 > * { + flex: 0 0 auto; + width: 16.66666667%; +} + +.col-auto { + flex: 0 0 auto; + width: auto; +} + +.col-1 { + flex: 0 0 auto; + width: 8.33333333%; +} + +.col-2 { + flex: 0 0 auto; + width: 16.66666667%; +} + +.col-3 { + flex: 0 0 auto; + width: 25%; +} + +.col-4 { + flex: 0 0 auto; + width: 33.33333333%; +} + +.col-5 { + flex: 0 0 auto; + width: 41.66666667%; +} + +.col-6 { + flex: 0 0 auto; + width: 50%; +} + +.col-7 { + flex: 0 0 auto; + width: 58.33333333%; +} + +.col-8 { + flex: 0 0 auto; + width: 66.66666667%; +} + +.col-9 { + flex: 0 0 auto; + width: 75%; +} + +.col-10 { + flex: 0 0 auto; + width: 83.33333333%; +} + +.col-11 { + flex: 0 0 auto; + width: 91.66666667%; +} + +.col-12 { + flex: 0 0 auto; + width: 100%; +} + +.offset-1 { + margin-right: 8.33333333%; +} + +.offset-2 { + margin-right: 16.66666667%; +} + +.offset-3 { + margin-right: 25%; +} + +.offset-4 { + margin-right: 33.33333333%; +} + +.offset-5 { + margin-right: 41.66666667%; +} + +.offset-6 { + margin-right: 50%; +} + +.offset-7 { + margin-right: 58.33333333%; +} + +.offset-8 { + margin-right: 66.66666667%; +} + +.offset-9 { + margin-right: 75%; +} + +.offset-10 { + margin-right: 83.33333333%; +} + +.offset-11 { + margin-right: 91.66666667%; +} + +.g-0, +.gx-0 { + --bs-gutter-x: 0; +} + +.g-0, +.gy-0 { + --bs-gutter-y: 0; +} + +.g-1, +.gx-1 { + --bs-gutter-x: 0.25rem; +} + +.g-1, +.gy-1 { + --bs-gutter-y: 0.25rem; +} + +.g-2, +.gx-2 { + --bs-gutter-x: 0.5rem; +} + +.g-2, +.gy-2 { + --bs-gutter-y: 0.5rem; +} + +.g-3, +.gx-3 { + --bs-gutter-x: 1rem; +} + +.g-3, +.gy-3 { + --bs-gutter-y: 1rem; +} + +.g-4, +.gx-4 { + --bs-gutter-x: 1.5rem; +} + +.g-4, +.gy-4 { + --bs-gutter-y: 1.5rem; +} + +.g-5, +.gx-5 { + --bs-gutter-x: 3rem; +} + +.g-5, +.gy-5 { + --bs-gutter-y: 3rem; +} + +@media (min-width: 576px) { + .col-sm { + flex: 1 0 0%; + } + .row-cols-sm-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-sm-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-sm-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-sm-3 > * { + flex: 0 0 auto; + width: 33.33333333%; + } + .row-cols-sm-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-sm-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-sm-6 > * { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-sm-auto { + flex: 0 0 auto; + width: auto; + } + .col-sm-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-sm-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-sm-3 { + flex: 0 0 auto; + width: 25%; + } + .col-sm-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-sm-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-sm-6 { + flex: 0 0 auto; + width: 50%; + } + .col-sm-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-sm-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-sm-9 { + flex: 0 0 auto; + width: 75%; + } + .col-sm-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-sm-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-sm-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-sm-0 { + margin-right: 0; + } + .offset-sm-1 { + margin-right: 8.33333333%; + } + .offset-sm-2 { + margin-right: 16.66666667%; + } + .offset-sm-3 { + margin-right: 25%; + } + .offset-sm-4 { + margin-right: 33.33333333%; + } + .offset-sm-5 { + margin-right: 41.66666667%; + } + .offset-sm-6 { + margin-right: 50%; + } + .offset-sm-7 { + margin-right: 58.33333333%; + } + .offset-sm-8 { + margin-right: 66.66666667%; + } + .offset-sm-9 { + margin-right: 75%; + } + .offset-sm-10 { + margin-right: 83.33333333%; + } + .offset-sm-11 { + margin-right: 91.66666667%; + } + .g-sm-0, + .gx-sm-0 { + --bs-gutter-x: 0; + } + .g-sm-0, + .gy-sm-0 { + --bs-gutter-y: 0; + } + .g-sm-1, + .gx-sm-1 { + --bs-gutter-x: 0.25rem; + } + .g-sm-1, + .gy-sm-1 { + --bs-gutter-y: 0.25rem; + } + .g-sm-2, + .gx-sm-2 { + --bs-gutter-x: 0.5rem; + } + .g-sm-2, + .gy-sm-2 { + --bs-gutter-y: 0.5rem; + } + .g-sm-3, + .gx-sm-3 { + --bs-gutter-x: 1rem; + } + .g-sm-3, + .gy-sm-3 { + --bs-gutter-y: 1rem; + } + .g-sm-4, + .gx-sm-4 { + --bs-gutter-x: 1.5rem; + } + .g-sm-4, + .gy-sm-4 { + --bs-gutter-y: 1.5rem; + } + .g-sm-5, + .gx-sm-5 { + --bs-gutter-x: 3rem; + } + .g-sm-5, + .gy-sm-5 { + --bs-gutter-y: 3rem; + } +} +@media (min-width: 768px) { + .col-md { + flex: 1 0 0%; + } + .row-cols-md-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-md-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-md-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-md-3 > * { + flex: 0 0 auto; + width: 33.33333333%; + } + .row-cols-md-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-md-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-md-6 > * { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-md-auto { + flex: 0 0 auto; + width: auto; + } + .col-md-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-md-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-md-3 { + flex: 0 0 auto; + width: 25%; + } + .col-md-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-md-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-md-6 { + flex: 0 0 auto; + width: 50%; + } + .col-md-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-md-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-md-9 { + flex: 0 0 auto; + width: 75%; + } + .col-md-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-md-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-md-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-md-0 { + margin-right: 0; + } + .offset-md-1 { + margin-right: 8.33333333%; + } + .offset-md-2 { + margin-right: 16.66666667%; + } + .offset-md-3 { + margin-right: 25%; + } + .offset-md-4 { + margin-right: 33.33333333%; + } + .offset-md-5 { + margin-right: 41.66666667%; + } + .offset-md-6 { + margin-right: 50%; + } + .offset-md-7 { + margin-right: 58.33333333%; + } + .offset-md-8 { + margin-right: 66.66666667%; + } + .offset-md-9 { + margin-right: 75%; + } + .offset-md-10 { + margin-right: 83.33333333%; + } + .offset-md-11 { + margin-right: 91.66666667%; + } + .g-md-0, + .gx-md-0 { + --bs-gutter-x: 0; + } + .g-md-0, + .gy-md-0 { + --bs-gutter-y: 0; + } + .g-md-1, + .gx-md-1 { + --bs-gutter-x: 0.25rem; + } + .g-md-1, + .gy-md-1 { + --bs-gutter-y: 0.25rem; + } + .g-md-2, + .gx-md-2 { + --bs-gutter-x: 0.5rem; + } + .g-md-2, + .gy-md-2 { + --bs-gutter-y: 0.5rem; + } + .g-md-3, + .gx-md-3 { + --bs-gutter-x: 1rem; + } + .g-md-3, + .gy-md-3 { + --bs-gutter-y: 1rem; + } + .g-md-4, + .gx-md-4 { + --bs-gutter-x: 1.5rem; + } + .g-md-4, + .gy-md-4 { + --bs-gutter-y: 1.5rem; + } + .g-md-5, + .gx-md-5 { + --bs-gutter-x: 3rem; + } + .g-md-5, + .gy-md-5 { + --bs-gutter-y: 3rem; + } +} +@media (min-width: 992px) { + .col-lg { + flex: 1 0 0%; + } + .row-cols-lg-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-lg-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-lg-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-lg-3 > * { + flex: 0 0 auto; + width: 33.33333333%; + } + .row-cols-lg-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-lg-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-lg-6 > * { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-lg-auto { + flex: 0 0 auto; + width: auto; + } + .col-lg-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-lg-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-lg-3 { + flex: 0 0 auto; + width: 25%; + } + .col-lg-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-lg-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-lg-6 { + flex: 0 0 auto; + width: 50%; + } + .col-lg-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-lg-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-lg-9 { + flex: 0 0 auto; + width: 75%; + } + .col-lg-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-lg-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-lg-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-lg-0 { + margin-right: 0; + } + .offset-lg-1 { + margin-right: 8.33333333%; + } + .offset-lg-2 { + margin-right: 16.66666667%; + } + .offset-lg-3 { + margin-right: 25%; + } + .offset-lg-4 { + margin-right: 33.33333333%; + } + .offset-lg-5 { + margin-right: 41.66666667%; + } + .offset-lg-6 { + margin-right: 50%; + } + .offset-lg-7 { + margin-right: 58.33333333%; + } + .offset-lg-8 { + margin-right: 66.66666667%; + } + .offset-lg-9 { + margin-right: 75%; + } + .offset-lg-10 { + margin-right: 83.33333333%; + } + .offset-lg-11 { + margin-right: 91.66666667%; + } + .g-lg-0, + .gx-lg-0 { + --bs-gutter-x: 0; + } + .g-lg-0, + .gy-lg-0 { + --bs-gutter-y: 0; + } + .g-lg-1, + .gx-lg-1 { + --bs-gutter-x: 0.25rem; + } + .g-lg-1, + .gy-lg-1 { + --bs-gutter-y: 0.25rem; + } + .g-lg-2, + .gx-lg-2 { + --bs-gutter-x: 0.5rem; + } + .g-lg-2, + .gy-lg-2 { + --bs-gutter-y: 0.5rem; + } + .g-lg-3, + .gx-lg-3 { + --bs-gutter-x: 1rem; + } + .g-lg-3, + .gy-lg-3 { + --bs-gutter-y: 1rem; + } + .g-lg-4, + .gx-lg-4 { + --bs-gutter-x: 1.5rem; + } + .g-lg-4, + .gy-lg-4 { + --bs-gutter-y: 1.5rem; + } + .g-lg-5, + .gx-lg-5 { + --bs-gutter-x: 3rem; + } + .g-lg-5, + .gy-lg-5 { + --bs-gutter-y: 3rem; + } +} +@media (min-width: 1200px) { + .col-xl { + flex: 1 0 0%; + } + .row-cols-xl-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-xl-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-xl-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-xl-3 > * { + flex: 0 0 auto; + width: 33.33333333%; + } + .row-cols-xl-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-xl-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-xl-6 > * { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-xl-auto { + flex: 0 0 auto; + width: auto; + } + .col-xl-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-xl-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-xl-3 { + flex: 0 0 auto; + width: 25%; + } + .col-xl-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-xl-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-xl-6 { + flex: 0 0 auto; + width: 50%; + } + .col-xl-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-xl-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-xl-9 { + flex: 0 0 auto; + width: 75%; + } + .col-xl-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-xl-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-xl-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-xl-0 { + margin-right: 0; + } + .offset-xl-1 { + margin-right: 8.33333333%; + } + .offset-xl-2 { + margin-right: 16.66666667%; + } + .offset-xl-3 { + margin-right: 25%; + } + .offset-xl-4 { + margin-right: 33.33333333%; + } + .offset-xl-5 { + margin-right: 41.66666667%; + } + .offset-xl-6 { + margin-right: 50%; + } + .offset-xl-7 { + margin-right: 58.33333333%; + } + .offset-xl-8 { + margin-right: 66.66666667%; + } + .offset-xl-9 { + margin-right: 75%; + } + .offset-xl-10 { + margin-right: 83.33333333%; + } + .offset-xl-11 { + margin-right: 91.66666667%; + } + .g-xl-0, + .gx-xl-0 { + --bs-gutter-x: 0; + } + .g-xl-0, + .gy-xl-0 { + --bs-gutter-y: 0; + } + .g-xl-1, + .gx-xl-1 { + --bs-gutter-x: 0.25rem; + } + .g-xl-1, + .gy-xl-1 { + --bs-gutter-y: 0.25rem; + } + .g-xl-2, + .gx-xl-2 { + --bs-gutter-x: 0.5rem; + } + .g-xl-2, + .gy-xl-2 { + --bs-gutter-y: 0.5rem; + } + .g-xl-3, + .gx-xl-3 { + --bs-gutter-x: 1rem; + } + .g-xl-3, + .gy-xl-3 { + --bs-gutter-y: 1rem; + } + .g-xl-4, + .gx-xl-4 { + --bs-gutter-x: 1.5rem; + } + .g-xl-4, + .gy-xl-4 { + --bs-gutter-y: 1.5rem; + } + .g-xl-5, + .gx-xl-5 { + --bs-gutter-x: 3rem; + } + .g-xl-5, + .gy-xl-5 { + --bs-gutter-y: 3rem; + } +} +@media (min-width: 1400px) { + .col-xxl { + flex: 1 0 0%; + } + .row-cols-xxl-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-xxl-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-xxl-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-xxl-3 > * { + flex: 0 0 auto; + width: 33.33333333%; + } + .row-cols-xxl-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-xxl-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-xxl-6 > * { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-xxl-auto { + flex: 0 0 auto; + width: auto; + } + .col-xxl-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-xxl-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-xxl-3 { + flex: 0 0 auto; + width: 25%; + } + .col-xxl-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-xxl-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-xxl-6 { + flex: 0 0 auto; + width: 50%; + } + .col-xxl-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-xxl-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-xxl-9 { + flex: 0 0 auto; + width: 75%; + } + .col-xxl-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-xxl-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-xxl-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-xxl-0 { + margin-right: 0; + } + .offset-xxl-1 { + margin-right: 8.33333333%; + } + .offset-xxl-2 { + margin-right: 16.66666667%; + } + .offset-xxl-3 { + margin-right: 25%; + } + .offset-xxl-4 { + margin-right: 33.33333333%; + } + .offset-xxl-5 { + margin-right: 41.66666667%; + } + .offset-xxl-6 { + margin-right: 50%; + } + .offset-xxl-7 { + margin-right: 58.33333333%; + } + .offset-xxl-8 { + margin-right: 66.66666667%; + } + .offset-xxl-9 { + margin-right: 75%; + } + .offset-xxl-10 { + margin-right: 83.33333333%; + } + .offset-xxl-11 { + margin-right: 91.66666667%; + } + .g-xxl-0, + .gx-xxl-0 { + --bs-gutter-x: 0; + } + .g-xxl-0, + .gy-xxl-0 { + --bs-gutter-y: 0; + } + .g-xxl-1, + .gx-xxl-1 { + --bs-gutter-x: 0.25rem; + } + .g-xxl-1, + .gy-xxl-1 { + --bs-gutter-y: 0.25rem; + } + .g-xxl-2, + .gx-xxl-2 { + --bs-gutter-x: 0.5rem; + } + .g-xxl-2, + .gy-xxl-2 { + --bs-gutter-y: 0.5rem; + } + .g-xxl-3, + .gx-xxl-3 { + --bs-gutter-x: 1rem; + } + .g-xxl-3, + .gy-xxl-3 { + --bs-gutter-y: 1rem; + } + .g-xxl-4, + .gx-xxl-4 { + --bs-gutter-x: 1.5rem; + } + .g-xxl-4, + .gy-xxl-4 { + --bs-gutter-y: 1.5rem; + } + .g-xxl-5, + .gx-xxl-5 { + --bs-gutter-x: 3rem; + } + .g-xxl-5, + .gy-xxl-5 { + --bs-gutter-y: 3rem; + } +} +.d-inline { + display: inline !important; +} + +.d-inline-block { + display: inline-block !important; +} + +.d-block { + display: block !important; +} + +.d-grid { + display: grid !important; +} + +.d-inline-grid { + display: inline-grid !important; +} + +.d-table { + display: table !important; +} + +.d-table-row { + display: table-row !important; +} + +.d-table-cell { + display: table-cell !important; +} + +.d-flex { + display: flex !important; +} + +.d-inline-flex { + display: inline-flex !important; +} + +.d-none { + display: none !important; +} + +.flex-fill { + flex: 1 1 auto !important; +} + +.flex-row { + flex-direction: row !important; +} + +.flex-column { + flex-direction: column !important; +} + +.flex-row-reverse { + flex-direction: row-reverse !important; +} + +.flex-column-reverse { + flex-direction: column-reverse !important; +} + +.flex-grow-0 { + flex-grow: 0 !important; +} + +.flex-grow-1 { + flex-grow: 1 !important; +} + +.flex-shrink-0 { + flex-shrink: 0 !important; +} + +.flex-shrink-1 { + flex-shrink: 1 !important; +} + +.flex-wrap { + flex-wrap: wrap !important; +} + +.flex-nowrap { + flex-wrap: nowrap !important; +} + +.flex-wrap-reverse { + flex-wrap: wrap-reverse !important; +} + +.justify-content-start { + justify-content: flex-start !important; +} + +.justify-content-end { + justify-content: flex-end !important; +} + +.justify-content-center { + justify-content: center !important; +} + +.justify-content-between { + justify-content: space-between !important; +} + +.justify-content-around { + justify-content: space-around !important; +} + +.justify-content-evenly { + justify-content: space-evenly !important; +} + +.align-items-start { + align-items: flex-start !important; +} + +.align-items-end { + align-items: flex-end !important; +} + +.align-items-center { + align-items: center !important; +} + +.align-items-baseline { + align-items: baseline !important; +} + +.align-items-stretch { + align-items: stretch !important; +} + +.align-content-start { + align-content: flex-start !important; +} + +.align-content-end { + align-content: flex-end !important; +} + +.align-content-center { + align-content: center !important; +} + +.align-content-between { + align-content: space-between !important; +} + +.align-content-around { + align-content: space-around !important; +} + +.align-content-stretch { + align-content: stretch !important; +} + +.align-self-auto { + align-self: auto !important; +} + +.align-self-start { + align-self: flex-start !important; +} + +.align-self-end { + align-self: flex-end !important; +} + +.align-self-center { + align-self: center !important; +} + +.align-self-baseline { + align-self: baseline !important; +} + +.align-self-stretch { + align-self: stretch !important; +} + +.order-first { + order: -1 !important; +} + +.order-0 { + order: 0 !important; +} + +.order-1 { + order: 1 !important; +} + +.order-2 { + order: 2 !important; +} + +.order-3 { + order: 3 !important; +} + +.order-4 { + order: 4 !important; +} + +.order-5 { + order: 5 !important; +} + +.order-last { + order: 6 !important; +} + +.m-0 { + margin: 0 !important; +} + +.m-1 { + margin: 0.25rem !important; +} + +.m-2 { + margin: 0.5rem !important; +} + +.m-3 { + margin: 1rem !important; +} + +.m-4 { + margin: 1.5rem !important; +} + +.m-5 { + margin: 3rem !important; +} + +.m-auto { + margin: auto !important; +} + +.mx-0 { + margin-left: 0 !important; + margin-right: 0 !important; +} + +.mx-1 { + margin-left: 0.25rem !important; + margin-right: 0.25rem !important; +} + +.mx-2 { + margin-left: 0.5rem !important; + margin-right: 0.5rem !important; +} + +.mx-3 { + margin-left: 1rem !important; + margin-right: 1rem !important; +} + +.mx-4 { + margin-left: 1.5rem !important; + margin-right: 1.5rem !important; +} + +.mx-5 { + margin-left: 3rem !important; + margin-right: 3rem !important; +} + +.mx-auto { + margin-left: auto !important; + margin-right: auto !important; +} + +.my-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +.my-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; +} + +.my-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; +} + +.my-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; +} + +.my-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; +} + +.my-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; +} + +.my-auto { + margin-top: auto !important; + margin-bottom: auto !important; +} + +.mt-0 { + margin-top: 0 !important; +} + +.mt-1 { + margin-top: 0.25rem !important; +} + +.mt-2 { + margin-top: 0.5rem !important; +} + +.mt-3 { + margin-top: 1rem !important; +} + +.mt-4 { + margin-top: 1.5rem !important; +} + +.mt-5 { + margin-top: 3rem !important; +} + +.mt-auto { + margin-top: auto !important; +} + +.me-0 { + margin-left: 0 !important; +} + +.me-1 { + margin-left: 0.25rem !important; +} + +.me-2 { + margin-left: 0.5rem !important; +} + +.me-3 { + margin-left: 1rem !important; +} + +.me-4 { + margin-left: 1.5rem !important; +} + +.me-5 { + margin-left: 3rem !important; +} + +.me-auto { + margin-left: auto !important; +} + +.mb-0 { + margin-bottom: 0 !important; +} + +.mb-1 { + margin-bottom: 0.25rem !important; +} + +.mb-2 { + margin-bottom: 0.5rem !important; +} + +.mb-3 { + margin-bottom: 1rem !important; +} + +.mb-4 { + margin-bottom: 1.5rem !important; +} + +.mb-5 { + margin-bottom: 3rem !important; +} + +.mb-auto { + margin-bottom: auto !important; +} + +.ms-0 { + margin-right: 0 !important; +} + +.ms-1 { + margin-right: 0.25rem !important; +} + +.ms-2 { + margin-right: 0.5rem !important; +} + +.ms-3 { + margin-right: 1rem !important; +} + +.ms-4 { + margin-right: 1.5rem !important; +} + +.ms-5 { + margin-right: 3rem !important; +} + +.ms-auto { + margin-right: auto !important; +} + +.p-0 { + padding: 0 !important; +} + +.p-1 { + padding: 0.25rem !important; +} + +.p-2 { + padding: 0.5rem !important; +} + +.p-3 { + padding: 1rem !important; +} + +.p-4 { + padding: 1.5rem !important; +} + +.p-5 { + padding: 3rem !important; +} + +.px-0 { + padding-left: 0 !important; + padding-right: 0 !important; +} + +.px-1 { + padding-left: 0.25rem !important; + padding-right: 0.25rem !important; +} + +.px-2 { + padding-left: 0.5rem !important; + padding-right: 0.5rem !important; +} + +.px-3 { + padding-left: 1rem !important; + padding-right: 1rem !important; +} + +.px-4 { + padding-left: 1.5rem !important; + padding-right: 1.5rem !important; +} + +.px-5 { + padding-left: 3rem !important; + padding-right: 3rem !important; +} + +.py-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; +} + +.py-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; +} + +.py-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; +} + +.py-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; +} + +.py-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; +} + +.py-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; +} + +.pt-0 { + padding-top: 0 !important; +} + +.pt-1 { + padding-top: 0.25rem !important; +} + +.pt-2 { + padding-top: 0.5rem !important; +} + +.pt-3 { + padding-top: 1rem !important; +} + +.pt-4 { + padding-top: 1.5rem !important; +} + +.pt-5 { + padding-top: 3rem !important; +} + +.pe-0 { + padding-left: 0 !important; +} + +.pe-1 { + padding-left: 0.25rem !important; +} + +.pe-2 { + padding-left: 0.5rem !important; +} + +.pe-3 { + padding-left: 1rem !important; +} + +.pe-4 { + padding-left: 1.5rem !important; +} + +.pe-5 { + padding-left: 3rem !important; +} + +.pb-0 { + padding-bottom: 0 !important; +} + +.pb-1 { + padding-bottom: 0.25rem !important; +} + +.pb-2 { + padding-bottom: 0.5rem !important; +} + +.pb-3 { + padding-bottom: 1rem !important; +} + +.pb-4 { + padding-bottom: 1.5rem !important; +} + +.pb-5 { + padding-bottom: 3rem !important; +} + +.ps-0 { + padding-right: 0 !important; +} + +.ps-1 { + padding-right: 0.25rem !important; +} + +.ps-2 { + padding-right: 0.5rem !important; +} + +.ps-3 { + padding-right: 1rem !important; +} + +.ps-4 { + padding-right: 1.5rem !important; +} + +.ps-5 { + padding-right: 3rem !important; +} + +@media (min-width: 576px) { + .d-sm-inline { + display: inline !important; + } + .d-sm-inline-block { + display: inline-block !important; + } + .d-sm-block { + display: block !important; + } + .d-sm-grid { + display: grid !important; + } + .d-sm-inline-grid { + display: inline-grid !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: flex !important; + } + .d-sm-inline-flex { + display: inline-flex !important; + } + .d-sm-none { + display: none !important; + } + .flex-sm-fill { + flex: 1 1 auto !important; + } + .flex-sm-row { + flex-direction: row !important; + } + .flex-sm-column { + flex-direction: column !important; + } + .flex-sm-row-reverse { + flex-direction: row-reverse !important; + } + .flex-sm-column-reverse { + flex-direction: column-reverse !important; + } + .flex-sm-grow-0 { + flex-grow: 0 !important; + } + .flex-sm-grow-1 { + flex-grow: 1 !important; + } + .flex-sm-shrink-0 { + flex-shrink: 0 !important; + } + .flex-sm-shrink-1 { + flex-shrink: 1 !important; + } + .flex-sm-wrap { + flex-wrap: wrap !important; + } + .flex-sm-nowrap { + flex-wrap: nowrap !important; + } + .flex-sm-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-sm-start { + justify-content: flex-start !important; + } + .justify-content-sm-end { + justify-content: flex-end !important; + } + .justify-content-sm-center { + justify-content: center !important; + } + .justify-content-sm-between { + justify-content: space-between !important; + } + .justify-content-sm-around { + justify-content: space-around !important; + } + .justify-content-sm-evenly { + justify-content: space-evenly !important; + } + .align-items-sm-start { + align-items: flex-start !important; + } + .align-items-sm-end { + align-items: flex-end !important; + } + .align-items-sm-center { + align-items: center !important; + } + .align-items-sm-baseline { + align-items: baseline !important; + } + .align-items-sm-stretch { + align-items: stretch !important; + } + .align-content-sm-start { + align-content: flex-start !important; + } + .align-content-sm-end { + align-content: flex-end !important; + } + .align-content-sm-center { + align-content: center !important; + } + .align-content-sm-between { + align-content: space-between !important; + } + .align-content-sm-around { + align-content: space-around !important; + } + .align-content-sm-stretch { + align-content: stretch !important; + } + .align-self-sm-auto { + align-self: auto !important; + } + .align-self-sm-start { + align-self: flex-start !important; + } + .align-self-sm-end { + align-self: flex-end !important; + } + .align-self-sm-center { + align-self: center !important; + } + .align-self-sm-baseline { + align-self: baseline !important; + } + .align-self-sm-stretch { + align-self: stretch !important; + } + .order-sm-first { + order: -1 !important; + } + .order-sm-0 { + order: 0 !important; + } + .order-sm-1 { + order: 1 !important; + } + .order-sm-2 { + order: 2 !important; + } + .order-sm-3 { + order: 3 !important; + } + .order-sm-4 { + order: 4 !important; + } + .order-sm-5 { + order: 5 !important; + } + .order-sm-last { + order: 6 !important; + } + .m-sm-0 { + margin: 0 !important; + } + .m-sm-1 { + margin: 0.25rem !important; + } + .m-sm-2 { + margin: 0.5rem !important; + } + .m-sm-3 { + margin: 1rem !important; + } + .m-sm-4 { + margin: 1.5rem !important; + } + .m-sm-5 { + margin: 3rem !important; + } + .m-sm-auto { + margin: auto !important; + } + .mx-sm-0 { + margin-left: 0 !important; + margin-right: 0 !important; + } + .mx-sm-1 { + margin-left: 0.25rem !important; + margin-right: 0.25rem !important; + } + .mx-sm-2 { + margin-left: 0.5rem !important; + margin-right: 0.5rem !important; + } + .mx-sm-3 { + margin-left: 1rem !important; + margin-right: 1rem !important; + } + .mx-sm-4 { + margin-left: 1.5rem !important; + margin-right: 1.5rem !important; + } + .mx-sm-5 { + margin-left: 3rem !important; + margin-right: 3rem !important; + } + .mx-sm-auto { + margin-left: auto !important; + margin-right: auto !important; + } + .my-sm-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-sm-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-sm-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-sm-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-sm-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-sm-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-sm-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-sm-0 { + margin-top: 0 !important; + } + .mt-sm-1 { + margin-top: 0.25rem !important; + } + .mt-sm-2 { + margin-top: 0.5rem !important; + } + .mt-sm-3 { + margin-top: 1rem !important; + } + .mt-sm-4 { + margin-top: 1.5rem !important; + } + .mt-sm-5 { + margin-top: 3rem !important; + } + .mt-sm-auto { + margin-top: auto !important; + } + .me-sm-0 { + margin-left: 0 !important; + } + .me-sm-1 { + margin-left: 0.25rem !important; + } + .me-sm-2 { + margin-left: 0.5rem !important; + } + .me-sm-3 { + margin-left: 1rem !important; + } + .me-sm-4 { + margin-left: 1.5rem !important; + } + .me-sm-5 { + margin-left: 3rem !important; + } + .me-sm-auto { + margin-left: auto !important; + } + .mb-sm-0 { + margin-bottom: 0 !important; + } + .mb-sm-1 { + margin-bottom: 0.25rem !important; + } + .mb-sm-2 { + margin-bottom: 0.5rem !important; + } + .mb-sm-3 { + margin-bottom: 1rem !important; + } + .mb-sm-4 { + margin-bottom: 1.5rem !important; + } + .mb-sm-5 { + margin-bottom: 3rem !important; + } + .mb-sm-auto { + margin-bottom: auto !important; + } + .ms-sm-0 { + margin-right: 0 !important; + } + .ms-sm-1 { + margin-right: 0.25rem !important; + } + .ms-sm-2 { + margin-right: 0.5rem !important; + } + .ms-sm-3 { + margin-right: 1rem !important; + } + .ms-sm-4 { + margin-right: 1.5rem !important; + } + .ms-sm-5 { + margin-right: 3rem !important; + } + .ms-sm-auto { + margin-right: auto !important; + } + .p-sm-0 { + padding: 0 !important; + } + .p-sm-1 { + padding: 0.25rem !important; + } + .p-sm-2 { + padding: 0.5rem !important; + } + .p-sm-3 { + padding: 1rem !important; + } + .p-sm-4 { + padding: 1.5rem !important; + } + .p-sm-5 { + padding: 3rem !important; + } + .px-sm-0 { + padding-left: 0 !important; + padding-right: 0 !important; + } + .px-sm-1 { + padding-left: 0.25rem !important; + padding-right: 0.25rem !important; + } + .px-sm-2 { + padding-left: 0.5rem !important; + padding-right: 0.5rem !important; + } + .px-sm-3 { + padding-left: 1rem !important; + padding-right: 1rem !important; + } + .px-sm-4 { + padding-left: 1.5rem !important; + padding-right: 1.5rem !important; + } + .px-sm-5 { + padding-left: 3rem !important; + padding-right: 3rem !important; + } + .py-sm-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-sm-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-sm-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-sm-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-sm-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-sm-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-sm-0 { + padding-top: 0 !important; + } + .pt-sm-1 { + padding-top: 0.25rem !important; + } + .pt-sm-2 { + padding-top: 0.5rem !important; + } + .pt-sm-3 { + padding-top: 1rem !important; + } + .pt-sm-4 { + padding-top: 1.5rem !important; + } + .pt-sm-5 { + padding-top: 3rem !important; + } + .pe-sm-0 { + padding-left: 0 !important; + } + .pe-sm-1 { + padding-left: 0.25rem !important; + } + .pe-sm-2 { + padding-left: 0.5rem !important; + } + .pe-sm-3 { + padding-left: 1rem !important; + } + .pe-sm-4 { + padding-left: 1.5rem !important; + } + .pe-sm-5 { + padding-left: 3rem !important; + } + .pb-sm-0 { + padding-bottom: 0 !important; + } + .pb-sm-1 { + padding-bottom: 0.25rem !important; + } + .pb-sm-2 { + padding-bottom: 0.5rem !important; + } + .pb-sm-3 { + padding-bottom: 1rem !important; + } + .pb-sm-4 { + padding-bottom: 1.5rem !important; + } + .pb-sm-5 { + padding-bottom: 3rem !important; + } + .ps-sm-0 { + padding-right: 0 !important; + } + .ps-sm-1 { + padding-right: 0.25rem !important; + } + .ps-sm-2 { + padding-right: 0.5rem !important; + } + .ps-sm-3 { + padding-right: 1rem !important; + } + .ps-sm-4 { + padding-right: 1.5rem !important; + } + .ps-sm-5 { + padding-right: 3rem !important; + } +} +@media (min-width: 768px) { + .d-md-inline { + display: inline !important; + } + .d-md-inline-block { + display: inline-block !important; + } + .d-md-block { + display: block !important; + } + .d-md-grid { + display: grid !important; + } + .d-md-inline-grid { + display: inline-grid !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: flex !important; + } + .d-md-inline-flex { + display: inline-flex !important; + } + .d-md-none { + display: none !important; + } + .flex-md-fill { + flex: 1 1 auto !important; + } + .flex-md-row { + flex-direction: row !important; + } + .flex-md-column { + flex-direction: column !important; + } + .flex-md-row-reverse { + flex-direction: row-reverse !important; + } + .flex-md-column-reverse { + flex-direction: column-reverse !important; + } + .flex-md-grow-0 { + flex-grow: 0 !important; + } + .flex-md-grow-1 { + flex-grow: 1 !important; + } + .flex-md-shrink-0 { + flex-shrink: 0 !important; + } + .flex-md-shrink-1 { + flex-shrink: 1 !important; + } + .flex-md-wrap { + flex-wrap: wrap !important; + } + .flex-md-nowrap { + flex-wrap: nowrap !important; + } + .flex-md-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-md-start { + justify-content: flex-start !important; + } + .justify-content-md-end { + justify-content: flex-end !important; + } + .justify-content-md-center { + justify-content: center !important; + } + .justify-content-md-between { + justify-content: space-between !important; + } + .justify-content-md-around { + justify-content: space-around !important; + } + .justify-content-md-evenly { + justify-content: space-evenly !important; + } + .align-items-md-start { + align-items: flex-start !important; + } + .align-items-md-end { + align-items: flex-end !important; + } + .align-items-md-center { + align-items: center !important; + } + .align-items-md-baseline { + align-items: baseline !important; + } + .align-items-md-stretch { + align-items: stretch !important; + } + .align-content-md-start { + align-content: flex-start !important; + } + .align-content-md-end { + align-content: flex-end !important; + } + .align-content-md-center { + align-content: center !important; + } + .align-content-md-between { + align-content: space-between !important; + } + .align-content-md-around { + align-content: space-around !important; + } + .align-content-md-stretch { + align-content: stretch !important; + } + .align-self-md-auto { + align-self: auto !important; + } + .align-self-md-start { + align-self: flex-start !important; + } + .align-self-md-end { + align-self: flex-end !important; + } + .align-self-md-center { + align-self: center !important; + } + .align-self-md-baseline { + align-self: baseline !important; + } + .align-self-md-stretch { + align-self: stretch !important; + } + .order-md-first { + order: -1 !important; + } + .order-md-0 { + order: 0 !important; + } + .order-md-1 { + order: 1 !important; + } + .order-md-2 { + order: 2 !important; + } + .order-md-3 { + order: 3 !important; + } + .order-md-4 { + order: 4 !important; + } + .order-md-5 { + order: 5 !important; + } + .order-md-last { + order: 6 !important; + } + .m-md-0 { + margin: 0 !important; + } + .m-md-1 { + margin: 0.25rem !important; + } + .m-md-2 { + margin: 0.5rem !important; + } + .m-md-3 { + margin: 1rem !important; + } + .m-md-4 { + margin: 1.5rem !important; + } + .m-md-5 { + margin: 3rem !important; + } + .m-md-auto { + margin: auto !important; + } + .mx-md-0 { + margin-left: 0 !important; + margin-right: 0 !important; + } + .mx-md-1 { + margin-left: 0.25rem !important; + margin-right: 0.25rem !important; + } + .mx-md-2 { + margin-left: 0.5rem !important; + margin-right: 0.5rem !important; + } + .mx-md-3 { + margin-left: 1rem !important; + margin-right: 1rem !important; + } + .mx-md-4 { + margin-left: 1.5rem !important; + margin-right: 1.5rem !important; + } + .mx-md-5 { + margin-left: 3rem !important; + margin-right: 3rem !important; + } + .mx-md-auto { + margin-left: auto !important; + margin-right: auto !important; + } + .my-md-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-md-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-md-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-md-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-md-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-md-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-md-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-md-0 { + margin-top: 0 !important; + } + .mt-md-1 { + margin-top: 0.25rem !important; + } + .mt-md-2 { + margin-top: 0.5rem !important; + } + .mt-md-3 { + margin-top: 1rem !important; + } + .mt-md-4 { + margin-top: 1.5rem !important; + } + .mt-md-5 { + margin-top: 3rem !important; + } + .mt-md-auto { + margin-top: auto !important; + } + .me-md-0 { + margin-left: 0 !important; + } + .me-md-1 { + margin-left: 0.25rem !important; + } + .me-md-2 { + margin-left: 0.5rem !important; + } + .me-md-3 { + margin-left: 1rem !important; + } + .me-md-4 { + margin-left: 1.5rem !important; + } + .me-md-5 { + margin-left: 3rem !important; + } + .me-md-auto { + margin-left: auto !important; + } + .mb-md-0 { + margin-bottom: 0 !important; + } + .mb-md-1 { + margin-bottom: 0.25rem !important; + } + .mb-md-2 { + margin-bottom: 0.5rem !important; + } + .mb-md-3 { + margin-bottom: 1rem !important; + } + .mb-md-4 { + margin-bottom: 1.5rem !important; + } + .mb-md-5 { + margin-bottom: 3rem !important; + } + .mb-md-auto { + margin-bottom: auto !important; + } + .ms-md-0 { + margin-right: 0 !important; + } + .ms-md-1 { + margin-right: 0.25rem !important; + } + .ms-md-2 { + margin-right: 0.5rem !important; + } + .ms-md-3 { + margin-right: 1rem !important; + } + .ms-md-4 { + margin-right: 1.5rem !important; + } + .ms-md-5 { + margin-right: 3rem !important; + } + .ms-md-auto { + margin-right: auto !important; + } + .p-md-0 { + padding: 0 !important; + } + .p-md-1 { + padding: 0.25rem !important; + } + .p-md-2 { + padding: 0.5rem !important; + } + .p-md-3 { + padding: 1rem !important; + } + .p-md-4 { + padding: 1.5rem !important; + } + .p-md-5 { + padding: 3rem !important; + } + .px-md-0 { + padding-left: 0 !important; + padding-right: 0 !important; + } + .px-md-1 { + padding-left: 0.25rem !important; + padding-right: 0.25rem !important; + } + .px-md-2 { + padding-left: 0.5rem !important; + padding-right: 0.5rem !important; + } + .px-md-3 { + padding-left: 1rem !important; + padding-right: 1rem !important; + } + .px-md-4 { + padding-left: 1.5rem !important; + padding-right: 1.5rem !important; + } + .px-md-5 { + padding-left: 3rem !important; + padding-right: 3rem !important; + } + .py-md-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-md-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-md-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-md-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-md-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-md-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-md-0 { + padding-top: 0 !important; + } + .pt-md-1 { + padding-top: 0.25rem !important; + } + .pt-md-2 { + padding-top: 0.5rem !important; + } + .pt-md-3 { + padding-top: 1rem !important; + } + .pt-md-4 { + padding-top: 1.5rem !important; + } + .pt-md-5 { + padding-top: 3rem !important; + } + .pe-md-0 { + padding-left: 0 !important; + } + .pe-md-1 { + padding-left: 0.25rem !important; + } + .pe-md-2 { + padding-left: 0.5rem !important; + } + .pe-md-3 { + padding-left: 1rem !important; + } + .pe-md-4 { + padding-left: 1.5rem !important; + } + .pe-md-5 { + padding-left: 3rem !important; + } + .pb-md-0 { + padding-bottom: 0 !important; + } + .pb-md-1 { + padding-bottom: 0.25rem !important; + } + .pb-md-2 { + padding-bottom: 0.5rem !important; + } + .pb-md-3 { + padding-bottom: 1rem !important; + } + .pb-md-4 { + padding-bottom: 1.5rem !important; + } + .pb-md-5 { + padding-bottom: 3rem !important; + } + .ps-md-0 { + padding-right: 0 !important; + } + .ps-md-1 { + padding-right: 0.25rem !important; + } + .ps-md-2 { + padding-right: 0.5rem !important; + } + .ps-md-3 { + padding-right: 1rem !important; + } + .ps-md-4 { + padding-right: 1.5rem !important; + } + .ps-md-5 { + padding-right: 3rem !important; + } +} +@media (min-width: 992px) { + .d-lg-inline { + display: inline !important; + } + .d-lg-inline-block { + display: inline-block !important; + } + .d-lg-block { + display: block !important; + } + .d-lg-grid { + display: grid !important; + } + .d-lg-inline-grid { + display: inline-grid !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: flex !important; + } + .d-lg-inline-flex { + display: inline-flex !important; + } + .d-lg-none { + display: none !important; + } + .flex-lg-fill { + flex: 1 1 auto !important; + } + .flex-lg-row { + flex-direction: row !important; + } + .flex-lg-column { + flex-direction: column !important; + } + .flex-lg-row-reverse { + flex-direction: row-reverse !important; + } + .flex-lg-column-reverse { + flex-direction: column-reverse !important; + } + .flex-lg-grow-0 { + flex-grow: 0 !important; + } + .flex-lg-grow-1 { + flex-grow: 1 !important; + } + .flex-lg-shrink-0 { + flex-shrink: 0 !important; + } + .flex-lg-shrink-1 { + flex-shrink: 1 !important; + } + .flex-lg-wrap { + flex-wrap: wrap !important; + } + .flex-lg-nowrap { + flex-wrap: nowrap !important; + } + .flex-lg-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-lg-start { + justify-content: flex-start !important; + } + .justify-content-lg-end { + justify-content: flex-end !important; + } + .justify-content-lg-center { + justify-content: center !important; + } + .justify-content-lg-between { + justify-content: space-between !important; + } + .justify-content-lg-around { + justify-content: space-around !important; + } + .justify-content-lg-evenly { + justify-content: space-evenly !important; + } + .align-items-lg-start { + align-items: flex-start !important; + } + .align-items-lg-end { + align-items: flex-end !important; + } + .align-items-lg-center { + align-items: center !important; + } + .align-items-lg-baseline { + align-items: baseline !important; + } + .align-items-lg-stretch { + align-items: stretch !important; + } + .align-content-lg-start { + align-content: flex-start !important; + } + .align-content-lg-end { + align-content: flex-end !important; + } + .align-content-lg-center { + align-content: center !important; + } + .align-content-lg-between { + align-content: space-between !important; + } + .align-content-lg-around { + align-content: space-around !important; + } + .align-content-lg-stretch { + align-content: stretch !important; + } + .align-self-lg-auto { + align-self: auto !important; + } + .align-self-lg-start { + align-self: flex-start !important; + } + .align-self-lg-end { + align-self: flex-end !important; + } + .align-self-lg-center { + align-self: center !important; + } + .align-self-lg-baseline { + align-self: baseline !important; + } + .align-self-lg-stretch { + align-self: stretch !important; + } + .order-lg-first { + order: -1 !important; + } + .order-lg-0 { + order: 0 !important; + } + .order-lg-1 { + order: 1 !important; + } + .order-lg-2 { + order: 2 !important; + } + .order-lg-3 { + order: 3 !important; + } + .order-lg-4 { + order: 4 !important; + } + .order-lg-5 { + order: 5 !important; + } + .order-lg-last { + order: 6 !important; + } + .m-lg-0 { + margin: 0 !important; + } + .m-lg-1 { + margin: 0.25rem !important; + } + .m-lg-2 { + margin: 0.5rem !important; + } + .m-lg-3 { + margin: 1rem !important; + } + .m-lg-4 { + margin: 1.5rem !important; + } + .m-lg-5 { + margin: 3rem !important; + } + .m-lg-auto { + margin: auto !important; + } + .mx-lg-0 { + margin-left: 0 !important; + margin-right: 0 !important; + } + .mx-lg-1 { + margin-left: 0.25rem !important; + margin-right: 0.25rem !important; + } + .mx-lg-2 { + margin-left: 0.5rem !important; + margin-right: 0.5rem !important; + } + .mx-lg-3 { + margin-left: 1rem !important; + margin-right: 1rem !important; + } + .mx-lg-4 { + margin-left: 1.5rem !important; + margin-right: 1.5rem !important; + } + .mx-lg-5 { + margin-left: 3rem !important; + margin-right: 3rem !important; + } + .mx-lg-auto { + margin-left: auto !important; + margin-right: auto !important; + } + .my-lg-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-lg-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-lg-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-lg-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-lg-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-lg-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-lg-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-lg-0 { + margin-top: 0 !important; + } + .mt-lg-1 { + margin-top: 0.25rem !important; + } + .mt-lg-2 { + margin-top: 0.5rem !important; + } + .mt-lg-3 { + margin-top: 1rem !important; + } + .mt-lg-4 { + margin-top: 1.5rem !important; + } + .mt-lg-5 { + margin-top: 3rem !important; + } + .mt-lg-auto { + margin-top: auto !important; + } + .me-lg-0 { + margin-left: 0 !important; + } + .me-lg-1 { + margin-left: 0.25rem !important; + } + .me-lg-2 { + margin-left: 0.5rem !important; + } + .me-lg-3 { + margin-left: 1rem !important; + } + .me-lg-4 { + margin-left: 1.5rem !important; + } + .me-lg-5 { + margin-left: 3rem !important; + } + .me-lg-auto { + margin-left: auto !important; + } + .mb-lg-0 { + margin-bottom: 0 !important; + } + .mb-lg-1 { + margin-bottom: 0.25rem !important; + } + .mb-lg-2 { + margin-bottom: 0.5rem !important; + } + .mb-lg-3 { + margin-bottom: 1rem !important; + } + .mb-lg-4 { + margin-bottom: 1.5rem !important; + } + .mb-lg-5 { + margin-bottom: 3rem !important; + } + .mb-lg-auto { + margin-bottom: auto !important; + } + .ms-lg-0 { + margin-right: 0 !important; + } + .ms-lg-1 { + margin-right: 0.25rem !important; + } + .ms-lg-2 { + margin-right: 0.5rem !important; + } + .ms-lg-3 { + margin-right: 1rem !important; + } + .ms-lg-4 { + margin-right: 1.5rem !important; + } + .ms-lg-5 { + margin-right: 3rem !important; + } + .ms-lg-auto { + margin-right: auto !important; + } + .p-lg-0 { + padding: 0 !important; + } + .p-lg-1 { + padding: 0.25rem !important; + } + .p-lg-2 { + padding: 0.5rem !important; + } + .p-lg-3 { + padding: 1rem !important; + } + .p-lg-4 { + padding: 1.5rem !important; + } + .p-lg-5 { + padding: 3rem !important; + } + .px-lg-0 { + padding-left: 0 !important; + padding-right: 0 !important; + } + .px-lg-1 { + padding-left: 0.25rem !important; + padding-right: 0.25rem !important; + } + .px-lg-2 { + padding-left: 0.5rem !important; + padding-right: 0.5rem !important; + } + .px-lg-3 { + padding-left: 1rem !important; + padding-right: 1rem !important; + } + .px-lg-4 { + padding-left: 1.5rem !important; + padding-right: 1.5rem !important; + } + .px-lg-5 { + padding-left: 3rem !important; + padding-right: 3rem !important; + } + .py-lg-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-lg-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-lg-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-lg-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-lg-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-lg-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-lg-0 { + padding-top: 0 !important; + } + .pt-lg-1 { + padding-top: 0.25rem !important; + } + .pt-lg-2 { + padding-top: 0.5rem !important; + } + .pt-lg-3 { + padding-top: 1rem !important; + } + .pt-lg-4 { + padding-top: 1.5rem !important; + } + .pt-lg-5 { + padding-top: 3rem !important; + } + .pe-lg-0 { + padding-left: 0 !important; + } + .pe-lg-1 { + padding-left: 0.25rem !important; + } + .pe-lg-2 { + padding-left: 0.5rem !important; + } + .pe-lg-3 { + padding-left: 1rem !important; + } + .pe-lg-4 { + padding-left: 1.5rem !important; + } + .pe-lg-5 { + padding-left: 3rem !important; + } + .pb-lg-0 { + padding-bottom: 0 !important; + } + .pb-lg-1 { + padding-bottom: 0.25rem !important; + } + .pb-lg-2 { + padding-bottom: 0.5rem !important; + } + .pb-lg-3 { + padding-bottom: 1rem !important; + } + .pb-lg-4 { + padding-bottom: 1.5rem !important; + } + .pb-lg-5 { + padding-bottom: 3rem !important; + } + .ps-lg-0 { + padding-right: 0 !important; + } + .ps-lg-1 { + padding-right: 0.25rem !important; + } + .ps-lg-2 { + padding-right: 0.5rem !important; + } + .ps-lg-3 { + padding-right: 1rem !important; + } + .ps-lg-4 { + padding-right: 1.5rem !important; + } + .ps-lg-5 { + padding-right: 3rem !important; + } +} +@media (min-width: 1200px) { + .d-xl-inline { + display: inline !important; + } + .d-xl-inline-block { + display: inline-block !important; + } + .d-xl-block { + display: block !important; + } + .d-xl-grid { + display: grid !important; + } + .d-xl-inline-grid { + display: inline-grid !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: flex !important; + } + .d-xl-inline-flex { + display: inline-flex !important; + } + .d-xl-none { + display: none !important; + } + .flex-xl-fill { + flex: 1 1 auto !important; + } + .flex-xl-row { + flex-direction: row !important; + } + .flex-xl-column { + flex-direction: column !important; + } + .flex-xl-row-reverse { + flex-direction: row-reverse !important; + } + .flex-xl-column-reverse { + flex-direction: column-reverse !important; + } + .flex-xl-grow-0 { + flex-grow: 0 !important; + } + .flex-xl-grow-1 { + flex-grow: 1 !important; + } + .flex-xl-shrink-0 { + flex-shrink: 0 !important; + } + .flex-xl-shrink-1 { + flex-shrink: 1 !important; + } + .flex-xl-wrap { + flex-wrap: wrap !important; + } + .flex-xl-nowrap { + flex-wrap: nowrap !important; + } + .flex-xl-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-xl-start { + justify-content: flex-start !important; + } + .justify-content-xl-end { + justify-content: flex-end !important; + } + .justify-content-xl-center { + justify-content: center !important; + } + .justify-content-xl-between { + justify-content: space-between !important; + } + .justify-content-xl-around { + justify-content: space-around !important; + } + .justify-content-xl-evenly { + justify-content: space-evenly !important; + } + .align-items-xl-start { + align-items: flex-start !important; + } + .align-items-xl-end { + align-items: flex-end !important; + } + .align-items-xl-center { + align-items: center !important; + } + .align-items-xl-baseline { + align-items: baseline !important; + } + .align-items-xl-stretch { + align-items: stretch !important; + } + .align-content-xl-start { + align-content: flex-start !important; + } + .align-content-xl-end { + align-content: flex-end !important; + } + .align-content-xl-center { + align-content: center !important; + } + .align-content-xl-between { + align-content: space-between !important; + } + .align-content-xl-around { + align-content: space-around !important; + } + .align-content-xl-stretch { + align-content: stretch !important; + } + .align-self-xl-auto { + align-self: auto !important; + } + .align-self-xl-start { + align-self: flex-start !important; + } + .align-self-xl-end { + align-self: flex-end !important; + } + .align-self-xl-center { + align-self: center !important; + } + .align-self-xl-baseline { + align-self: baseline !important; + } + .align-self-xl-stretch { + align-self: stretch !important; + } + .order-xl-first { + order: -1 !important; + } + .order-xl-0 { + order: 0 !important; + } + .order-xl-1 { + order: 1 !important; + } + .order-xl-2 { + order: 2 !important; + } + .order-xl-3 { + order: 3 !important; + } + .order-xl-4 { + order: 4 !important; + } + .order-xl-5 { + order: 5 !important; + } + .order-xl-last { + order: 6 !important; + } + .m-xl-0 { + margin: 0 !important; + } + .m-xl-1 { + margin: 0.25rem !important; + } + .m-xl-2 { + margin: 0.5rem !important; + } + .m-xl-3 { + margin: 1rem !important; + } + .m-xl-4 { + margin: 1.5rem !important; + } + .m-xl-5 { + margin: 3rem !important; + } + .m-xl-auto { + margin: auto !important; + } + .mx-xl-0 { + margin-left: 0 !important; + margin-right: 0 !important; + } + .mx-xl-1 { + margin-left: 0.25rem !important; + margin-right: 0.25rem !important; + } + .mx-xl-2 { + margin-left: 0.5rem !important; + margin-right: 0.5rem !important; + } + .mx-xl-3 { + margin-left: 1rem !important; + margin-right: 1rem !important; + } + .mx-xl-4 { + margin-left: 1.5rem !important; + margin-right: 1.5rem !important; + } + .mx-xl-5 { + margin-left: 3rem !important; + margin-right: 3rem !important; + } + .mx-xl-auto { + margin-left: auto !important; + margin-right: auto !important; + } + .my-xl-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-xl-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-xl-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-xl-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-xl-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-xl-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-xl-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-xl-0 { + margin-top: 0 !important; + } + .mt-xl-1 { + margin-top: 0.25rem !important; + } + .mt-xl-2 { + margin-top: 0.5rem !important; + } + .mt-xl-3 { + margin-top: 1rem !important; + } + .mt-xl-4 { + margin-top: 1.5rem !important; + } + .mt-xl-5 { + margin-top: 3rem !important; + } + .mt-xl-auto { + margin-top: auto !important; + } + .me-xl-0 { + margin-left: 0 !important; + } + .me-xl-1 { + margin-left: 0.25rem !important; + } + .me-xl-2 { + margin-left: 0.5rem !important; + } + .me-xl-3 { + margin-left: 1rem !important; + } + .me-xl-4 { + margin-left: 1.5rem !important; + } + .me-xl-5 { + margin-left: 3rem !important; + } + .me-xl-auto { + margin-left: auto !important; + } + .mb-xl-0 { + margin-bottom: 0 !important; + } + .mb-xl-1 { + margin-bottom: 0.25rem !important; + } + .mb-xl-2 { + margin-bottom: 0.5rem !important; + } + .mb-xl-3 { + margin-bottom: 1rem !important; + } + .mb-xl-4 { + margin-bottom: 1.5rem !important; + } + .mb-xl-5 { + margin-bottom: 3rem !important; + } + .mb-xl-auto { + margin-bottom: auto !important; + } + .ms-xl-0 { + margin-right: 0 !important; + } + .ms-xl-1 { + margin-right: 0.25rem !important; + } + .ms-xl-2 { + margin-right: 0.5rem !important; + } + .ms-xl-3 { + margin-right: 1rem !important; + } + .ms-xl-4 { + margin-right: 1.5rem !important; + } + .ms-xl-5 { + margin-right: 3rem !important; + } + .ms-xl-auto { + margin-right: auto !important; + } + .p-xl-0 { + padding: 0 !important; + } + .p-xl-1 { + padding: 0.25rem !important; + } + .p-xl-2 { + padding: 0.5rem !important; + } + .p-xl-3 { + padding: 1rem !important; + } + .p-xl-4 { + padding: 1.5rem !important; + } + .p-xl-5 { + padding: 3rem !important; + } + .px-xl-0 { + padding-left: 0 !important; + padding-right: 0 !important; + } + .px-xl-1 { + padding-left: 0.25rem !important; + padding-right: 0.25rem !important; + } + .px-xl-2 { + padding-left: 0.5rem !important; + padding-right: 0.5rem !important; + } + .px-xl-3 { + padding-left: 1rem !important; + padding-right: 1rem !important; + } + .px-xl-4 { + padding-left: 1.5rem !important; + padding-right: 1.5rem !important; + } + .px-xl-5 { + padding-left: 3rem !important; + padding-right: 3rem !important; + } + .py-xl-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-xl-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-xl-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-xl-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-xl-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-xl-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-xl-0 { + padding-top: 0 !important; + } + .pt-xl-1 { + padding-top: 0.25rem !important; + } + .pt-xl-2 { + padding-top: 0.5rem !important; + } + .pt-xl-3 { + padding-top: 1rem !important; + } + .pt-xl-4 { + padding-top: 1.5rem !important; + } + .pt-xl-5 { + padding-top: 3rem !important; + } + .pe-xl-0 { + padding-left: 0 !important; + } + .pe-xl-1 { + padding-left: 0.25rem !important; + } + .pe-xl-2 { + padding-left: 0.5rem !important; + } + .pe-xl-3 { + padding-left: 1rem !important; + } + .pe-xl-4 { + padding-left: 1.5rem !important; + } + .pe-xl-5 { + padding-left: 3rem !important; + } + .pb-xl-0 { + padding-bottom: 0 !important; + } + .pb-xl-1 { + padding-bottom: 0.25rem !important; + } + .pb-xl-2 { + padding-bottom: 0.5rem !important; + } + .pb-xl-3 { + padding-bottom: 1rem !important; + } + .pb-xl-4 { + padding-bottom: 1.5rem !important; + } + .pb-xl-5 { + padding-bottom: 3rem !important; + } + .ps-xl-0 { + padding-right: 0 !important; + } + .ps-xl-1 { + padding-right: 0.25rem !important; + } + .ps-xl-2 { + padding-right: 0.5rem !important; + } + .ps-xl-3 { + padding-right: 1rem !important; + } + .ps-xl-4 { + padding-right: 1.5rem !important; + } + .ps-xl-5 { + padding-right: 3rem !important; + } +} +@media (min-width: 1400px) { + .d-xxl-inline { + display: inline !important; + } + .d-xxl-inline-block { + display: inline-block !important; + } + .d-xxl-block { + display: block !important; + } + .d-xxl-grid { + display: grid !important; + } + .d-xxl-inline-grid { + display: inline-grid !important; + } + .d-xxl-table { + display: table !important; + } + .d-xxl-table-row { + display: table-row !important; + } + .d-xxl-table-cell { + display: table-cell !important; + } + .d-xxl-flex { + display: flex !important; + } + .d-xxl-inline-flex { + display: inline-flex !important; + } + .d-xxl-none { + display: none !important; + } + .flex-xxl-fill { + flex: 1 1 auto !important; + } + .flex-xxl-row { + flex-direction: row !important; + } + .flex-xxl-column { + flex-direction: column !important; + } + .flex-xxl-row-reverse { + flex-direction: row-reverse !important; + } + .flex-xxl-column-reverse { + flex-direction: column-reverse !important; + } + .flex-xxl-grow-0 { + flex-grow: 0 !important; + } + .flex-xxl-grow-1 { + flex-grow: 1 !important; + } + .flex-xxl-shrink-0 { + flex-shrink: 0 !important; + } + .flex-xxl-shrink-1 { + flex-shrink: 1 !important; + } + .flex-xxl-wrap { + flex-wrap: wrap !important; + } + .flex-xxl-nowrap { + flex-wrap: nowrap !important; + } + .flex-xxl-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-xxl-start { + justify-content: flex-start !important; + } + .justify-content-xxl-end { + justify-content: flex-end !important; + } + .justify-content-xxl-center { + justify-content: center !important; + } + .justify-content-xxl-between { + justify-content: space-between !important; + } + .justify-content-xxl-around { + justify-content: space-around !important; + } + .justify-content-xxl-evenly { + justify-content: space-evenly !important; + } + .align-items-xxl-start { + align-items: flex-start !important; + } + .align-items-xxl-end { + align-items: flex-end !important; + } + .align-items-xxl-center { + align-items: center !important; + } + .align-items-xxl-baseline { + align-items: baseline !important; + } + .align-items-xxl-stretch { + align-items: stretch !important; + } + .align-content-xxl-start { + align-content: flex-start !important; + } + .align-content-xxl-end { + align-content: flex-end !important; + } + .align-content-xxl-center { + align-content: center !important; + } + .align-content-xxl-between { + align-content: space-between !important; + } + .align-content-xxl-around { + align-content: space-around !important; + } + .align-content-xxl-stretch { + align-content: stretch !important; + } + .align-self-xxl-auto { + align-self: auto !important; + } + .align-self-xxl-start { + align-self: flex-start !important; + } + .align-self-xxl-end { + align-self: flex-end !important; + } + .align-self-xxl-center { + align-self: center !important; + } + .align-self-xxl-baseline { + align-self: baseline !important; + } + .align-self-xxl-stretch { + align-self: stretch !important; + } + .order-xxl-first { + order: -1 !important; + } + .order-xxl-0 { + order: 0 !important; + } + .order-xxl-1 { + order: 1 !important; + } + .order-xxl-2 { + order: 2 !important; + } + .order-xxl-3 { + order: 3 !important; + } + .order-xxl-4 { + order: 4 !important; + } + .order-xxl-5 { + order: 5 !important; + } + .order-xxl-last { + order: 6 !important; + } + .m-xxl-0 { + margin: 0 !important; + } + .m-xxl-1 { + margin: 0.25rem !important; + } + .m-xxl-2 { + margin: 0.5rem !important; + } + .m-xxl-3 { + margin: 1rem !important; + } + .m-xxl-4 { + margin: 1.5rem !important; + } + .m-xxl-5 { + margin: 3rem !important; + } + .m-xxl-auto { + margin: auto !important; + } + .mx-xxl-0 { + margin-left: 0 !important; + margin-right: 0 !important; + } + .mx-xxl-1 { + margin-left: 0.25rem !important; + margin-right: 0.25rem !important; + } + .mx-xxl-2 { + margin-left: 0.5rem !important; + margin-right: 0.5rem !important; + } + .mx-xxl-3 { + margin-left: 1rem !important; + margin-right: 1rem !important; + } + .mx-xxl-4 { + margin-left: 1.5rem !important; + margin-right: 1.5rem !important; + } + .mx-xxl-5 { + margin-left: 3rem !important; + margin-right: 3rem !important; + } + .mx-xxl-auto { + margin-left: auto !important; + margin-right: auto !important; + } + .my-xxl-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-xxl-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-xxl-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-xxl-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-xxl-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-xxl-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-xxl-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-xxl-0 { + margin-top: 0 !important; + } + .mt-xxl-1 { + margin-top: 0.25rem !important; + } + .mt-xxl-2 { + margin-top: 0.5rem !important; + } + .mt-xxl-3 { + margin-top: 1rem !important; + } + .mt-xxl-4 { + margin-top: 1.5rem !important; + } + .mt-xxl-5 { + margin-top: 3rem !important; + } + .mt-xxl-auto { + margin-top: auto !important; + } + .me-xxl-0 { + margin-left: 0 !important; + } + .me-xxl-1 { + margin-left: 0.25rem !important; + } + .me-xxl-2 { + margin-left: 0.5rem !important; + } + .me-xxl-3 { + margin-left: 1rem !important; + } + .me-xxl-4 { + margin-left: 1.5rem !important; + } + .me-xxl-5 { + margin-left: 3rem !important; + } + .me-xxl-auto { + margin-left: auto !important; + } + .mb-xxl-0 { + margin-bottom: 0 !important; + } + .mb-xxl-1 { + margin-bottom: 0.25rem !important; + } + .mb-xxl-2 { + margin-bottom: 0.5rem !important; + } + .mb-xxl-3 { + margin-bottom: 1rem !important; + } + .mb-xxl-4 { + margin-bottom: 1.5rem !important; + } + .mb-xxl-5 { + margin-bottom: 3rem !important; + } + .mb-xxl-auto { + margin-bottom: auto !important; + } + .ms-xxl-0 { + margin-right: 0 !important; + } + .ms-xxl-1 { + margin-right: 0.25rem !important; + } + .ms-xxl-2 { + margin-right: 0.5rem !important; + } + .ms-xxl-3 { + margin-right: 1rem !important; + } + .ms-xxl-4 { + margin-right: 1.5rem !important; + } + .ms-xxl-5 { + margin-right: 3rem !important; + } + .ms-xxl-auto { + margin-right: auto !important; + } + .p-xxl-0 { + padding: 0 !important; + } + .p-xxl-1 { + padding: 0.25rem !important; + } + .p-xxl-2 { + padding: 0.5rem !important; + } + .p-xxl-3 { + padding: 1rem !important; + } + .p-xxl-4 { + padding: 1.5rem !important; + } + .p-xxl-5 { + padding: 3rem !important; + } + .px-xxl-0 { + padding-left: 0 !important; + padding-right: 0 !important; + } + .px-xxl-1 { + padding-left: 0.25rem !important; + padding-right: 0.25rem !important; + } + .px-xxl-2 { + padding-left: 0.5rem !important; + padding-right: 0.5rem !important; + } + .px-xxl-3 { + padding-left: 1rem !important; + padding-right: 1rem !important; + } + .px-xxl-4 { + padding-left: 1.5rem !important; + padding-right: 1.5rem !important; + } + .px-xxl-5 { + padding-left: 3rem !important; + padding-right: 3rem !important; + } + .py-xxl-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-xxl-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-xxl-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-xxl-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-xxl-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-xxl-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-xxl-0 { + padding-top: 0 !important; + } + .pt-xxl-1 { + padding-top: 0.25rem !important; + } + .pt-xxl-2 { + padding-top: 0.5rem !important; + } + .pt-xxl-3 { + padding-top: 1rem !important; + } + .pt-xxl-4 { + padding-top: 1.5rem !important; + } + .pt-xxl-5 { + padding-top: 3rem !important; + } + .pe-xxl-0 { + padding-left: 0 !important; + } + .pe-xxl-1 { + padding-left: 0.25rem !important; + } + .pe-xxl-2 { + padding-left: 0.5rem !important; + } + .pe-xxl-3 { + padding-left: 1rem !important; + } + .pe-xxl-4 { + padding-left: 1.5rem !important; + } + .pe-xxl-5 { + padding-left: 3rem !important; + } + .pb-xxl-0 { + padding-bottom: 0 !important; + } + .pb-xxl-1 { + padding-bottom: 0.25rem !important; + } + .pb-xxl-2 { + padding-bottom: 0.5rem !important; + } + .pb-xxl-3 { + padding-bottom: 1rem !important; + } + .pb-xxl-4 { + padding-bottom: 1.5rem !important; + } + .pb-xxl-5 { + padding-bottom: 3rem !important; + } + .ps-xxl-0 { + padding-right: 0 !important; + } + .ps-xxl-1 { + padding-right: 0.25rem !important; + } + .ps-xxl-2 { + padding-right: 0.5rem !important; + } + .ps-xxl-3 { + padding-right: 1rem !important; + } + .ps-xxl-4 { + padding-right: 1.5rem !important; + } + .ps-xxl-5 { + padding-right: 3rem !important; + } +} +@media print { + .d-print-inline { + display: inline !important; + } + .d-print-inline-block { + display: inline-block !important; + } + .d-print-block { + display: block !important; + } + .d-print-grid { + display: grid !important; + } + .d-print-inline-grid { + display: inline-grid !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: flex !important; + } + .d-print-inline-flex { + display: inline-flex !important; + } + .d-print-none { + display: none !important; + } +} +/*# sourceMappingURL=bootstrap-grid.rtl.css.map */ \ No newline at end of file diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css.map b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css.map new file mode 100644 index 0000000..8df43cf --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../scss/mixins/_banner.scss","../../scss/_containers.scss","../../scss/mixins/_container.scss","bootstrap-grid.css","../../scss/mixins/_breakpoints.scss","../../scss/_variables.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/mixins/_utilities.scss","../../scss/utilities/_api.scss"],"names":[],"mappings":"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EE,mBAAA;EJ6+BR;EI1+BM;;IAEE,mBAAA;EJ4+BR;AACF;AKpiCQ;EAOI,0BAAA;ALgiCZ;;AKviCQ;EAOI,gCAAA;ALoiCZ;;AK3iCQ;EAOI,yBAAA;ALwiCZ;;AK/iCQ;EAOI,wBAAA;AL4iCZ;;AKnjCQ;EAOI,+BAAA;ALgjCZ;;AKvjCQ;EAOI,yBAAA;ALojCZ;;AK3jCQ;EAOI,6BAAA;ALwjCZ;;AK/jCQ;EAOI,8BAAA;AL4jCZ;;AKnkCQ;EAOI,wBAAA;ALgkCZ;;AKvkCQ;EAOI,+BAAA;ALokCZ;;AK3kCQ;EAOI,wBAAA;ALwkCZ;;AK/kCQ;EAOI,yBAAA;AL4kCZ;;AKnlCQ;EAOI,8BAAA;ALglCZ;;AKvlCQ;EAOI,iCAAA;ALolCZ;;AK3lCQ;EAOI,sCAAA;ALwlCZ;;AK/lCQ;EAOI,yCAAA;AL4lCZ;;AKnmCQ;EAOI,uBAAA;ALgmCZ;;AKvmCQ;EAOI,uBAAA;ALomCZ;;AK3mCQ;EAOI,yBAAA;ALwmCZ;;AK/mCQ;EAOI,yBAAA;AL4mCZ;;AKnnCQ;EAOI,0BAAA;ALgnCZ;;AKvnCQ;EAOI,4BAAA;ALonCZ;;AK3nCQ;EAOI,kCAAA;ALwnCZ;;AK/nCQ;EAOI,sCAAA;AL4nCZ;;AKnoCQ;EAOI,oCAAA;ALgoCZ;;AKvoCQ;EAOI,kCAAA;ALooCZ;;AK3oCQ;EAOI,yCAAA;ALwoCZ;;AK/oCQ;EAOI,wCAAA;AL4oCZ;;AKnpCQ;EAOI,wCAAA;ALgpCZ;;AKvpCQ;EAOI,kCAAA;ALopCZ;;AK3pCQ;EAOI,gCAAA;ALwpCZ;;AK/pCQ;EAOI,8BAAA;AL4pCZ;;AKnqCQ;EAOI,gCAAA;ALgqCZ;;AKvqCQ;EAOI,+BAAA;ALoqCZ;;AK3qCQ;EAOI,oCAAA;ALwqCZ;;AK/qCQ;EAOI,kCAAA;AL4qCZ;;AKnrCQ;EAOI,gCAAA;ALgrCZ;;AKvrCQ;EAOI,uCAAA;ALorCZ;;AK3rCQ;EAOI,sCAAA;ALwrCZ;;AK/rCQ;EAOI,iCAAA;AL4rCZ;;AKnsCQ;EAOI,2BAAA;ALgsCZ;;AKvsCQ;EAOI,iCAAA;ALosCZ;;AK3sCQ;EAOI,+BAAA;ALwsCZ;;AK/sCQ;EAOI,6BAAA;AL4sCZ;;AKntCQ;EA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;AL8iDZ;;AKrjDQ;EAOI,4BAAA;ALkjDZ;;AKzjDQ;EAOI,0BAAA;ALsjDZ;;AK7jDQ;EAOI,gCAAA;AL0jDZ;;AKjkDQ;EAOI,+BAAA;AL8jDZ;;AKrkDQ;EAOI,6BAAA;ALkkDZ;;AKzkDQ;EAOI,+BAAA;ALskDZ;;AK7kDQ;EAOI,6BAAA;AL0kDZ;;AKjlDQ;EAOI,4BAAA;AL8kDZ;;AKrlDQ;EAOI,kCAAA;ALklDZ;;AKzlDQ;EAOI,iCAAA;ALslDZ;;AK7lDQ;EAOI,+BAAA;AL0lDZ;;AKjmDQ;EAOI,iCAAA;AL8lDZ;;AKrmDQ;EAOI,+BAAA;ALkmDZ;;AKzmDQ;EAOI,2BAAA;ALsmDZ;;AK7mDQ;EAOI,iCAAA;AL0mDZ;;AKjnDQ;EAOI,gCAAA;AL8mDZ;;AKrnDQ;EAOI,8BAAA;ALknDZ;;AKznDQ;EAOI,gCAAA;ALsnDZ;;AK7nDQ;EAOI,8BAAA;AL0nDZ;;ACpoDI;EIGI;IAOI,0BAAA;EL+nDV;EKtoDM;IAOI,gCAAA;ELkoDV;EKzoDM;IAOI,yBAAA;ELqoDV;EK5oDM;IAOI,wBAAA;ELwoDV;EK/oDM;IAOI,+BAAA;EL2oDV;EKlpDM;IAOI,yBAAA;EL8oDV;EKrpDM;IAOI,6BAAA;ELipDV;EKxpDM;IAOI,8BAAA;ELopDV;EK3pDM;IAOI,wBAAA;ELupDV;EK9pDM;IAOI,+BAAA;EL0pDV;EKjqDM;IAOI,wBAAA;EL6pDV;EKpqDM;IAOI,yBAAA;ELgqDV;EKvqDM;IAOI,8BAAA;ELmqDV;EK1qDM;IAOI,iCAAA;ELsqDV;EK7qDM;IAOI,sCAAA;ELyqDV;EKhrDM;IAOI,yCAAA;EL4qDV;EKnrDM;IAOI,uBAAA;EL+qDV;EKtrDM;IAOI,uBAAA;ELkrDV;EKzrDM;IAOI,yBAAA;ELqrDV;EK5rDM;IAOI,yBAAA;ELwrDV;EK/rDM;IAOI,0BAAA;EL2rDV;EKlsDM;IAOI,4BAAA;EL8rDV;EKrsDM;IAOI,kCAAA;ELisDV;EKxsDM;IAOI,sCAAA;ELosDV;EK3sDM;IAOI,oCAAA;ELusDV;EK9sDM;IAOI,kCAAA;EL0sDV;EKjtDM;IAOI,yCAAA;EL6sDV;EKptDM;IAOI,wCAAA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nEV;EK/nEM;IAOI,yCAAA;EL2nEV;EKloEM;IAOI,uBAAA;EL8nEV;EKroEM;IAOI,uBAAA;ELioEV;EKxoEM;IAOI,yBAAA;ELooEV;EK3oEM;IAOI,yBAAA;ELuoEV;EK9oEM;IAOI,0BAAA;EL0oEV;EKjpEM;IAOI,4BAAA;EL6oEV;EKppEM;IAOI,kCAAA;ELgpEV;EKvpEM;IAOI,sCAAA;ELmpEV;EK1pEM;IAOI,oCAAA;ELspEV;EK7pEM;IAOI,kCAAA;ELypEV;EKhqEM;IAOI,yCAAA;EL4pEV;EKnqEM;IAOI,wCAAA;EL+pEV;EKtqEM;IAOI,wCAAA;ELkqEV;EKzqEM;IAOI,kCAAA;ELqqEV;EK5qEM;IAOI,gCAAA;ELwqEV;EK/qEM;IAOI,8BAAA;EL2qEV;EKlrEM;IAOI,gCAAA;EL8qEV;EKrrEM;IAOI,+BAAA;ELirEV;EKxrEM;IAOI,oCAAA;ELorEV;EK3rEM;IAOI,kCAAA;ELurEV;EK9rEM;IAOI,gCAAA;EL0rEV;EKjsEM;IAOI,uCAAA;EL6rEV;EKpsEM;IAOI,sCAAA;ELgsEV;EKvsEM;IAOI,iCAAA;ELmsEV;EK1sEM;IAOI,2BAAA;ELssEV;EK7sEM;IAOI,iCAAA;ELysEV;EKhtEM;IAOI,+BAAA;EL4sEV;EKntEM;IAOI,6BAAA;EL+sEV;EKttEM;IAOI,+BAAA;ELktEV;EKztEM;IAOI,8BAAA;ELqtEV;EK5tEM;IAOI,oBAAA;ELwtEV;EK/tEM;IAOI,mBAAA;EL2tEV;EKluEM;IAOI,mBAAA;EL8tEV;EKruEM;IAOI,mBAAA;ELiuEV;EKxuEM;IAOI,mBAAA;ELouEV;EK3uEM;IAOI,mBAAA;ELuuEV;EK9uEM;IAOI,mBAAA;EL0uEV;EKjvEM;IAOI,mBAAA;EL6uEV;EKpvEM;IAOI,oBAAA;ELgvEV;EKvvEM;IAOI,0BAAA;ELmvEV;EK1vEM;IAOI,yBAAA;ELsvEV;EK7vEM;IAOI,uBAAA;ELyvEV;EKhwEM;IAOI,yBAAA;EL4vEV;EKnwEM;IAOI,uBAAA;EL+vEV;EKtwEM;IAOI,uBAAA;ELkwEV;EKzwEM;IAOI,yBAAA;IAAA,0BAAA;ELswEV;EK7wEM;IAO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EKviFM;IAOI,yBAAA;ELmiFV;EK1iFM;IAOI,wBAAA;ELsiFV;EK7iFM;IAOI,+BAAA;ELyiFV;EKhjFM;IAOI,yBAAA;EL4iFV;EKnjFM;IAOI,6BAAA;EL+iFV;EKtjFM;IAOI,8BAAA;ELkjFV;EKzjFM;IAOI,wBAAA;ELqjFV;EK5jFM;IAOI,+BAAA;ELwjFV;EK/jFM;IAOI,wBAAA;EL2jFV;EKlkFM;IAOI,yBAAA;EL8jFV;EKrkFM;IAOI,8BAAA;ELikFV;EKxkFM;IAOI,iCAAA;ELokFV;EK3kFM;IAOI,sCAAA;ELukFV;EK9kFM;IAOI,yCAAA;EL0kFV;EKjlFM;IAOI,uBAAA;EL6kFV;EKplFM;IAOI,uBAAA;ELglFV;EKvlFM;IAOI,yBAAA;ELmlFV;EK1lFM;IAOI,yBAAA;ELslFV;EK7lFM;IAOI,0BAAA;ELylFV;EKhmFM;IAOI,4BAAA;EL4lFV;EKnmFM;IAOI,kCAAA;EL+lFV;EKtmFM;IAOI,sCAAA;ELkmFV;EKzmFM;IAOI,oCAAA;ELqmFV;EK5mFM;IAOI,kCAAA;ELwmFV;EK/mFM;IAOI,yCAAA;EL2mFV;EKlnFM;IAOI,wCAAA;EL8mFV;EKrnFM;IAOI,wCAAA;ELinFV;EKxnFM;IAOI,kCAAA;ELonFV;EK3nFM;IAOI,gCAAA;ELunFV;EK9nFM;IAOI,8BAAA;EL0nFV;EKjoFM;IAOI,gCAAA;EL6nFV;EKpoFM;IAOI,+BAAA;ELgoFV;EKvoFM;IAOI,oCAAA;ELmoFV;EK1oFM;IAOI,kCAAA;ELsoFV;EK7oFM;IAOI,gCAAA;ELyoFV;EKhpFM;IAOI,uCAAA;EL4oFV;EKnpFM;IAOI,sCAAA;EL+oFV;EKtpFM;IAOI,iCAAA;ELkpFV;EKzpFM;IAOI,2BAAA;ELqpFV;EK5pFM;IAOI,iCAAA;ELwpFV;EK/pFM;IAOI,+BAAA;EL2pFV;EKlqFM;IAOI,6BAAA;EL8pFV;EKrqFM;IAOI,+BAAA;ELiqFV;EKxqFM;IAOI,8BAAA;ELoqFV;EK3qFM;IAOI,oBAAA;ELuqFV;EK9qFM;IAOI,mBAAA;EL0qFV;EKjrFM;IAOI,mBAAA;EL6qFV;EKprFM;IAOI,mBAAA;ELgrFV;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AAA;ELy8FV;EKh9FM;IAOI,iCAAA;EL48FV;EKn9FM;IAOI,+BAAA;EL+8FV;EKt9FM;IAOI,iCAAA;ELk9FV;EKz9FM;IAOI,+BAAA;ELq9FV;EK59FM;IAOI,2BAAA;ELw9FV;EK/9FM;IAOI,iCAAA;EL29FV;EKl+FM;IAOI,gCAAA;EL89FV;EKr+FM;IAOI,8BAAA;ELi+FV;EKx+FM;IAOI,gCAAA;ELo+FV;EK3+FM;IAOI,8BAAA;ELu+FV;AACF;ACl/FI;EIGI;IAOI,0BAAA;EL4+FV;EKn/FM;IAOI,gCAAA;EL++FV;EKt/FM;IAOI,yBAAA;ELk/FV;EKz/FM;IAOI,wBAAA;ELq/FV;EK5/FM;IAOI,+BAAA;ELw/FV;EK//FM;IAOI,yBAAA;EL2/FV;EKlgGM;IAOI,6BAAA;EL8/FV;EKrgGM;IAOI,8BAAA;ELigGV;EKxgGM;IAOI,wBAAA;ELogGV;EK3gGM;IAOI,+BAAA;ELugGV;EK9gGM;IAOI,wBAAA;EL0gGV;EKjhGM;IAOI,yBAAA;EL6gGV;EKphGM;IAOI,8BAAA;ELghGV;EKvhGM;IAOI,iCAAA;ELmhGV;EK1hGM;IAOI,sCAAA;ELshGV;EK7hGM;IAOI,yCAAA;ELyhGV;EKhiGM;IAOI,uBAAA;EL4hGV;EKniGM;IAOI,uBAAA;EL+hGV;EKtiGM;IAOI,yBAAA;ELkiGV;EKziGM;IAOI,yBAAA;ELqiGV;EK5iGM;IAOI,0BAAA;ELwiGV;EK/iGM;IAOI,4BAAA;EL2iGV;EKljGM;IAOI,kCAAA;EL8iGV;EKrjGM;IAOI,sCAAA;ELijGV;EKxjGM;IAOI,oCAAA;ELojGV;EK3jGM;IAOI,kCAAA;ELujGV;EK9jGM;IAOI,yCAAA;EL0jGV;EKjkGM;IAOI,wCAAA;EL6jGV;EKpkGM;IAOI,wCAAA;ELgkGV;EKvkGM;IAOI,kCAAA;ELmkGV;EK1kGM;IAOI,gCAAA;ELskGV;EK7kGM;IAOI,8BAAA;ELykGV;EKhlGM;IAOI,gCAAA;EL4kGV;EKnlGM;IAOI,+BAAA;EL+kGV;EKtlGM;IAOI,oCAAA;ELklGV;EKzlGM;IAOI,kCAAA;ELqlGV;EK5lGM;IAOI,gCAAA;ELwlGV;EK/l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ELi3GV;EKx3GM;IAOI,+BAAA;ELo3GV;EK33GM;IAOI,8BAAA;ELu3GV;EK93GM;IAOI,4BAAA;EL03GV;EKj4GM;IAOI,8BAAA;EL63GV;EKp4GM;IAOI,4BAAA;ELg4GV;EKv4GM;IAOI,0BAAA;ELm4GV;EK14GM;IAOI,gCAAA;ELs4GV;EK74GM;IAOI,+BAAA;ELy4GV;EKh5GM;IAOI,6BAAA;EL44GV;EKn5GM;IAOI,+BAAA;EL+4GV;EKt5GM;IAOI,6BAAA;ELk5GV;EKz5GM;IAOI,4BAAA;ELq5GV;EK55GM;IAOI,kCAAA;ELw5GV;EK/5GM;IAOI,iCAAA;EL25GV;EKl6GM;IAOI,+BAAA;EL85GV;EKr6GM;IAOI,iCAAA;ELi6GV;EKx6GM;IAOI,+BAAA;ELo6GV;EK36GM;IAOI,2BAAA;ELu6GV;EK96GM;IAOI,iCAAA;EL06GV;EKj7GM;IAOI,gCAAA;EL66GV;EKp7GM;IAOI,8BAAA;ELg7GV;EKv7GM;IAOI,gCAAA;ELm7GV;EK17GM;IAOI,8BAAA;ELs7GV;AACF;ACj8GI;EIGI;IAOI,0BAAA;EL27GV;EKl8GM;IAOI,gCAAA;EL87GV;EKr8GM;IAOI,yBAAA;ELi8GV;EKx8GM;IAOI,wBAAA;ELo8GV;EK38GM;IAOI,+BAAA;ELu8GV;EK98GM;IAOI,yBAAA;EL08GV;EKj9GM;IAOI,6BAAA;EL68GV;EKp9GM;IAOI,8BAAA;ELg9GV;EKv9GM;IAOI,wBAAA;ELm9GV;EK19GM;IAOI,+BAAA;ELs9GV;EK79GM;IAOI,wBAAA;ELy9GV;EKh+GM;IAOI,yBAAA;EL49GV;EKn+GM;IAOI,8BAAA;EL+9GV;EKt+GM;IAOI,iCAAA;ELk+GV;EKz+GM;IAOI,sCAAA;ELq+GV;EK5+GM;IAOI,yCAAA;ELw+GV;EK/+GM;IAOI,uBAAA;EL2+GV;EKl/GM;IAOI,uBAAA;EL8+GV;EKr/GM;IAOI,yBAAA;ELi/GV;EKx/GM;IAOI,yBAAA;ELo/GV;EK3/GM;IAOI,0BAAA;ELu/GV;EK9/GM;IAOI,4BAAA;EL0/GV;EKjgHM;IAOI,kCAAA;EL6/GV;EKpgHM;IAOI,sCAAA;ELggHV;EKvgHM;I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","file":"bootstrap-grid.rtl.css","sourcesContent":["@mixin bsBanner($file) {\n /*!\n * Bootstrap #{$file} v5.3.3 (https://getbootstrap.com/)\n * Copyright 2011-2024 The Bootstrap Authors\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n}\n","// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n@if $enable-container-classes {\n // Single container class with breakpoint max-widths\n .container,\n // 100% wide container at all breakpoints\n .container-fluid {\n @include make-container();\n }\n\n // Responsive containers that are 100% wide until a breakpoint\n @each $breakpoint, $container-max-width in $container-max-widths {\n .container-#{$breakpoint} {\n @extend .container-fluid;\n }\n\n @include media-breakpoint-up($breakpoint, $grid-breakpoints) {\n %responsive-container-#{$breakpoint} {\n max-width: $container-max-width;\n }\n\n // Extend each breakpoint which is smaller or equal to the current breakpoint\n $extend-breakpoint: true;\n\n @each $name, $width in $grid-breakpoints {\n @if ($extend-breakpoint) {\n .container#{breakpoint-infix($name, $grid-breakpoints)} {\n @extend %responsive-container-#{$breakpoint};\n }\n\n // Once the current breakpoint is reached, stop extending\n @if ($breakpoint == $name) {\n $extend-breakpoint: false;\n }\n }\n }\n }\n }\n}\n","// Container mixins\n\n@mixin make-container($gutter: $container-padding-x) {\n --#{$prefix}gutter-x: #{$gutter};\n --#{$prefix}gutter-y: 0;\n width: 100%;\n padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n margin-right: auto;\n margin-left: auto;\n}\n","/*!\n * Bootstrap Grid v5.3.3 (https://getbootstrap.com/)\n * Copyright 2011-2024 The Bootstrap Authors\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n.container,\n.container-fluid,\n.container-xxl,\n.container-xl,\n.container-lg,\n.container-md,\n.container-sm {\n --bs-gutter-x: 1.5rem;\n --bs-gutter-y: 0;\n width: 100%;\n padding-right: calc(var(--bs-gutter-x) * 0.5);\n padding-left: calc(var(--bs-gutter-x) * 0.5);\n margin-right: auto;\n margin-left: auto;\n}\n\n@media (min-width: 576px) {\n .container-sm, .container {\n max-width: 540px;\n }\n}\n@media (min-width: 768px) {\n .container-md, .container-sm, .container {\n max-width: 720px;\n }\n}\n@media (min-width: 992px) {\n .container-lg, .container-md, .container-sm, .container {\n max-width: 960px;\n }\n}\n@media (min-width: 1200px) {\n .container-xl, .container-lg, .container-md, .container-sm, .container {\n max-width: 1140px;\n }\n}\n@media (min-width: 1400px) {\n .container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container {\n max-width: 1320px;\n }\n}\n:root {\n --bs-breakpoint-xs: 0;\n --bs-breakpoint-sm: 576px;\n --bs-breakpoint-md: 768px;\n --bs-breakpoint-lg: 992px;\n --bs-breakpoint-xl: 1200px;\n --bs-breakpoint-xxl: 1400px;\n}\n\n.row {\n --bs-gutter-x: 1.5rem;\n --bs-gutter-y: 0;\n display: flex;\n flex-wrap: wrap;\n margin-top: calc(-1 * var(--bs-gutter-y));\n margin-right: calc(-0.5 * var(--bs-gutter-x));\n margin-left: calc(-0.5 * var(--bs-gutter-x));\n}\n.row > * {\n box-sizing: border-box;\n flex-shrink: 0;\n width: 100%;\n max-width: 100%;\n padding-right: calc(var(--bs-gutter-x) * 0.5);\n padding-left: calc(var(--bs-gutter-x) * 0.5);\n margin-top: var(--bs-gutter-y);\n}\n\n.col {\n flex: 1 0 0%;\n}\n\n.row-cols-auto > * {\n flex: 0 0 auto;\n width: auto;\n}\n\n.row-cols-1 > * {\n flex: 0 0 auto;\n width: 100%;\n}\n\n.row-cols-2 > * {\n flex: 0 0 auto;\n width: 50%;\n}\n\n.row-cols-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n}\n\n.row-cols-4 > * {\n flex: 0 0 auto;\n width: 25%;\n}\n\n.row-cols-5 > * {\n flex: 0 0 auto;\n width: 20%;\n}\n\n.row-cols-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n}\n\n.col-auto {\n flex: 0 0 auto;\n width: auto;\n}\n\n.col-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n}\n\n.col-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n}\n\n.col-3 {\n flex: 0 0 auto;\n width: 25%;\n}\n\n.col-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n}\n\n.col-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n}\n\n.col-6 {\n flex: 0 0 auto;\n width: 50%;\n}\n\n.col-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n}\n\n.col-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n}\n\n.col-9 {\n flex: 0 0 auto;\n width: 75%;\n}\n\n.col-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n}\n\n.col-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n}\n\n.col-12 {\n flex: 0 0 auto;\n width: 100%;\n}\n\n.offset-1 {\n margin-left: 8.33333333%;\n}\n\n.offset-2 {\n margin-left: 16.66666667%;\n}\n\n.offset-3 {\n margin-left: 25%;\n}\n\n.offset-4 {\n margin-left: 33.33333333%;\n}\n\n.offset-5 {\n margin-left: 41.66666667%;\n}\n\n.offset-6 {\n margin-left: 50%;\n}\n\n.offset-7 {\n margin-left: 58.33333333%;\n}\n\n.offset-8 {\n margin-left: 66.66666667%;\n}\n\n.offset-9 {\n margin-left: 75%;\n}\n\n.offset-10 {\n margin-left: 83.33333333%;\n}\n\n.offset-11 {\n margin-left: 91.66666667%;\n}\n\n.g-0,\n.gx-0 {\n --bs-gutter-x: 0;\n}\n\n.g-0,\n.gy-0 {\n --bs-gutter-y: 0;\n}\n\n.g-1,\n.gx-1 {\n --bs-gutter-x: 0.25rem;\n}\n\n.g-1,\n.gy-1 {\n --bs-gutter-y: 0.25rem;\n}\n\n.g-2,\n.gx-2 {\n --bs-gutter-x: 0.5rem;\n}\n\n.g-2,\n.gy-2 {\n --bs-gutter-y: 0.5rem;\n}\n\n.g-3,\n.gx-3 {\n --bs-gutter-x: 1rem;\n}\n\n.g-3,\n.gy-3 {\n --bs-gutter-y: 1rem;\n}\n\n.g-4,\n.gx-4 {\n --bs-gutter-x: 1.5rem;\n}\n\n.g-4,\n.gy-4 {\n --bs-gutter-y: 1.5rem;\n}\n\n.g-5,\n.gx-5 {\n --bs-gutter-x: 3rem;\n}\n\n.g-5,\n.gy-5 {\n --bs-gutter-y: 3rem;\n}\n\n@media (min-width: 576px) {\n .col-sm {\n flex: 1 0 0%;\n }\n .row-cols-sm-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-sm-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-sm-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-sm-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-sm-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-sm-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-sm-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-sm-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-sm-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-sm-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-sm-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-sm-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-sm-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-sm-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-sm-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-sm-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-sm-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-sm-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-sm-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-sm-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-sm-0 {\n margin-left: 0;\n }\n .offset-sm-1 {\n margin-left: 8.33333333%;\n }\n .offset-sm-2 {\n margin-left: 16.66666667%;\n }\n .offset-sm-3 {\n margin-left: 25%;\n }\n .offset-sm-4 {\n margin-left: 33.33333333%;\n }\n .offset-sm-5 {\n margin-left: 41.66666667%;\n }\n .offset-sm-6 {\n margin-left: 50%;\n }\n .offset-sm-7 {\n margin-left: 58.33333333%;\n }\n .offset-sm-8 {\n margin-left: 66.66666667%;\n }\n .offset-sm-9 {\n margin-left: 75%;\n }\n .offset-sm-10 {\n margin-left: 83.33333333%;\n }\n .offset-sm-11 {\n margin-left: 91.66666667%;\n }\n .g-sm-0,\n .gx-sm-0 {\n --bs-gutter-x: 0;\n }\n .g-sm-0,\n .gy-sm-0 {\n --bs-gutter-y: 0;\n }\n .g-sm-1,\n .gx-sm-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-sm-1,\n .gy-sm-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-sm-2,\n .gx-sm-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-sm-2,\n .gy-sm-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-sm-3,\n .gx-sm-3 {\n --bs-gutter-x: 1rem;\n }\n .g-sm-3,\n .gy-sm-3 {\n --bs-gutter-y: 1rem;\n }\n .g-sm-4,\n .gx-sm-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-sm-4,\n .gy-sm-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-sm-5,\n .gx-sm-5 {\n --bs-gutter-x: 3rem;\n }\n .g-sm-5,\n .gy-sm-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 768px) {\n .col-md {\n flex: 1 0 0%;\n }\n .row-cols-md-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-md-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-md-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-md-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-md-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-md-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-md-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-md-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-md-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-md-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-md-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-md-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-md-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-md-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-md-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-md-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-md-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-md-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-md-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-md-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-md-0 {\n margin-left: 0;\n }\n .offset-md-1 {\n margin-left: 8.33333333%;\n }\n .offset-md-2 {\n margin-left: 16.66666667%;\n }\n .offset-md-3 {\n margin-left: 25%;\n }\n .offset-md-4 {\n margin-left: 33.33333333%;\n }\n .offset-md-5 {\n margin-left: 41.66666667%;\n }\n .offset-md-6 {\n margin-left: 50%;\n }\n .offset-md-7 {\n margin-left: 58.33333333%;\n }\n .offset-md-8 {\n margin-left: 66.66666667%;\n }\n .offset-md-9 {\n margin-left: 75%;\n }\n .offset-md-10 {\n margin-left: 83.33333333%;\n }\n .offset-md-11 {\n margin-left: 91.66666667%;\n }\n .g-md-0,\n .gx-md-0 {\n --bs-gutter-x: 0;\n }\n .g-md-0,\n .gy-md-0 {\n --bs-gutter-y: 0;\n }\n .g-md-1,\n .gx-md-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-md-1,\n .gy-md-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-md-2,\n .gx-md-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-md-2,\n .gy-md-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-md-3,\n .gx-md-3 {\n --bs-gutter-x: 1rem;\n }\n .g-md-3,\n .gy-md-3 {\n --bs-gutter-y: 1rem;\n }\n .g-md-4,\n .gx-md-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-md-4,\n .gy-md-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-md-5,\n .gx-md-5 {\n --bs-gutter-x: 3rem;\n }\n .g-md-5,\n .gy-md-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 992px) {\n .col-lg {\n flex: 1 0 0%;\n }\n .row-cols-lg-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-lg-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-lg-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-lg-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-lg-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-lg-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-lg-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-lg-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-lg-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-lg-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-lg-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-lg-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-lg-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-lg-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-lg-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-lg-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-lg-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-lg-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-lg-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-lg-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-lg-0 {\n margin-left: 0;\n }\n .offset-lg-1 {\n margin-left: 8.33333333%;\n }\n .offset-lg-2 {\n margin-left: 16.66666667%;\n }\n .offset-lg-3 {\n margin-left: 25%;\n }\n .offset-lg-4 {\n margin-left: 33.33333333%;\n }\n .offset-lg-5 {\n margin-left: 41.66666667%;\n }\n .offset-lg-6 {\n margin-left: 50%;\n }\n .offset-lg-7 {\n margin-left: 58.33333333%;\n }\n .offset-lg-8 {\n margin-left: 66.66666667%;\n }\n .offset-lg-9 {\n margin-left: 75%;\n }\n .offset-lg-10 {\n margin-left: 83.33333333%;\n }\n .offset-lg-11 {\n margin-left: 91.66666667%;\n }\n .g-lg-0,\n .gx-lg-0 {\n --bs-gutter-x: 0;\n }\n .g-lg-0,\n .gy-lg-0 {\n --bs-gutter-y: 0;\n }\n .g-lg-1,\n .gx-lg-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-lg-1,\n .gy-lg-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-lg-2,\n .gx-lg-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-lg-2,\n .gy-lg-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-lg-3,\n .gx-lg-3 {\n --bs-gutter-x: 1rem;\n }\n .g-lg-3,\n .gy-lg-3 {\n --bs-gutter-y: 1rem;\n }\n .g-lg-4,\n .gx-lg-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-lg-4,\n .gy-lg-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-lg-5,\n .gx-lg-5 {\n --bs-gutter-x: 3rem;\n }\n .g-lg-5,\n .gy-lg-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 1200px) {\n .col-xl {\n flex: 1 0 0%;\n }\n .row-cols-xl-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-xl-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-xl-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-xl-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-xl-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-xl-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-xl-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xl-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-xl-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-xl-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xl-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-xl-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-xl-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-xl-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-xl-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-xl-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-xl-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-xl-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-xl-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-xl-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-xl-0 {\n margin-left: 0;\n }\n .offset-xl-1 {\n margin-left: 8.33333333%;\n }\n .offset-xl-2 {\n margin-left: 16.66666667%;\n }\n .offset-xl-3 {\n margin-left: 25%;\n }\n .offset-xl-4 {\n margin-left: 33.33333333%;\n }\n .offset-xl-5 {\n margin-left: 41.66666667%;\n }\n .offset-xl-6 {\n margin-left: 50%;\n }\n .offset-xl-7 {\n margin-left: 58.33333333%;\n }\n .offset-xl-8 {\n margin-left: 66.66666667%;\n }\n .offset-xl-9 {\n margin-left: 75%;\n }\n .offset-xl-10 {\n margin-left: 83.33333333%;\n }\n .offset-xl-11 {\n margin-left: 91.66666667%;\n }\n .g-xl-0,\n .gx-xl-0 {\n --bs-gutter-x: 0;\n }\n .g-xl-0,\n .gy-xl-0 {\n --bs-gutter-y: 0;\n }\n .g-xl-1,\n .gx-xl-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-xl-1,\n .gy-xl-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-xl-2,\n .gx-xl-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-xl-2,\n .gy-xl-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-xl-3,\n .gx-xl-3 {\n --bs-gutter-x: 1rem;\n }\n .g-xl-3,\n .gy-xl-3 {\n --bs-gutter-y: 1rem;\n }\n .g-xl-4,\n .gx-xl-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-xl-4,\n .gy-xl-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-xl-5,\n .gx-xl-5 {\n --bs-gutter-x: 3rem;\n }\n .g-xl-5,\n .gy-xl-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 1400px) {\n .col-xxl {\n flex: 1 0 0%;\n }\n .row-cols-xxl-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-xxl-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-xxl-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-xxl-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-xxl-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-xxl-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-xxl-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xxl-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-xxl-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-xxl-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xxl-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-xxl-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-xxl-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-xxl-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-xxl-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-xxl-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-xxl-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-xxl-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-xxl-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-xxl-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-xxl-0 {\n margin-left: 0;\n }\n .offset-xxl-1 {\n margin-left: 8.33333333%;\n }\n .offset-xxl-2 {\n margin-left: 16.66666667%;\n }\n .offset-xxl-3 {\n margin-left: 25%;\n }\n .offset-xxl-4 {\n margin-left: 33.33333333%;\n }\n .offset-xxl-5 {\n margin-left: 41.66666667%;\n }\n .offset-xxl-6 {\n margin-left: 50%;\n }\n .offset-xxl-7 {\n margin-left: 58.33333333%;\n }\n .offset-xxl-8 {\n margin-left: 66.66666667%;\n }\n .offset-xxl-9 {\n margin-left: 75%;\n }\n .offset-xxl-10 {\n margin-left: 83.33333333%;\n }\n .offset-xxl-11 {\n margin-left: 91.66666667%;\n }\n .g-xxl-0,\n .gx-xxl-0 {\n --bs-gutter-x: 0;\n }\n .g-xxl-0,\n .gy-xxl-0 {\n --bs-gutter-y: 0;\n }\n .g-xxl-1,\n .gx-xxl-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-xxl-1,\n .gy-xxl-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-xxl-2,\n .gx-xxl-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-xxl-2,\n .gy-xxl-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-xxl-3,\n .gx-xxl-3 {\n --bs-gutter-x: 1rem;\n }\n .g-xxl-3,\n .gy-xxl-3 {\n --bs-gutter-y: 1rem;\n }\n .g-xxl-4,\n .gx-xxl-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-xxl-4,\n .gy-xxl-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-xxl-5,\n .gx-xxl-5 {\n --bs-gutter-x: 3rem;\n }\n .g-xxl-5,\n .gy-xxl-5 {\n --bs-gutter-y: 3rem;\n }\n}\n.d-inline {\n display: inline !important;\n}\n\n.d-inline-block {\n display: inline-block !important;\n}\n\n.d-block {\n display: block !important;\n}\n\n.d-grid {\n display: grid !important;\n}\n\n.d-inline-grid {\n display: inline-grid !important;\n}\n\n.d-table {\n display: table !important;\n}\n\n.d-table-row {\n display: table-row !important;\n}\n\n.d-table-cell {\n display: table-cell !important;\n}\n\n.d-flex {\n display: flex !important;\n}\n\n.d-inline-flex {\n display: inline-flex !important;\n}\n\n.d-none {\n display: none !important;\n}\n\n.flex-fill {\n flex: 1 1 auto !important;\n}\n\n.flex-row {\n flex-direction: row !important;\n}\n\n.flex-column {\n flex-direction: column !important;\n}\n\n.flex-row-reverse {\n flex-direction: row-reverse !important;\n}\n\n.flex-column-reverse {\n flex-direction: column-reverse !important;\n}\n\n.flex-grow-0 {\n flex-grow: 0 !important;\n}\n\n.flex-grow-1 {\n flex-grow: 1 !important;\n}\n\n.flex-shrink-0 {\n flex-shrink: 0 !important;\n}\n\n.flex-shrink-1 {\n flex-shrink: 1 !important;\n}\n\n.flex-wrap {\n flex-wrap: wrap !important;\n}\n\n.flex-nowrap {\n flex-wrap: nowrap !important;\n}\n\n.flex-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n}\n\n.justify-content-start {\n justify-content: flex-start !important;\n}\n\n.justify-content-end {\n justify-content: flex-end !important;\n}\n\n.justify-content-center {\n justify-content: center !important;\n}\n\n.justify-content-between {\n justify-content: space-between !important;\n}\n\n.justify-content-around {\n justify-content: space-around !important;\n}\n\n.justify-content-evenly {\n justify-content: space-evenly !important;\n}\n\n.align-items-start {\n align-items: flex-start !important;\n}\n\n.align-items-end {\n align-items: flex-end !important;\n}\n\n.align-items-center {\n align-items: center !important;\n}\n\n.align-items-baseline {\n align-items: baseline !important;\n}\n\n.align-items-stretch {\n align-items: stretch !important;\n}\n\n.align-content-start {\n align-content: flex-start !important;\n}\n\n.align-content-end {\n align-content: flex-end !important;\n}\n\n.align-content-center {\n align-content: center !important;\n}\n\n.align-content-between {\n align-content: space-between !important;\n}\n\n.align-content-around {\n align-content: space-around !important;\n}\n\n.align-content-stretch {\n align-content: stretch !important;\n}\n\n.align-self-auto {\n align-self: auto !important;\n}\n\n.align-self-start {\n align-self: flex-start !important;\n}\n\n.align-self-end {\n align-self: flex-end !important;\n}\n\n.align-self-center {\n align-self: center !important;\n}\n\n.align-self-baseline {\n align-self: baseline !important;\n}\n\n.align-self-stretch {\n align-self: stretch !important;\n}\n\n.order-first {\n order: -1 !important;\n}\n\n.order-0 {\n order: 0 !important;\n}\n\n.order-1 {\n order: 1 !important;\n}\n\n.order-2 {\n order: 2 !important;\n}\n\n.order-3 {\n order: 3 !important;\n}\n\n.order-4 {\n order: 4 !important;\n}\n\n.order-5 {\n order: 5 !important;\n}\n\n.order-last {\n order: 6 !important;\n}\n\n.m-0 {\n margin: 0 !important;\n}\n\n.m-1 {\n margin: 0.25rem !important;\n}\n\n.m-2 {\n margin: 0.5rem !important;\n}\n\n.m-3 {\n margin: 1rem !important;\n}\n\n.m-4 {\n margin: 1.5rem !important;\n}\n\n.m-5 {\n margin: 3rem !important;\n}\n\n.m-auto {\n margin: auto !important;\n}\n\n.mx-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n}\n\n.mx-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n}\n\n.mx-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n}\n\n.mx-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n}\n\n.mx-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n}\n\n.mx-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n}\n\n.mx-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n}\n\n.my-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n.my-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n}\n\n.my-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n}\n\n.my-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n}\n\n.my-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n}\n\n.my-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n}\n\n.my-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n}\n\n.mt-0 {\n margin-top: 0 !important;\n}\n\n.mt-1 {\n margin-top: 0.25rem !important;\n}\n\n.mt-2 {\n margin-top: 0.5rem !important;\n}\n\n.mt-3 {\n margin-top: 1rem !important;\n}\n\n.mt-4 {\n margin-top: 1.5rem !important;\n}\n\n.mt-5 {\n margin-top: 3rem !important;\n}\n\n.mt-auto {\n margin-top: auto !important;\n}\n\n.me-0 {\n margin-right: 0 !important;\n}\n\n.me-1 {\n margin-right: 0.25rem !important;\n}\n\n.me-2 {\n margin-right: 0.5rem !important;\n}\n\n.me-3 {\n margin-right: 1rem !important;\n}\n\n.me-4 {\n margin-right: 1.5rem !important;\n}\n\n.me-5 {\n margin-right: 3rem !important;\n}\n\n.me-auto {\n margin-right: auto !important;\n}\n\n.mb-0 {\n margin-bottom: 0 !important;\n}\n\n.mb-1 {\n margin-bottom: 0.25rem !important;\n}\n\n.mb-2 {\n margin-bottom: 0.5rem !important;\n}\n\n.mb-3 {\n margin-bottom: 1rem !important;\n}\n\n.mb-4 {\n margin-bottom: 1.5rem !important;\n}\n\n.mb-5 {\n margin-bottom: 3rem !important;\n}\n\n.mb-auto {\n margin-bottom: auto !important;\n}\n\n.ms-0 {\n margin-left: 0 !important;\n}\n\n.ms-1 {\n margin-left: 0.25rem !important;\n}\n\n.ms-2 {\n margin-left: 0.5rem !important;\n}\n\n.ms-3 {\n margin-left: 1rem !important;\n}\n\n.ms-4 {\n margin-left: 1.5rem !important;\n}\n\n.ms-5 {\n margin-left: 3rem !important;\n}\n\n.ms-auto {\n margin-left: auto !important;\n}\n\n.p-0 {\n padding: 0 !important;\n}\n\n.p-1 {\n padding: 0.25rem !important;\n}\n\n.p-2 {\n padding: 0.5rem !important;\n}\n\n.p-3 {\n padding: 1rem !important;\n}\n\n.p-4 {\n padding: 1.5rem !important;\n}\n\n.p-5 {\n padding: 3rem !important;\n}\n\n.px-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n}\n\n.px-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n}\n\n.px-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n}\n\n.px-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n}\n\n.px-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n}\n\n.px-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n}\n\n.py-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n}\n\n.py-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n}\n\n.py-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n}\n\n.py-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n}\n\n.py-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n}\n\n.py-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n}\n\n.pt-0 {\n padding-top: 0 !important;\n}\n\n.pt-1 {\n padding-top: 0.25rem !important;\n}\n\n.pt-2 {\n padding-top: 0.5rem !important;\n}\n\n.pt-3 {\n padding-top: 1rem !important;\n}\n\n.pt-4 {\n padding-top: 1.5rem !important;\n}\n\n.pt-5 {\n padding-top: 3rem !important;\n}\n\n.pe-0 {\n padding-right: 0 !important;\n}\n\n.pe-1 {\n padding-right: 0.25rem !important;\n}\n\n.pe-2 {\n padding-right: 0.5rem !important;\n}\n\n.pe-3 {\n padding-right: 1rem !important;\n}\n\n.pe-4 {\n padding-right: 1.5rem !important;\n}\n\n.pe-5 {\n padding-right: 3rem !important;\n}\n\n.pb-0 {\n padding-bottom: 0 !important;\n}\n\n.pb-1 {\n padding-bottom: 0.25rem !important;\n}\n\n.pb-2 {\n padding-bottom: 0.5rem !important;\n}\n\n.pb-3 {\n padding-bottom: 1rem !important;\n}\n\n.pb-4 {\n padding-bottom: 1.5rem !important;\n}\n\n.pb-5 {\n padding-bottom: 3rem !important;\n}\n\n.ps-0 {\n padding-left: 0 !important;\n}\n\n.ps-1 {\n padding-left: 0.25rem !important;\n}\n\n.ps-2 {\n padding-left: 0.5rem !important;\n}\n\n.ps-3 {\n padding-left: 1rem !important;\n}\n\n.ps-4 {\n padding-left: 1.5rem !important;\n}\n\n.ps-5 {\n padding-left: 3rem !important;\n}\n\n@media (min-width: 576px) {\n .d-sm-inline {\n display: inline !important;\n }\n .d-sm-inline-block {\n display: inline-block !important;\n }\n .d-sm-block {\n display: block !important;\n }\n .d-sm-grid {\n display: grid !important;\n }\n .d-sm-inline-grid {\n display: inline-grid !important;\n }\n .d-sm-table {\n display: table !important;\n }\n .d-sm-table-row {\n display: table-row !important;\n }\n .d-sm-table-cell {\n display: table-cell !important;\n }\n .d-sm-flex {\n display: flex !important;\n }\n .d-sm-inline-flex {\n display: inline-flex !important;\n }\n .d-sm-none {\n display: none !important;\n }\n .flex-sm-fill {\n flex: 1 1 auto !important;\n }\n .flex-sm-row {\n flex-direction: row !important;\n }\n .flex-sm-column {\n flex-direction: column !important;\n }\n .flex-sm-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-sm-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-sm-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-sm-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-sm-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-sm-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-sm-wrap {\n flex-wrap: wrap !important;\n }\n .flex-sm-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-sm-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-sm-start {\n justify-content: flex-start !important;\n }\n .justify-content-sm-end {\n justify-content: flex-end !important;\n }\n .justify-content-sm-center {\n justify-content: center !important;\n }\n .justify-content-sm-between {\n justify-content: space-between !important;\n }\n .justify-content-sm-around {\n justify-content: space-around !important;\n }\n .justify-content-sm-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-sm-start {\n align-items: flex-start !important;\n }\n .align-items-sm-end {\n align-items: flex-end !important;\n }\n .align-items-sm-center {\n align-items: center !important;\n }\n .align-items-sm-baseline {\n align-items: baseline !important;\n }\n .align-items-sm-stretch {\n align-items: stretch !important;\n }\n .align-content-sm-start {\n align-content: flex-start !important;\n }\n .align-content-sm-end {\n align-content: flex-end !important;\n }\n .align-content-sm-center {\n align-content: center !important;\n }\n .align-content-sm-between {\n align-content: space-between !important;\n }\n .align-content-sm-around {\n align-content: space-around !important;\n }\n .align-content-sm-stretch {\n align-content: stretch !important;\n }\n .align-self-sm-auto {\n align-self: auto !important;\n }\n .align-self-sm-start {\n align-self: flex-start !important;\n }\n .align-self-sm-end {\n align-self: flex-end !important;\n }\n .align-self-sm-center {\n align-self: center !important;\n }\n .align-self-sm-baseline {\n align-self: baseline !important;\n }\n .align-self-sm-stretch {\n align-self: stretch !important;\n }\n .order-sm-first {\n order: -1 !important;\n }\n .order-sm-0 {\n order: 0 !important;\n }\n .order-sm-1 {\n order: 1 !important;\n }\n .order-sm-2 {\n order: 2 !important;\n }\n .order-sm-3 {\n order: 3 !important;\n }\n .order-sm-4 {\n order: 4 !important;\n }\n .order-sm-5 {\n order: 5 !important;\n }\n .order-sm-last {\n order: 6 !important;\n }\n .m-sm-0 {\n margin: 0 !important;\n }\n .m-sm-1 {\n margin: 0.25rem !important;\n }\n .m-sm-2 {\n margin: 0.5rem !important;\n }\n .m-sm-3 {\n margin: 1rem !important;\n }\n .m-sm-4 {\n margin: 1.5rem !important;\n }\n .m-sm-5 {\n margin: 3rem !important;\n }\n .m-sm-auto {\n margin: auto !important;\n }\n .mx-sm-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-sm-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-sm-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-sm-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-sm-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-sm-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-sm-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-sm-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-sm-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-sm-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-sm-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-sm-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-sm-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-sm-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-sm-0 {\n margin-top: 0 !important;\n }\n .mt-sm-1 {\n margin-top: 0.25rem !important;\n }\n .mt-sm-2 {\n margin-top: 0.5rem !important;\n }\n .mt-sm-3 {\n margin-top: 1rem !important;\n }\n .mt-sm-4 {\n margin-top: 1.5rem !important;\n }\n .mt-sm-5 {\n margin-top: 3rem !important;\n }\n .mt-sm-auto {\n margin-top: auto !important;\n }\n .me-sm-0 {\n margin-right: 0 !important;\n }\n .me-sm-1 {\n margin-right: 0.25rem !important;\n }\n .me-sm-2 {\n margin-right: 0.5rem !important;\n }\n .me-sm-3 {\n margin-right: 1rem !important;\n }\n .me-sm-4 {\n margin-right: 1.5rem !important;\n }\n .me-sm-5 {\n margin-right: 3rem !important;\n }\n .me-sm-auto {\n margin-right: auto !important;\n }\n .mb-sm-0 {\n margin-bottom: 0 !important;\n }\n .mb-sm-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-sm-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-sm-3 {\n margin-bottom: 1rem !important;\n }\n .mb-sm-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-sm-5 {\n margin-bottom: 3rem !important;\n }\n .mb-sm-auto {\n margin-bottom: auto !important;\n }\n .ms-sm-0 {\n margin-left: 0 !important;\n }\n .ms-sm-1 {\n margin-left: 0.25rem !important;\n }\n .ms-sm-2 {\n margin-left: 0.5rem !important;\n }\n .ms-sm-3 {\n margin-left: 1rem !important;\n }\n .ms-sm-4 {\n margin-left: 1.5rem !important;\n }\n .ms-sm-5 {\n margin-left: 3rem !important;\n }\n .ms-sm-auto {\n margin-left: auto !important;\n }\n .p-sm-0 {\n padding: 0 !important;\n }\n .p-sm-1 {\n padding: 0.25rem !important;\n }\n .p-sm-2 {\n padding: 0.5rem !important;\n }\n .p-sm-3 {\n padding: 1rem !important;\n }\n .p-sm-4 {\n padding: 1.5rem !important;\n }\n .p-sm-5 {\n padding: 3rem !important;\n }\n .px-sm-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-sm-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-sm-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-sm-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-sm-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-sm-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-sm-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-sm-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-sm-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-sm-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-sm-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-sm-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-sm-0 {\n padding-top: 0 !important;\n }\n .pt-sm-1 {\n padding-top: 0.25rem !important;\n }\n .pt-sm-2 {\n padding-top: 0.5rem !important;\n }\n .pt-sm-3 {\n padding-top: 1rem !important;\n }\n .pt-sm-4 {\n padding-top: 1.5rem !important;\n }\n .pt-sm-5 {\n padding-top: 3rem !important;\n }\n .pe-sm-0 {\n padding-right: 0 !important;\n }\n .pe-sm-1 {\n padding-right: 0.25rem !important;\n }\n .pe-sm-2 {\n padding-right: 0.5rem !important;\n }\n .pe-sm-3 {\n padding-right: 1rem !important;\n }\n .pe-sm-4 {\n padding-right: 1.5rem !important;\n }\n .pe-sm-5 {\n padding-right: 3rem !important;\n }\n .pb-sm-0 {\n padding-bottom: 0 !important;\n }\n .pb-sm-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-sm-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-sm-3 {\n padding-bottom: 1rem !important;\n }\n .pb-sm-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-sm-5 {\n padding-bottom: 3rem !important;\n }\n .ps-sm-0 {\n padding-left: 0 !important;\n }\n .ps-sm-1 {\n padding-left: 0.25rem !important;\n }\n .ps-sm-2 {\n padding-left: 0.5rem !important;\n }\n .ps-sm-3 {\n padding-left: 1rem !important;\n }\n .ps-sm-4 {\n padding-left: 1.5rem !important;\n }\n .ps-sm-5 {\n padding-left: 3rem !important;\n }\n}\n@media (min-width: 768px) {\n .d-md-inline {\n display: inline !important;\n }\n .d-md-inline-block {\n display: inline-block !important;\n }\n .d-md-block {\n display: block !important;\n }\n .d-md-grid {\n display: grid !important;\n }\n .d-md-inline-grid {\n display: inline-grid !important;\n }\n .d-md-table {\n display: table !important;\n }\n .d-md-table-row {\n display: table-row !important;\n }\n .d-md-table-cell {\n display: table-cell !important;\n }\n .d-md-flex {\n display: flex !important;\n }\n .d-md-inline-flex {\n display: inline-flex !important;\n }\n .d-md-none {\n display: none !important;\n }\n .flex-md-fill {\n flex: 1 1 auto !important;\n }\n .flex-md-row {\n flex-direction: row !important;\n }\n .flex-md-column {\n flex-direction: column !important;\n }\n .flex-md-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-md-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-md-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-md-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-md-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-md-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-md-wrap {\n flex-wrap: wrap !important;\n }\n .flex-md-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-md-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-md-start {\n justify-content: flex-start !important;\n }\n .justify-content-md-end {\n justify-content: flex-end !important;\n }\n .justify-content-md-center {\n justify-content: center !important;\n }\n .justify-content-md-between {\n justify-content: space-between !important;\n }\n .justify-content-md-around {\n justify-content: space-around !important;\n }\n .justify-content-md-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-md-start {\n align-items: flex-start !important;\n }\n .align-items-md-end {\n align-items: flex-end !important;\n }\n .align-items-md-center {\n align-items: center !important;\n }\n .align-items-md-baseline {\n align-items: baseline !important;\n }\n .align-items-md-stretch {\n align-items: stretch !important;\n }\n .align-content-md-start {\n align-content: flex-start !important;\n }\n .align-content-md-end {\n align-content: flex-end !important;\n }\n .align-content-md-center {\n align-content: center !important;\n }\n .align-content-md-between {\n align-content: space-between !important;\n }\n .align-content-md-around {\n align-content: space-around !important;\n }\n .align-content-md-stretch {\n align-content: stretch !important;\n }\n .align-self-md-auto {\n align-self: auto !important;\n }\n .align-self-md-start {\n align-self: flex-start !important;\n }\n .align-self-md-end {\n align-self: flex-end !important;\n }\n .align-self-md-center {\n align-self: center !important;\n }\n .align-self-md-baseline {\n align-self: baseline !important;\n }\n .align-self-md-stretch {\n align-self: stretch !important;\n }\n .order-md-first {\n order: -1 !important;\n }\n .order-md-0 {\n order: 0 !important;\n }\n .order-md-1 {\n order: 1 !important;\n }\n .order-md-2 {\n order: 2 !important;\n }\n .order-md-3 {\n order: 3 !important;\n }\n .order-md-4 {\n order: 4 !important;\n }\n .order-md-5 {\n order: 5 !important;\n }\n .order-md-last {\n order: 6 !important;\n }\n .m-md-0 {\n margin: 0 !important;\n }\n .m-md-1 {\n margin: 0.25rem !important;\n }\n .m-md-2 {\n margin: 0.5rem !important;\n }\n .m-md-3 {\n margin: 1rem !important;\n }\n .m-md-4 {\n margin: 1.5rem !important;\n }\n .m-md-5 {\n margin: 3rem !important;\n }\n .m-md-auto {\n margin: auto !important;\n }\n .mx-md-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-md-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-md-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-md-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-md-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-md-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-md-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-md-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-md-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-md-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-md-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-md-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-md-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-md-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-md-0 {\n margin-top: 0 !important;\n }\n .mt-md-1 {\n margin-top: 0.25rem !important;\n }\n .mt-md-2 {\n margin-top: 0.5rem !important;\n }\n .mt-md-3 {\n margin-top: 1rem !important;\n }\n .mt-md-4 {\n margin-top: 1.5rem !important;\n }\n .mt-md-5 {\n margin-top: 3rem !important;\n }\n .mt-md-auto {\n margin-top: auto !important;\n }\n .me-md-0 {\n margin-right: 0 !important;\n }\n .me-md-1 {\n margin-right: 0.25rem !important;\n }\n .me-md-2 {\n margin-right: 0.5rem !important;\n }\n .me-md-3 {\n margin-right: 1rem !important;\n }\n .me-md-4 {\n margin-right: 1.5rem !important;\n }\n .me-md-5 {\n margin-right: 3rem !important;\n }\n .me-md-auto {\n margin-right: auto !important;\n }\n .mb-md-0 {\n margin-bottom: 0 !important;\n }\n .mb-md-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-md-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-md-3 {\n margin-bottom: 1rem !important;\n }\n .mb-md-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-md-5 {\n margin-bottom: 3rem !important;\n }\n .mb-md-auto {\n margin-bottom: auto !important;\n }\n .ms-md-0 {\n margin-left: 0 !important;\n }\n .ms-md-1 {\n margin-left: 0.25rem !important;\n }\n .ms-md-2 {\n margin-left: 0.5rem !important;\n }\n .ms-md-3 {\n margin-left: 1rem !important;\n }\n .ms-md-4 {\n margin-left: 1.5rem !important;\n }\n .ms-md-5 {\n margin-left: 3rem !important;\n }\n .ms-md-auto {\n margin-left: auto !important;\n }\n .p-md-0 {\n padding: 0 !important;\n }\n .p-md-1 {\n padding: 0.25rem !important;\n }\n .p-md-2 {\n padding: 0.5rem !important;\n }\n .p-md-3 {\n padding: 1rem !important;\n }\n .p-md-4 {\n padding: 1.5rem !important;\n }\n .p-md-5 {\n padding: 3rem !important;\n }\n .px-md-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-md-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-md-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-md-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-md-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-md-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-md-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-md-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-md-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-md-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-md-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-md-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-md-0 {\n padding-top: 0 !important;\n }\n .pt-md-1 {\n padding-top: 0.25rem !important;\n }\n .pt-md-2 {\n padding-top: 0.5rem !important;\n }\n .pt-md-3 {\n padding-top: 1rem !important;\n }\n .pt-md-4 {\n padding-top: 1.5rem !important;\n }\n .pt-md-5 {\n padding-top: 3rem !important;\n }\n .pe-md-0 {\n padding-right: 0 !important;\n }\n .pe-md-1 {\n padding-right: 0.25rem !important;\n }\n .pe-md-2 {\n padding-right: 0.5rem !important;\n }\n .pe-md-3 {\n padding-right: 1rem !important;\n }\n .pe-md-4 {\n padding-right: 1.5rem !important;\n }\n .pe-md-5 {\n padding-right: 3rem !important;\n }\n .pb-md-0 {\n padding-bottom: 0 !important;\n }\n .pb-md-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-md-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-md-3 {\n padding-bottom: 1rem !important;\n }\n .pb-md-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-md-5 {\n padding-bottom: 3rem !important;\n }\n .ps-md-0 {\n padding-left: 0 !important;\n }\n .ps-md-1 {\n padding-left: 0.25rem !important;\n }\n .ps-md-2 {\n padding-left: 0.5rem !important;\n }\n .ps-md-3 {\n padding-left: 1rem !important;\n }\n .ps-md-4 {\n padding-left: 1.5rem !important;\n }\n .ps-md-5 {\n padding-left: 3rem !important;\n }\n}\n@media (min-width: 992px) {\n .d-lg-inline {\n display: inline !important;\n }\n .d-lg-inline-block {\n display: inline-block !important;\n }\n .d-lg-block {\n display: block !important;\n }\n .d-lg-grid {\n display: grid !important;\n }\n .d-lg-inline-grid {\n display: inline-grid !important;\n }\n .d-lg-table {\n display: table !important;\n }\n .d-lg-table-row {\n display: table-row !important;\n }\n .d-lg-table-cell {\n display: table-cell !important;\n }\n .d-lg-flex {\n display: flex !important;\n }\n .d-lg-inline-flex {\n display: inline-flex !important;\n }\n .d-lg-none {\n display: none !important;\n }\n .flex-lg-fill {\n flex: 1 1 auto !important;\n }\n .flex-lg-row {\n flex-direction: row !important;\n }\n .flex-lg-column {\n flex-direction: column !important;\n }\n .flex-lg-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-lg-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-lg-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-lg-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-lg-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-lg-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-lg-wrap {\n flex-wrap: wrap !important;\n }\n .flex-lg-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-lg-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-lg-start {\n justify-content: flex-start !important;\n }\n .justify-content-lg-end {\n justify-content: flex-end !important;\n }\n .justify-content-lg-center {\n justify-content: center !important;\n }\n .justify-content-lg-between {\n justify-content: space-between !important;\n }\n .justify-content-lg-around {\n justify-content: space-around !important;\n }\n .justify-content-lg-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-lg-start {\n align-items: flex-start !important;\n }\n .align-items-lg-end {\n align-items: flex-end !important;\n }\n .align-items-lg-center {\n align-items: center !important;\n }\n .align-items-lg-baseline {\n align-items: baseline !important;\n }\n .align-items-lg-stretch {\n align-items: stretch !important;\n }\n .align-content-lg-start {\n align-content: flex-start !important;\n }\n .align-content-lg-end {\n align-content: flex-end !important;\n }\n .align-content-lg-center {\n align-content: center !important;\n }\n .align-content-lg-between {\n align-content: space-between !important;\n }\n .align-content-lg-around {\n align-content: space-around !important;\n }\n .align-content-lg-stretch {\n align-content: stretch !important;\n }\n .align-self-lg-auto {\n align-self: auto !important;\n }\n .align-self-lg-start {\n align-self: flex-start !important;\n }\n .align-self-lg-end {\n align-self: flex-end !important;\n }\n .align-self-lg-center {\n align-self: center !important;\n }\n .align-self-lg-baseline {\n align-self: baseline !important;\n }\n .align-self-lg-stretch {\n align-self: stretch !important;\n }\n .order-lg-first {\n order: -1 !important;\n }\n .order-lg-0 {\n order: 0 !important;\n }\n .order-lg-1 {\n order: 1 !important;\n }\n .order-lg-2 {\n order: 2 !important;\n }\n .order-lg-3 {\n order: 3 !important;\n }\n .order-lg-4 {\n order: 4 !important;\n }\n .order-lg-5 {\n order: 5 !important;\n }\n .order-lg-last {\n order: 6 !important;\n }\n .m-lg-0 {\n margin: 0 !important;\n }\n .m-lg-1 {\n margin: 0.25rem !important;\n }\n .m-lg-2 {\n margin: 0.5rem !important;\n }\n .m-lg-3 {\n margin: 1rem !important;\n }\n .m-lg-4 {\n margin: 1.5rem !important;\n }\n .m-lg-5 {\n margin: 3rem !important;\n }\n .m-lg-auto {\n margin: auto !important;\n }\n .mx-lg-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-lg-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-lg-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-lg-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-lg-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-lg-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-lg-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-lg-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-lg-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-lg-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-lg-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-lg-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-lg-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-lg-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-lg-0 {\n margin-top: 0 !important;\n }\n .mt-lg-1 {\n margin-top: 0.25rem !important;\n }\n .mt-lg-2 {\n margin-top: 0.5rem !important;\n }\n .mt-lg-3 {\n margin-top: 1rem !important;\n }\n .mt-lg-4 {\n margin-top: 1.5rem !important;\n }\n .mt-lg-5 {\n margin-top: 3rem !important;\n }\n .mt-lg-auto {\n margin-top: auto !important;\n }\n .me-lg-0 {\n margin-right: 0 !important;\n }\n .me-lg-1 {\n margin-right: 0.25rem !important;\n }\n .me-lg-2 {\n margin-right: 0.5rem !important;\n }\n .me-lg-3 {\n margin-right: 1rem !important;\n }\n .me-lg-4 {\n margin-right: 1.5rem !important;\n }\n .me-lg-5 {\n margin-right: 3rem !important;\n }\n .me-lg-auto {\n margin-right: auto !important;\n }\n .mb-lg-0 {\n margin-bottom: 0 !important;\n }\n .mb-lg-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-lg-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-lg-3 {\n margin-bottom: 1rem !important;\n }\n .mb-lg-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-lg-5 {\n margin-bottom: 3rem !important;\n }\n .mb-lg-auto {\n margin-bottom: auto !important;\n }\n .ms-lg-0 {\n margin-left: 0 !important;\n }\n .ms-lg-1 {\n margin-left: 0.25rem !important;\n }\n .ms-lg-2 {\n margin-left: 0.5rem !important;\n }\n .ms-lg-3 {\n margin-left: 1rem !important;\n }\n .ms-lg-4 {\n margin-left: 1.5rem !important;\n }\n .ms-lg-5 {\n margin-left: 3rem !important;\n }\n .ms-lg-auto {\n margin-left: auto !important;\n }\n .p-lg-0 {\n padding: 0 !important;\n }\n .p-lg-1 {\n padding: 0.25rem !important;\n }\n .p-lg-2 {\n padding: 0.5rem !important;\n }\n .p-lg-3 {\n padding: 1rem !important;\n }\n .p-lg-4 {\n padding: 1.5rem !important;\n }\n .p-lg-5 {\n padding: 3rem !important;\n }\n .px-lg-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-lg-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-lg-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-lg-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-lg-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-lg-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-lg-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-lg-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-lg-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-lg-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-lg-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-lg-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-lg-0 {\n padding-top: 0 !important;\n }\n .pt-lg-1 {\n padding-top: 0.25rem !important;\n }\n .pt-lg-2 {\n padding-top: 0.5rem !important;\n }\n .pt-lg-3 {\n padding-top: 1rem !important;\n }\n .pt-lg-4 {\n padding-top: 1.5rem !important;\n }\n .pt-lg-5 {\n padding-top: 3rem !important;\n }\n .pe-lg-0 {\n padding-right: 0 !important;\n }\n .pe-lg-1 {\n padding-right: 0.25rem !important;\n }\n .pe-lg-2 {\n padding-right: 0.5rem !important;\n }\n .pe-lg-3 {\n padding-right: 1rem !important;\n }\n .pe-lg-4 {\n padding-right: 1.5rem !important;\n }\n .pe-lg-5 {\n padding-right: 3rem !important;\n }\n .pb-lg-0 {\n padding-bottom: 0 !important;\n }\n .pb-lg-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-lg-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-lg-3 {\n padding-bottom: 1rem !important;\n }\n .pb-lg-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-lg-5 {\n padding-bottom: 3rem !important;\n }\n .ps-lg-0 {\n padding-left: 0 !important;\n }\n .ps-lg-1 {\n padding-left: 0.25rem !important;\n }\n .ps-lg-2 {\n padding-left: 0.5rem !important;\n }\n .ps-lg-3 {\n padding-left: 1rem !important;\n }\n .ps-lg-4 {\n padding-left: 1.5rem !important;\n }\n .ps-lg-5 {\n padding-left: 3rem !important;\n }\n}\n@media (min-width: 1200px) {\n .d-xl-inline {\n display: inline !important;\n }\n .d-xl-inline-block {\n display: inline-block !important;\n }\n .d-xl-block {\n display: block !important;\n }\n .d-xl-grid {\n display: grid !important;\n }\n .d-xl-inline-grid {\n display: inline-grid !important;\n }\n .d-xl-table {\n display: table !important;\n }\n .d-xl-table-row {\n display: table-row !important;\n }\n .d-xl-table-cell {\n display: table-cell !important;\n }\n .d-xl-flex {\n display: flex !important;\n }\n .d-xl-inline-flex {\n display: inline-flex !important;\n }\n .d-xl-none {\n display: none !important;\n }\n .flex-xl-fill {\n flex: 1 1 auto !important;\n }\n .flex-xl-row {\n flex-direction: row !important;\n }\n .flex-xl-column {\n flex-direction: column !important;\n }\n .flex-xl-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-xl-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-xl-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-xl-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-xl-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-xl-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-xl-wrap {\n flex-wrap: wrap !important;\n }\n .flex-xl-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-xl-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-xl-start {\n justify-content: flex-start !important;\n }\n .justify-content-xl-end {\n justify-content: flex-end !important;\n }\n .justify-content-xl-center {\n justify-content: center !important;\n }\n .justify-content-xl-between {\n justify-content: space-between !important;\n }\n .justify-content-xl-around {\n justify-content: space-around !important;\n }\n .justify-content-xl-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-xl-start {\n align-items: flex-start !important;\n }\n .align-items-xl-end {\n align-items: flex-end !important;\n }\n .align-items-xl-center {\n align-items: center !important;\n }\n .align-items-xl-baseline {\n align-items: baseline !important;\n }\n .align-items-xl-stretch {\n align-items: stretch !important;\n }\n .align-content-xl-start {\n align-content: flex-start !important;\n }\n .align-content-xl-end {\n align-content: flex-end !important;\n }\n .align-content-xl-center {\n align-content: center !important;\n }\n .align-content-xl-between {\n align-content: space-between !important;\n }\n .align-content-xl-around {\n align-content: space-around !important;\n }\n .align-content-xl-stretch {\n align-content: stretch !important;\n }\n .align-self-xl-auto {\n align-self: auto !important;\n }\n .align-self-xl-start {\n align-self: flex-start !important;\n }\n .align-self-xl-end {\n align-self: flex-end !important;\n }\n .align-self-xl-center {\n align-self: center !important;\n }\n .align-self-xl-baseline {\n align-self: baseline !important;\n }\n .align-self-xl-stretch {\n align-self: stretch !important;\n }\n .order-xl-first {\n order: -1 !important;\n }\n .order-xl-0 {\n order: 0 !important;\n }\n .order-xl-1 {\n order: 1 !important;\n }\n .order-xl-2 {\n order: 2 !important;\n }\n .order-xl-3 {\n order: 3 !important;\n }\n .order-xl-4 {\n order: 4 !important;\n }\n .order-xl-5 {\n order: 5 !important;\n }\n .order-xl-last {\n order: 6 !important;\n }\n .m-xl-0 {\n margin: 0 !important;\n }\n .m-xl-1 {\n margin: 0.25rem !important;\n }\n .m-xl-2 {\n margin: 0.5rem !important;\n }\n .m-xl-3 {\n margin: 1rem !important;\n }\n .m-xl-4 {\n margin: 1.5rem !important;\n }\n .m-xl-5 {\n margin: 3rem !important;\n }\n .m-xl-auto {\n margin: auto !important;\n }\n .mx-xl-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-xl-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-xl-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-xl-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-xl-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-xl-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-xl-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-xl-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-xl-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-xl-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-xl-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-xl-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-xl-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-xl-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-xl-0 {\n margin-top: 0 !important;\n }\n .mt-xl-1 {\n margin-top: 0.25rem !important;\n }\n .mt-xl-2 {\n margin-top: 0.5rem !important;\n }\n .mt-xl-3 {\n margin-top: 1rem !important;\n }\n .mt-xl-4 {\n margin-top: 1.5rem !important;\n }\n .mt-xl-5 {\n margin-top: 3rem !important;\n }\n .mt-xl-auto {\n margin-top: auto !important;\n }\n .me-xl-0 {\n margin-right: 0 !important;\n }\n .me-xl-1 {\n margin-right: 0.25rem !important;\n }\n .me-xl-2 {\n margin-right: 0.5rem !important;\n }\n .me-xl-3 {\n margin-right: 1rem !important;\n }\n .me-xl-4 {\n margin-right: 1.5rem !important;\n }\n .me-xl-5 {\n margin-right: 3rem !important;\n }\n .me-xl-auto {\n margin-right: auto !important;\n }\n .mb-xl-0 {\n margin-bottom: 0 !important;\n }\n .mb-xl-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-xl-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-xl-3 {\n margin-bottom: 1rem !important;\n }\n .mb-xl-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-xl-5 {\n margin-bottom: 3rem !important;\n }\n .mb-xl-auto {\n margin-bottom: auto !important;\n }\n .ms-xl-0 {\n margin-left: 0 !important;\n }\n .ms-xl-1 {\n margin-left: 0.25rem !important;\n }\n .ms-xl-2 {\n margin-left: 0.5rem !important;\n }\n .ms-xl-3 {\n margin-left: 1rem !important;\n }\n .ms-xl-4 {\n margin-left: 1.5rem !important;\n }\n .ms-xl-5 {\n margin-left: 3rem !important;\n }\n .ms-xl-auto {\n margin-left: auto !important;\n }\n .p-xl-0 {\n padding: 0 !important;\n }\n .p-xl-1 {\n padding: 0.25rem !important;\n }\n .p-xl-2 {\n padding: 0.5rem !important;\n }\n .p-xl-3 {\n padding: 1rem !important;\n }\n .p-xl-4 {\n padding: 1.5rem !important;\n }\n .p-xl-5 {\n padding: 3rem !important;\n }\n .px-xl-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-xl-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-xl-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-xl-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-xl-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-xl-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-xl-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-xl-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-xl-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-xl-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-xl-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-xl-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-xl-0 {\n padding-top: 0 !important;\n }\n .pt-xl-1 {\n padding-top: 0.25rem !important;\n }\n .pt-xl-2 {\n padding-top: 0.5rem !important;\n }\n .pt-xl-3 {\n padding-top: 1rem !important;\n }\n .pt-xl-4 {\n padding-top: 1.5rem !important;\n }\n .pt-xl-5 {\n padding-top: 3rem !important;\n }\n .pe-xl-0 {\n padding-right: 0 !important;\n }\n .pe-xl-1 {\n padding-right: 0.25rem !important;\n }\n .pe-xl-2 {\n padding-right: 0.5rem !important;\n }\n .pe-xl-3 {\n padding-right: 1rem !important;\n }\n .pe-xl-4 {\n padding-right: 1.5rem !important;\n }\n .pe-xl-5 {\n padding-right: 3rem !important;\n }\n .pb-xl-0 {\n padding-bottom: 0 !important;\n }\n .pb-xl-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-xl-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-xl-3 {\n padding-bottom: 1rem !important;\n }\n .pb-xl-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-xl-5 {\n padding-bottom: 3rem !important;\n }\n .ps-xl-0 {\n padding-left: 0 !important;\n }\n .ps-xl-1 {\n padding-left: 0.25rem !important;\n }\n .ps-xl-2 {\n padding-left: 0.5rem !important;\n }\n .ps-xl-3 {\n padding-left: 1rem !important;\n }\n .ps-xl-4 {\n padding-left: 1.5rem !important;\n }\n .ps-xl-5 {\n padding-left: 3rem !important;\n }\n}\n@media (min-width: 1400px) {\n .d-xxl-inline {\n display: inline !important;\n }\n .d-xxl-inline-block {\n display: inline-block !important;\n }\n .d-xxl-block {\n display: block !important;\n }\n .d-xxl-grid {\n display: grid !important;\n }\n .d-xxl-inline-grid {\n display: inline-grid !important;\n }\n .d-xxl-table {\n display: table !important;\n }\n .d-xxl-table-row {\n display: table-row !important;\n }\n .d-xxl-table-cell {\n display: table-cell !important;\n }\n .d-xxl-flex {\n display: flex !important;\n }\n .d-xxl-inline-flex {\n display: inline-flex !important;\n }\n .d-xxl-none {\n display: none !important;\n }\n .flex-xxl-fill {\n flex: 1 1 auto !important;\n }\n .flex-xxl-row {\n flex-direction: row !important;\n }\n .flex-xxl-column {\n flex-direction: column !important;\n }\n .flex-xxl-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-xxl-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-xxl-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-xxl-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-xxl-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-xxl-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-xxl-wrap {\n flex-wrap: wrap !important;\n }\n .flex-xxl-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-xxl-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-xxl-start {\n justify-content: flex-start !important;\n }\n .justify-content-xxl-end {\n justify-content: flex-end !important;\n }\n .justify-content-xxl-center {\n justify-content: center !important;\n }\n .justify-content-xxl-between {\n justify-content: space-between !important;\n }\n .justify-content-xxl-around {\n justify-content: space-around !important;\n }\n .justify-content-xxl-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-xxl-start {\n align-items: flex-start !important;\n }\n .align-items-xxl-end {\n align-items: flex-end !important;\n }\n .align-items-xxl-center {\n align-items: center !important;\n }\n .align-items-xxl-baseline {\n align-items: baseline !important;\n }\n .align-items-xxl-stretch {\n align-items: stretch !important;\n }\n .align-content-xxl-start {\n align-content: flex-start !important;\n }\n .align-content-xxl-end {\n align-content: flex-end !important;\n }\n .align-content-xxl-center {\n align-content: center !important;\n }\n .align-content-xxl-between {\n align-content: space-between !important;\n }\n .align-content-xxl-around {\n align-content: space-around !important;\n }\n .align-content-xxl-stretch {\n align-content: stretch !important;\n }\n .align-self-xxl-auto {\n align-self: auto !important;\n }\n .align-self-xxl-start {\n align-self: flex-start !important;\n }\n .align-self-xxl-end {\n align-self: flex-end !important;\n }\n .align-self-xxl-center {\n align-self: center !important;\n }\n .align-self-xxl-baseline {\n align-self: baseline !important;\n }\n .align-self-xxl-stretch {\n align-self: stretch !important;\n }\n .order-xxl-first {\n order: -1 !important;\n }\n .order-xxl-0 {\n order: 0 !important;\n }\n .order-xxl-1 {\n order: 1 !important;\n }\n .order-xxl-2 {\n order: 2 !important;\n }\n .order-xxl-3 {\n order: 3 !important;\n }\n .order-xxl-4 {\n order: 4 !important;\n }\n .order-xxl-5 {\n order: 5 !important;\n }\n .order-xxl-last {\n order: 6 !important;\n }\n .m-xxl-0 {\n margin: 0 !important;\n }\n .m-xxl-1 {\n margin: 0.25rem !important;\n }\n .m-xxl-2 {\n margin: 0.5rem !important;\n }\n .m-xxl-3 {\n margin: 1rem !important;\n }\n .m-xxl-4 {\n margin: 1.5rem !important;\n }\n .m-xxl-5 {\n margin: 3rem !important;\n }\n .m-xxl-auto {\n margin: auto !important;\n }\n .mx-xxl-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-xxl-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-xxl-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-xxl-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-xxl-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-xxl-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-xxl-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-xxl-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-xxl-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-xxl-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-xxl-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-xxl-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-xxl-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-xxl-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-xxl-0 {\n margin-top: 0 !important;\n }\n .mt-xxl-1 {\n margin-top: 0.25rem !important;\n }\n .mt-xxl-2 {\n margin-top: 0.5rem !important;\n }\n .mt-xxl-3 {\n margin-top: 1rem !important;\n }\n .mt-xxl-4 {\n margin-top: 1.5rem !important;\n }\n .mt-xxl-5 {\n margin-top: 3rem !important;\n }\n .mt-xxl-auto {\n margin-top: auto !important;\n }\n .me-xxl-0 {\n margin-right: 0 !important;\n }\n .me-xxl-1 {\n margin-right: 0.25rem !important;\n }\n .me-xxl-2 {\n margin-right: 0.5rem !important;\n }\n .me-xxl-3 {\n margin-right: 1rem !important;\n }\n .me-xxl-4 {\n margin-right: 1.5rem !important;\n }\n .me-xxl-5 {\n margin-right: 3rem !important;\n }\n .me-xxl-auto {\n margin-right: auto !important;\n }\n .mb-xxl-0 {\n margin-bottom: 0 !important;\n }\n .mb-xxl-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-xxl-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-xxl-3 {\n margin-bottom: 1rem !important;\n }\n .mb-xxl-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-xxl-5 {\n margin-bottom: 3rem !important;\n }\n .mb-xxl-auto {\n margin-bottom: auto !important;\n }\n .ms-xxl-0 {\n margin-left: 0 !important;\n }\n .ms-xxl-1 {\n margin-left: 0.25rem !important;\n }\n .ms-xxl-2 {\n margin-left: 0.5rem !important;\n }\n .ms-xxl-3 {\n margin-left: 1rem !important;\n }\n .ms-xxl-4 {\n margin-left: 1.5rem !important;\n }\n .ms-xxl-5 {\n margin-left: 3rem !important;\n }\n .ms-xxl-auto {\n margin-left: auto !important;\n }\n .p-xxl-0 {\n padding: 0 !important;\n }\n .p-xxl-1 {\n padding: 0.25rem !important;\n }\n .p-xxl-2 {\n padding: 0.5rem !important;\n }\n .p-xxl-3 {\n padding: 1rem !important;\n }\n .p-xxl-4 {\n padding: 1.5rem !important;\n }\n .p-xxl-5 {\n padding: 3rem !important;\n }\n .px-xxl-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-xxl-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-xxl-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-xxl-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-xxl-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-xxl-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-xxl-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-xxl-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-xxl-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-xxl-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-xxl-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-xxl-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-xxl-0 {\n padding-top: 0 !important;\n }\n .pt-xxl-1 {\n padding-top: 0.25rem !important;\n }\n .pt-xxl-2 {\n padding-top: 0.5rem !important;\n }\n .pt-xxl-3 {\n padding-top: 1rem !important;\n }\n .pt-xxl-4 {\n padding-top: 1.5rem !important;\n }\n .pt-xxl-5 {\n padding-top: 3rem !important;\n }\n .pe-xxl-0 {\n padding-right: 0 !important;\n }\n .pe-xxl-1 {\n padding-right: 0.25rem !important;\n }\n .pe-xxl-2 {\n padding-right: 0.5rem !important;\n }\n .pe-xxl-3 {\n padding-right: 1rem !important;\n }\n .pe-xxl-4 {\n padding-right: 1.5rem !important;\n }\n .pe-xxl-5 {\n padding-right: 3rem !important;\n }\n .pb-xxl-0 {\n padding-bottom: 0 !important;\n }\n .pb-xxl-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-xxl-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-xxl-3 {\n padding-bottom: 1rem !important;\n }\n .pb-xxl-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-xxl-5 {\n padding-bottom: 3rem !important;\n }\n .ps-xxl-0 {\n padding-left: 0 !important;\n }\n .ps-xxl-1 {\n padding-left: 0.25rem !important;\n }\n .ps-xxl-2 {\n padding-left: 0.5rem !important;\n }\n .ps-xxl-3 {\n padding-left: 1rem !important;\n }\n .ps-xxl-4 {\n padding-left: 1.5rem !important;\n }\n .ps-xxl-5 {\n padding-left: 3rem !important;\n }\n}\n@media print {\n .d-print-inline {\n display: inline !important;\n }\n .d-print-inline-block {\n display: inline-block !important;\n }\n .d-print-block {\n display: block !important;\n }\n .d-print-grid {\n display: grid !important;\n }\n .d-print-inline-grid {\n display: inline-grid !important;\n }\n .d-print-table {\n display: table !important;\n }\n .d-print-table-row {\n display: table-row !important;\n }\n .d-print-table-cell {\n display: table-cell !important;\n }\n .d-print-flex {\n display: flex !important;\n }\n .d-print-inline-flex {\n display: inline-flex !important;\n }\n .d-print-none {\n display: none !important;\n }\n}\n\n/*# sourceMappingURL=bootstrap-grid.css.map */\n","// Breakpoint viewport sizes and media queries.\n//\n// Breakpoints are defined as a map of (name: minimum width), order from small to large:\n//\n// (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)\n//\n// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default.\n\n// Name of the next breakpoint, or null for the last breakpoint.\n//\n// >> breakpoint-next(sm)\n// md\n// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// md\n// >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl xxl))\n// md\n@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) {\n $n: index($breakpoint-names, $name);\n @if not $n {\n @error \"breakpoint `#{$name}` not found in `#{$breakpoints}`\";\n }\n @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null);\n}\n\n// Minimum breakpoint width. Null for the smallest (first) breakpoint.\n//\n// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// 576px\n@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {\n $min: map-get($breakpoints, $name);\n @return if($min != 0, $min, null);\n}\n\n// Maximum breakpoint width.\n// The maximum value is reduced by 0.02px to work around the limitations of\n// `min-` and `max-` prefixes and viewports with fractional widths.\n// See https://www.w3.org/TR/mediaqueries-4/#mq-min-max\n// Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari.\n// See https://bugs.webkit.org/show_bug.cgi?id=178261\n//\n// >> breakpoint-max(md, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// 767.98px\n@function breakpoint-max($name, $breakpoints: $grid-breakpoints) {\n $max: map-get($breakpoints, $name);\n @return if($max and $max > 0, $max - .02, null);\n}\n\n// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front.\n// Useful for making responsive utilities.\n//\n// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// \"\" (Returns a blank string)\n// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// \"-sm\"\n@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) {\n @return if(breakpoint-min($name, $breakpoints) == null, \"\", \"-#{$name}\");\n}\n\n// Media of at least the minimum breakpoint width. No query for the smallest breakpoint.\n// Makes the @content apply to the given breakpoint and wider.\n@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($name, $breakpoints);\n @if $min {\n @media (min-width: $min) {\n @content;\n }\n } @else {\n @content;\n }\n}\n\n// Media of at most the maximum breakpoint width. No query for the largest breakpoint.\n// Makes the @content apply to the given breakpoint and narrower.\n@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) {\n $max: breakpoint-max($name, $breakpoints);\n @if $max {\n @media (max-width: $max) {\n @content;\n }\n } @else {\n @content;\n }\n}\n\n// Media that spans multiple breakpoint widths.\n// Makes the @content apply between the min and max breakpoints\n@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($lower, $breakpoints);\n $max: breakpoint-max($upper, $breakpoints);\n\n @if $min != null and $max != null {\n @media (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else if $max == null {\n @include media-breakpoint-up($lower, $breakpoints) {\n @content;\n }\n } @else if $min == null {\n @include media-breakpoint-down($upper, $breakpoints) {\n @content;\n }\n }\n}\n\n// Media between the breakpoint's minimum and maximum widths.\n// No minimum for the smallest breakpoint, and no maximum for the largest one.\n// Makes the @content apply only to the given breakpoint, not viewports any wider or narrower.\n@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($name, $breakpoints);\n $next: breakpoint-next($name, $breakpoints);\n $max: breakpoint-max($next, $breakpoints);\n\n @if $min != null and $max != null {\n @media (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else if $max == null {\n @include media-breakpoint-up($name, $breakpoints) {\n @content;\n }\n } @else if $min == null {\n @include media-breakpoint-down($next, $breakpoints) {\n @content;\n }\n }\n}\n","// Variables\n//\n// Variables should follow the `$component-state-property-size` formula for\n// consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs.\n\n// Color system\n\n// scss-docs-start gray-color-variables\n$white: #fff !default;\n$gray-100: #f8f9fa !default;\n$gray-200: #e9ecef !default;\n$gray-300: #dee2e6 !default;\n$gray-400: #ced4da !default;\n$gray-500: #adb5bd !default;\n$gray-600: #6c757d !default;\n$gray-700: #495057 !default;\n$gray-800: #343a40 !default;\n$gray-900: #212529 !default;\n$black: #000 !default;\n// scss-docs-end gray-color-variables\n\n// fusv-disable\n// scss-docs-start gray-colors-map\n$grays: (\n \"100\": $gray-100,\n \"200\": $gray-200,\n \"300\": $gray-300,\n \"400\": $gray-400,\n \"500\": $gray-500,\n \"600\": $gray-600,\n \"700\": $gray-700,\n \"800\": $gray-800,\n \"900\": $gray-900\n) !default;\n// scss-docs-end gray-colors-map\n// fusv-enable\n\n// scss-docs-start color-variables\n$blue: #0d6efd !default;\n$indigo: #6610f2 !default;\n$purple: #6f42c1 !default;\n$pink: #d63384 !default;\n$red: #dc3545 !default;\n$orange: #fd7e14 !default;\n$yellow: #ffc107 !default;\n$green: #198754 !default;\n$teal: #20c997 !default;\n$cyan: #0dcaf0 !default;\n// scss-docs-end color-variables\n\n// scss-docs-start colors-map\n$colors: (\n \"blue\": $blue,\n \"indigo\": $indigo,\n \"purple\": $purple,\n \"pink\": $pink,\n \"red\": $red,\n \"orange\": $orange,\n \"yellow\": $yellow,\n \"green\": $green,\n \"teal\": $teal,\n \"cyan\": $cyan,\n \"black\": $black,\n \"white\": $white,\n \"gray\": $gray-600,\n \"gray-dark\": $gray-800\n) !default;\n// scss-docs-end colors-map\n\n// The contrast ratio to reach against white, to determine if color changes from \"light\" to \"dark\". Acceptable values for WCAG 2.0 are 3, 4.5 and 7.\n// See https://www.w3.org/TR/WCAG20/#visual-audio-contrast-contrast\n$min-contrast-ratio: 4.5 !default;\n\n// Customize the light and dark text colors for use in our color contrast function.\n$color-contrast-dark: $black !default;\n$color-contrast-light: $white !default;\n\n// fusv-disable\n$blue-100: tint-color($blue, 80%) !default;\n$blue-200: tint-color($blue, 60%) !default;\n$blue-300: tint-color($blue, 40%) !default;\n$blue-400: tint-color($blue, 20%) !default;\n$blue-500: $blue !default;\n$blue-600: shade-color($blue, 20%) !default;\n$blue-700: shade-color($blue, 40%) !default;\n$blue-800: shade-color($blue, 60%) !default;\n$blue-900: shade-color($blue, 80%) !default;\n\n$indigo-100: tint-color($indigo, 80%) !default;\n$indigo-200: tint-color($indigo, 60%) !default;\n$indigo-300: tint-color($indigo, 40%) !default;\n$indigo-400: tint-color($indigo, 20%) !default;\n$indigo-500: $indigo !default;\n$indigo-600: shade-color($indigo, 20%) !default;\n$indigo-700: shade-color($indigo, 40%) !default;\n$indigo-800: shade-color($indigo, 60%) !default;\n$indigo-900: shade-color($indigo, 80%) !default;\n\n$purple-100: tint-color($purple, 80%) !default;\n$purple-200: tint-color($purple, 60%) !default;\n$purple-300: tint-color($purple, 40%) !default;\n$purple-400: tint-color($purple, 20%) !default;\n$purple-500: $purple !default;\n$purple-600: shade-color($purple, 20%) !default;\n$purple-700: shade-color($purple, 40%) !default;\n$purple-800: shade-color($purple, 60%) !default;\n$purple-900: shade-color($purple, 80%) !default;\n\n$pink-100: tint-color($pink, 80%) !default;\n$pink-200: tint-color($pink, 60%) !default;\n$pink-300: tint-color($pink, 40%) !default;\n$pink-400: tint-color($pink, 20%) !default;\n$pink-500: $pink !default;\n$pink-600: shade-color($pink, 20%) !default;\n$pink-700: shade-color($pink, 40%) !default;\n$pink-800: shade-color($pink, 60%) !default;\n$pink-900: shade-color($pink, 80%) !default;\n\n$red-100: tint-color($red, 80%) !default;\n$red-200: tint-color($red, 60%) !default;\n$red-300: tint-color($red, 40%) !default;\n$red-400: tint-color($red, 20%) !default;\n$red-500: $red !default;\n$red-600: shade-color($red, 20%) !default;\n$red-700: shade-color($red, 40%) !default;\n$red-800: shade-color($red, 60%) !default;\n$red-900: shade-color($red, 80%) !default;\n\n$orange-100: tint-color($orange, 80%) !default;\n$orange-200: tint-color($orange, 60%) !default;\n$orange-300: tint-color($orange, 40%) !default;\n$orange-400: tint-color($orange, 20%) !default;\n$orange-500: $orange !default;\n$orange-600: shade-color($orange, 20%) !default;\n$orange-700: shade-color($orange, 40%) !default;\n$orange-800: shade-color($orange, 60%) !default;\n$orange-900: shade-color($orange, 80%) !default;\n\n$yellow-100: tint-color($yellow, 80%) !default;\n$yellow-200: tint-color($yellow, 60%) !default;\n$yellow-300: tint-color($yellow, 40%) !default;\n$yellow-400: tint-color($yellow, 20%) !default;\n$yellow-500: $yellow !default;\n$yellow-600: shade-color($yellow, 20%) !default;\n$yellow-700: shade-color($yellow, 40%) !default;\n$yellow-800: shade-color($yellow, 60%) !default;\n$yellow-900: shade-color($yellow, 80%) !default;\n\n$green-100: tint-color($green, 80%) !default;\n$green-200: tint-color($green, 60%) !default;\n$green-300: tint-color($green, 40%) !default;\n$green-400: tint-color($green, 20%) !default;\n$green-500: $green !default;\n$green-600: shade-color($green, 20%) !default;\n$green-700: shade-color($green, 40%) !default;\n$green-800: shade-color($green, 60%) !default;\n$green-900: shade-color($green, 80%) !default;\n\n$teal-100: tint-color($teal, 80%) !default;\n$teal-200: tint-color($teal, 60%) !default;\n$teal-300: tint-color($teal, 40%) !default;\n$teal-400: tint-color($teal, 20%) !default;\n$teal-500: $teal !default;\n$teal-600: shade-color($teal, 20%) !default;\n$teal-700: shade-color($teal, 40%) !default;\n$teal-800: shade-color($teal, 60%) !default;\n$teal-900: shade-color($teal, 80%) !default;\n\n$cyan-100: tint-color($cyan, 80%) !default;\n$cyan-200: tint-color($cyan, 60%) !default;\n$cyan-300: tint-color($cyan, 40%) !default;\n$cyan-400: tint-color($cyan, 20%) !default;\n$cyan-500: $cyan !default;\n$cyan-600: shade-color($cyan, 20%) !default;\n$cyan-700: shade-color($cyan, 40%) !default;\n$cyan-800: shade-color($cyan, 60%) !default;\n$cyan-900: shade-color($cyan, 80%) !default;\n\n$blues: (\n \"blue-100\": $blue-100,\n \"blue-200\": $blue-200,\n \"blue-300\": $blue-300,\n \"blue-400\": $blue-400,\n \"blue-500\": $blue-500,\n \"blue-600\": $blue-600,\n \"blue-700\": $blue-700,\n \"blue-800\": $blue-800,\n \"blue-900\": $blue-900\n) !default;\n\n$indigos: (\n \"indigo-100\": $indigo-100,\n \"indigo-200\": $indigo-200,\n \"indigo-300\": $indigo-300,\n \"indigo-400\": $indigo-400,\n \"indigo-500\": $indigo-500,\n \"indigo-600\": $indigo-600,\n \"indigo-700\": $indigo-700,\n \"indigo-800\": $indigo-800,\n \"indigo-900\": $indigo-900\n) !default;\n\n$purples: (\n \"purple-100\": $purple-100,\n \"purple-200\": $purple-200,\n \"purple-300\": $purple-300,\n \"purple-400\": $purple-400,\n \"purple-500\": $purple-500,\n \"purple-600\": $purple-600,\n \"purple-700\": $purple-700,\n \"purple-800\": $purple-800,\n \"purple-900\": $purple-900\n) !default;\n\n$pinks: (\n \"pink-100\": $pink-100,\n \"pink-200\": $pink-200,\n \"pink-300\": $pink-300,\n \"pink-400\": $pink-400,\n \"pink-500\": $pink-500,\n \"pink-600\": $pink-600,\n \"pink-700\": $pink-700,\n \"pink-800\": $pink-800,\n \"pink-900\": $pink-900\n) !default;\n\n$reds: (\n \"red-100\": $red-100,\n \"red-200\": $red-200,\n \"red-300\": $red-300,\n \"red-400\": $red-400,\n \"red-500\": $red-500,\n \"red-600\": $red-600,\n \"red-700\": $red-700,\n \"red-800\": $red-800,\n \"red-900\": $red-900\n) !default;\n\n$oranges: (\n \"orange-100\": $orange-100,\n \"orange-200\": $orange-200,\n \"orange-300\": $orange-300,\n \"orange-400\": $orange-400,\n \"orange-500\": $orange-500,\n \"orange-600\": $orange-600,\n \"orange-700\": $orange-700,\n \"orange-800\": $orange-800,\n \"orange-900\": $orange-900\n) !default;\n\n$yellows: (\n \"yellow-100\": $yellow-100,\n \"yellow-200\": $yellow-200,\n \"yellow-300\": $yellow-300,\n \"yellow-400\": $yellow-400,\n \"yellow-500\": $yellow-500,\n \"yellow-600\": $yellow-600,\n \"yellow-700\": $yellow-700,\n \"yellow-800\": $yellow-800,\n \"yellow-900\": $yellow-900\n) !default;\n\n$greens: (\n \"green-100\": $green-100,\n \"green-200\": $green-200,\n \"green-300\": $green-300,\n \"green-400\": $green-400,\n \"green-500\": $green-500,\n \"green-600\": $green-600,\n \"green-700\": $green-700,\n \"green-800\": $green-800,\n \"green-900\": $green-900\n) !default;\n\n$teals: (\n \"teal-100\": $teal-100,\n \"teal-200\": $teal-200,\n \"teal-300\": $teal-300,\n \"teal-400\": $teal-400,\n \"teal-500\": $teal-500,\n \"teal-600\": $teal-600,\n \"teal-700\": $teal-700,\n \"teal-800\": $teal-800,\n \"teal-900\": $teal-900\n) !default;\n\n$cyans: (\n \"cyan-100\": $cyan-100,\n \"cyan-200\": $cyan-200,\n \"cyan-300\": $cyan-300,\n \"cyan-400\": $cyan-400,\n \"cyan-500\": $cyan-500,\n \"cyan-600\": $cyan-600,\n \"cyan-700\": $cyan-700,\n \"cyan-800\": $cyan-800,\n \"cyan-900\": $cyan-900\n) !default;\n// fusv-enable\n\n// scss-docs-start theme-color-variables\n$primary: $blue !default;\n$secondary: $gray-600 !default;\n$success: $green !default;\n$info: $cyan !default;\n$warning: $yellow !default;\n$danger: $red !default;\n$light: $gray-100 !default;\n$dark: $gray-900 !default;\n// scss-docs-end theme-color-variables\n\n// scss-docs-start theme-colors-map\n$theme-colors: (\n \"primary\": $primary,\n \"secondary\": $secondary,\n \"success\": $success,\n \"info\": $info,\n \"warning\": $warning,\n \"danger\": $danger,\n \"light\": $light,\n \"dark\": $dark\n) !default;\n// scss-docs-end theme-colors-map\n\n// scss-docs-start theme-text-variables\n$primary-text-emphasis: shade-color($primary, 60%) !default;\n$secondary-text-emphasis: shade-color($secondary, 60%) !default;\n$success-text-emphasis: shade-color($success, 60%) !default;\n$info-text-emphasis: shade-color($info, 60%) !default;\n$warning-text-emphasis: shade-color($warning, 60%) !default;\n$danger-text-emphasis: shade-color($danger, 60%) !default;\n$light-text-emphasis: $gray-700 !default;\n$dark-text-emphasis: $gray-700 !default;\n// scss-docs-end theme-text-variables\n\n// scss-docs-start theme-bg-subtle-variables\n$primary-bg-subtle: tint-color($primary, 80%) !default;\n$secondary-bg-subtle: tint-color($secondary, 80%) !default;\n$success-bg-subtle: tint-color($success, 80%) !default;\n$info-bg-subtle: tint-color($info, 80%) !default;\n$warning-bg-subtle: tint-color($warning, 80%) !default;\n$danger-bg-subtle: tint-color($danger, 80%) !default;\n$light-bg-subtle: mix($gray-100, $white) !default;\n$dark-bg-subtle: $gray-400 !default;\n// scss-docs-end theme-bg-subtle-variables\n\n// scss-docs-start theme-border-subtle-variables\n$primary-border-subtle: tint-color($primary, 60%) !default;\n$secondary-border-subtle: tint-color($secondary, 60%) !default;\n$success-border-subtle: tint-color($success, 60%) !default;\n$info-border-subtle: tint-color($info, 60%) !default;\n$warning-border-subtle: tint-color($warning, 60%) !default;\n$danger-border-subtle: tint-color($danger, 60%) !default;\n$light-border-subtle: $gray-200 !default;\n$dark-border-subtle: $gray-500 !default;\n// scss-docs-end theme-border-subtle-variables\n\n// Characters which are escaped by the escape-svg function\n$escaped-characters: (\n (\"<\", \"%3c\"),\n (\">\", \"%3e\"),\n (\"#\", \"%23\"),\n (\"(\", \"%28\"),\n (\")\", \"%29\"),\n) !default;\n\n// Options\n//\n// Quickly modify global styling by enabling or disabling optional features.\n\n$enable-caret: true !default;\n$enable-rounded: true !default;\n$enable-shadows: false !default;\n$enable-gradients: false !default;\n$enable-transitions: true !default;\n$enable-reduced-motion: true !default;\n$enable-smooth-scroll: true !default;\n$enable-grid-classes: true !default;\n$enable-container-classes: true !default;\n$enable-cssgrid: false !default;\n$enable-button-pointers: true !default;\n$enable-rfs: true !default;\n$enable-validation-icons: true !default;\n$enable-negative-margins: false !default;\n$enable-deprecation-messages: true !default;\n$enable-important-utilities: true !default;\n\n$enable-dark-mode: true !default;\n$color-mode-type: data !default; // `data` or `media-query`\n\n// Prefix for :root CSS variables\n\n$variable-prefix: bs- !default; // Deprecated in v5.2.0 for the shorter `$prefix`\n$prefix: $variable-prefix !default;\n\n// Gradient\n//\n// The gradient which is added to components if `$enable-gradients` is `true`\n// This gradient is also added to elements with `.bg-gradient`\n// scss-docs-start variable-gradient\n$gradient: linear-gradient(180deg, rgba($white, .15), rgba($white, 0)) !default;\n// scss-docs-end variable-gradient\n\n// Spacing\n//\n// Control the default styling of most Bootstrap elements by modifying these\n// variables. Mostly focused on spacing.\n// You can add more entries to the $spacers map, should you need more variation.\n\n// scss-docs-start spacer-variables-maps\n$spacer: 1rem !default;\n$spacers: (\n 0: 0,\n 1: $spacer * .25,\n 2: $spacer * .5,\n 3: $spacer,\n 4: $spacer * 1.5,\n 5: $spacer * 3,\n) !default;\n// scss-docs-end spacer-variables-maps\n\n// Position\n//\n// Define the edge positioning anchors of the position utilities.\n\n// scss-docs-start position-map\n$position-values: (\n 0: 0,\n 50: 50%,\n 100: 100%\n) !default;\n// scss-docs-end position-map\n\n// Body\n//\n// Settings for the `` element.\n\n$body-text-align: null !default;\n$body-color: $gray-900 !default;\n$body-bg: $white !default;\n\n$body-secondary-color: rgba($body-color, .75) !default;\n$body-secondary-bg: $gray-200 !default;\n\n$body-tertiary-color: rgba($body-color, .5) !default;\n$body-tertiary-bg: $gray-100 !default;\n\n$body-emphasis-color: $black !default;\n\n// Links\n//\n// Style anchor elements.\n\n$link-color: $primary !default;\n$link-decoration: underline !default;\n$link-shade-percentage: 20% !default;\n$link-hover-color: shift-color($link-color, $link-shade-percentage) !default;\n$link-hover-decoration: null !default;\n\n$stretched-link-pseudo-element: after !default;\n$stretched-link-z-index: 1 !default;\n\n// Icon links\n// scss-docs-start icon-link-variables\n$icon-link-gap: .375rem !default;\n$icon-link-underline-offset: .25em !default;\n$icon-link-icon-size: 1em !default;\n$icon-link-icon-transition: .2s ease-in-out transform !default;\n$icon-link-icon-transform: translate3d(.25em, 0, 0) !default;\n// scss-docs-end icon-link-variables\n\n// Paragraphs\n//\n// Style p element.\n\n$paragraph-margin-bottom: 1rem !default;\n\n\n// Grid breakpoints\n//\n// Define the minimum dimensions at which your layout will change,\n// adapting to different screen sizes, for use in media queries.\n\n// scss-docs-start grid-breakpoints\n$grid-breakpoints: (\n xs: 0,\n sm: 576px,\n md: 768px,\n lg: 992px,\n xl: 1200px,\n xxl: 1400px\n) !default;\n// scss-docs-end grid-breakpoints\n\n@include _assert-ascending($grid-breakpoints, \"$grid-breakpoints\");\n@include _assert-starts-at-zero($grid-breakpoints, \"$grid-breakpoints\");\n\n\n// Grid containers\n//\n// Define the maximum width of `.container` for different screen sizes.\n\n// scss-docs-start container-max-widths\n$container-max-widths: (\n sm: 540px,\n md: 720px,\n lg: 960px,\n xl: 1140px,\n xxl: 1320px\n) !default;\n// scss-docs-end container-max-widths\n\n@include _assert-ascending($container-max-widths, \"$container-max-widths\");\n\n\n// Grid columns\n//\n// Set the number of columns and specify the width of the gutters.\n\n$grid-columns: 12 !default;\n$grid-gutter-width: 1.5rem !default;\n$grid-row-columns: 6 !default;\n\n// Container padding\n\n$container-padding-x: $grid-gutter-width !default;\n\n\n// Components\n//\n// Define common padding and border radius sizes and more.\n\n// scss-docs-start border-variables\n$border-width: 1px !default;\n$border-widths: (\n 1: 1px,\n 2: 2px,\n 3: 3px,\n 4: 4px,\n 5: 5px\n) !default;\n$border-style: solid !default;\n$border-color: $gray-300 !default;\n$border-color-translucent: rgba($black, .175) !default;\n// scss-docs-end border-variables\n\n// scss-docs-start border-radius-variables\n$border-radius: .375rem !default;\n$border-radius-sm: .25rem !default;\n$border-radius-lg: .5rem !default;\n$border-radius-xl: 1rem !default;\n$border-radius-xxl: 2rem !default;\n$border-radius-pill: 50rem !default;\n// scss-docs-end border-radius-variables\n// fusv-disable\n$border-radius-2xl: $border-radius-xxl !default; // Deprecated in v5.3.0\n// fusv-enable\n\n// scss-docs-start box-shadow-variables\n$box-shadow: 0 .5rem 1rem rgba($black, .15) !default;\n$box-shadow-sm: 0 .125rem .25rem rgba($black, .075) !default;\n$box-shadow-lg: 0 1rem 3rem rgba($black, .175) !default;\n$box-shadow-inset: inset 0 1px 2px rgba($black, .075) !default;\n// scss-docs-end box-shadow-variables\n\n$component-active-color: $white !default;\n$component-active-bg: $primary !default;\n\n// scss-docs-start focus-ring-variables\n$focus-ring-width: .25rem !default;\n$focus-ring-opacity: .25 !default;\n$focus-ring-color: rgba($primary, $focus-ring-opacity) !default;\n$focus-ring-blur: 0 !default;\n$focus-ring-box-shadow: 0 0 $focus-ring-blur $focus-ring-width $focus-ring-color !default;\n// scss-docs-end focus-ring-variables\n\n// scss-docs-start caret-variables\n$caret-width: .3em !default;\n$caret-vertical-align: $caret-width * .85 !default;\n$caret-spacing: $caret-width * .85 !default;\n// scss-docs-end caret-variables\n\n$transition-base: all .2s ease-in-out !default;\n$transition-fade: opacity .15s linear !default;\n// scss-docs-start collapse-transition\n$transition-collapse: height .35s ease !default;\n$transition-collapse-width: width .35s ease !default;\n// scss-docs-end collapse-transition\n\n// stylelint-disable function-disallowed-list\n// scss-docs-start aspect-ratios\n$aspect-ratios: (\n \"1x1\": 100%,\n \"4x3\": calc(3 / 4 * 100%),\n \"16x9\": calc(9 / 16 * 100%),\n \"21x9\": calc(9 / 21 * 100%)\n) !default;\n// scss-docs-end aspect-ratios\n// stylelint-enable function-disallowed-list\n\n// Typography\n//\n// Font, line-height, and color for body text, headings, and more.\n\n// scss-docs-start font-variables\n// stylelint-disable value-keyword-case\n$font-family-sans-serif: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", \"Liberation Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\" !default;\n$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace !default;\n// stylelint-enable value-keyword-case\n$font-family-base: var(--#{$prefix}font-sans-serif) !default;\n$font-family-code: var(--#{$prefix}font-monospace) !default;\n\n// $font-size-root affects the value of `rem`, which is used for as well font sizes, paddings, and margins\n// $font-size-base affects the font size of the body text\n$font-size-root: null !default;\n$font-size-base: 1rem !default; // Assumes the browser default, typically `16px`\n$font-size-sm: $font-size-base * .875 !default;\n$font-size-lg: $font-size-base * 1.25 !default;\n\n$font-weight-lighter: lighter !default;\n$font-weight-light: 300 !default;\n$font-weight-normal: 400 !default;\n$font-weight-medium: 500 !default;\n$font-weight-semibold: 600 !default;\n$font-weight-bold: 700 !default;\n$font-weight-bolder: bolder !default;\n\n$font-weight-base: $font-weight-normal !default;\n\n$line-height-base: 1.5 !default;\n$line-height-sm: 1.25 !default;\n$line-height-lg: 2 !default;\n\n$h1-font-size: $font-size-base * 2.5 !default;\n$h2-font-size: $font-size-base * 2 !default;\n$h3-font-size: $font-size-base * 1.75 !default;\n$h4-font-size: $font-size-base * 1.5 !default;\n$h5-font-size: $font-size-base * 1.25 !default;\n$h6-font-size: $font-size-base !default;\n// scss-docs-end font-variables\n\n// scss-docs-start font-sizes\n$font-sizes: (\n 1: $h1-font-size,\n 2: $h2-font-size,\n 3: $h3-font-size,\n 4: $h4-font-size,\n 5: $h5-font-size,\n 6: $h6-font-size\n) !default;\n// scss-docs-end font-sizes\n\n// scss-docs-start headings-variables\n$headings-margin-bottom: $spacer * .5 !default;\n$headings-font-family: null !default;\n$headings-font-style: null !default;\n$headings-font-weight: 500 !default;\n$headings-line-height: 1.2 !default;\n$headings-color: inherit !default;\n// scss-docs-end headings-variables\n\n// scss-docs-start display-headings\n$display-font-sizes: (\n 1: 5rem,\n 2: 4.5rem,\n 3: 4rem,\n 4: 3.5rem,\n 5: 3rem,\n 6: 2.5rem\n) !default;\n\n$display-font-family: null !default;\n$display-font-style: null !default;\n$display-font-weight: 300 !default;\n$display-line-height: $headings-line-height !default;\n// scss-docs-end display-headings\n\n// scss-docs-start type-variables\n$lead-font-size: $font-size-base * 1.25 !default;\n$lead-font-weight: 300 !default;\n\n$small-font-size: .875em !default;\n\n$sub-sup-font-size: .75em !default;\n\n// fusv-disable\n$text-muted: var(--#{$prefix}secondary-color) !default; // Deprecated in 5.3.0\n// fusv-enable\n\n$initialism-font-size: $small-font-size !default;\n\n$blockquote-margin-y: $spacer !default;\n$blockquote-font-size: $font-size-base * 1.25 !default;\n$blockquote-footer-color: $gray-600 !default;\n$blockquote-footer-font-size: $small-font-size !default;\n\n$hr-margin-y: $spacer !default;\n$hr-color: inherit !default;\n\n// fusv-disable\n$hr-bg-color: null !default; // Deprecated in v5.2.0\n$hr-height: null !default; // Deprecated in v5.2.0\n// fusv-enable\n\n$hr-border-color: null !default; // Allows for inherited colors\n$hr-border-width: var(--#{$prefix}border-width) !default;\n$hr-opacity: .25 !default;\n\n// scss-docs-start vr-variables\n$vr-border-width: var(--#{$prefix}border-width) !default;\n// scss-docs-end vr-variables\n\n$legend-margin-bottom: .5rem !default;\n$legend-font-size: 1.5rem !default;\n$legend-font-weight: null !default;\n\n$dt-font-weight: $font-weight-bold !default;\n\n$list-inline-padding: .5rem !default;\n\n$mark-padding: .1875em !default;\n$mark-color: $body-color !default;\n$mark-bg: $yellow-100 !default;\n// scss-docs-end type-variables\n\n\n// Tables\n//\n// Customizes the `.table` component with basic values, each used across all table variations.\n\n// scss-docs-start table-variables\n$table-cell-padding-y: .5rem !default;\n$table-cell-padding-x: .5rem !default;\n$table-cell-padding-y-sm: .25rem !default;\n$table-cell-padding-x-sm: .25rem !default;\n\n$table-cell-vertical-align: top !default;\n\n$table-color: var(--#{$prefix}emphasis-color) !default;\n$table-bg: var(--#{$prefix}body-bg) !default;\n$table-accent-bg: transparent !default;\n\n$table-th-font-weight: null !default;\n\n$table-striped-color: $table-color !default;\n$table-striped-bg-factor: .05 !default;\n$table-striped-bg: rgba(var(--#{$prefix}emphasis-color-rgb), $table-striped-bg-factor) !default;\n\n$table-active-color: $table-color !default;\n$table-active-bg-factor: .1 !default;\n$table-active-bg: rgba(var(--#{$prefix}emphasis-color-rgb), $table-active-bg-factor) !default;\n\n$table-hover-color: $table-color !default;\n$table-hover-bg-factor: .075 !default;\n$table-hover-bg: rgba(var(--#{$prefix}emphasis-color-rgb), $table-hover-bg-factor) !default;\n\n$table-border-factor: .2 !default;\n$table-border-width: var(--#{$prefix}border-width) !default;\n$table-border-color: var(--#{$prefix}border-color) !default;\n\n$table-striped-order: odd !default;\n$table-striped-columns-order: even !default;\n\n$table-group-separator-color: currentcolor !default;\n\n$table-caption-color: var(--#{$prefix}secondary-color) !default;\n\n$table-bg-scale: -80% !default;\n// scss-docs-end table-variables\n\n// scss-docs-start table-loop\n$table-variants: (\n \"primary\": shift-color($primary, $table-bg-scale),\n \"secondary\": shift-color($secondary, $table-bg-scale),\n \"success\": shift-color($success, $table-bg-scale),\n \"info\": shift-color($info, $table-bg-scale),\n \"warning\": shift-color($warning, $table-bg-scale),\n \"danger\": shift-color($danger, $table-bg-scale),\n \"light\": $light,\n \"dark\": $dark,\n) !default;\n// scss-docs-end table-loop\n\n\n// Buttons + Forms\n//\n// Shared variables that are reassigned to `$input-` and `$btn-` specific variables.\n\n// scss-docs-start input-btn-variables\n$input-btn-padding-y: .375rem !default;\n$input-btn-padding-x: .75rem !default;\n$input-btn-font-family: null !default;\n$input-btn-font-size: $font-size-base !default;\n$input-btn-line-height: $line-height-base !default;\n\n$input-btn-focus-width: $focus-ring-width !default;\n$input-btn-focus-color-opacity: $focus-ring-opacity !default;\n$input-btn-focus-color: $focus-ring-color !default;\n$input-btn-focus-blur: $focus-ring-blur !default;\n$input-btn-focus-box-shadow: $focus-ring-box-shadow !default;\n\n$input-btn-padding-y-sm: .25rem !default;\n$input-btn-padding-x-sm: .5rem !default;\n$input-btn-font-size-sm: $font-size-sm !default;\n\n$input-btn-padding-y-lg: .5rem !default;\n$input-btn-padding-x-lg: 1rem !default;\n$input-btn-font-size-lg: $font-size-lg !default;\n\n$input-btn-border-width: var(--#{$prefix}border-width) !default;\n// scss-docs-end input-btn-variables\n\n\n// Buttons\n//\n// For each of Bootstrap's buttons, define text, background, and border color.\n\n// scss-docs-start btn-variables\n$btn-color: var(--#{$prefix}body-color) !default;\n$btn-padding-y: $input-btn-padding-y !default;\n$btn-padding-x: $input-btn-padding-x !default;\n$btn-font-family: $input-btn-font-family !default;\n$btn-font-size: $input-btn-font-size !default;\n$btn-line-height: $input-btn-line-height !default;\n$btn-white-space: null !default; // Set to `nowrap` to prevent text wrapping\n\n$btn-padding-y-sm: $input-btn-padding-y-sm !default;\n$btn-padding-x-sm: $input-btn-padding-x-sm !default;\n$btn-font-size-sm: $input-btn-font-size-sm !default;\n\n$btn-padding-y-lg: $input-btn-padding-y-lg !default;\n$btn-padding-x-lg: $input-btn-padding-x-lg !default;\n$btn-font-size-lg: $input-btn-font-size-lg !default;\n\n$btn-border-width: $input-btn-border-width !default;\n\n$btn-font-weight: $font-weight-normal !default;\n$btn-box-shadow: inset 0 1px 0 rgba($white, .15), 0 1px 1px rgba($black, .075) !default;\n$btn-focus-width: $input-btn-focus-width !default;\n$btn-focus-box-shadow: $input-btn-focus-box-shadow !default;\n$btn-disabled-opacity: .65 !default;\n$btn-active-box-shadow: inset 0 3px 5px rgba($black, .125) !default;\n\n$btn-link-color: var(--#{$prefix}link-color) !default;\n$btn-link-hover-color: var(--#{$prefix}link-hover-color) !default;\n$btn-link-disabled-color: $gray-600 !default;\n$btn-link-focus-shadow-rgb: to-rgb(mix(color-contrast($link-color), $link-color, 15%)) !default;\n\n// Allows for customizing button radius independently from global border radius\n$btn-border-radius: var(--#{$prefix}border-radius) !default;\n$btn-border-radius-sm: var(--#{$prefix}border-radius-sm) !default;\n$btn-border-radius-lg: var(--#{$prefix}border-radius-lg) !default;\n\n$btn-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;\n\n$btn-hover-bg-shade-amount: 15% !default;\n$btn-hover-bg-tint-amount: 15% !default;\n$btn-hover-border-shade-amount: 20% !default;\n$btn-hover-border-tint-amount: 10% !default;\n$btn-active-bg-shade-amount: 20% !default;\n$btn-active-bg-tint-amount: 20% !default;\n$btn-active-border-shade-amount: 25% !default;\n$btn-active-border-tint-amount: 10% !default;\n// scss-docs-end btn-variables\n\n\n// Forms\n\n// scss-docs-start form-text-variables\n$form-text-margin-top: .25rem !default;\n$form-text-font-size: $small-font-size !default;\n$form-text-font-style: null !default;\n$form-text-font-weight: null !default;\n$form-text-color: var(--#{$prefix}secondary-color) !default;\n// scss-docs-end form-text-variables\n\n// scss-docs-start form-label-variables\n$form-label-margin-bottom: .5rem !default;\n$form-label-font-size: null !default;\n$form-label-font-style: null !default;\n$form-label-font-weight: null !default;\n$form-label-color: null !default;\n// scss-docs-end form-label-variables\n\n// scss-docs-start form-input-variables\n$input-padding-y: $input-btn-padding-y !default;\n$input-padding-x: $input-btn-padding-x !default;\n$input-font-family: $input-btn-font-family !default;\n$input-font-size: $input-btn-font-size !default;\n$input-font-weight: $font-weight-base !default;\n$input-line-height: $input-btn-line-height !default;\n\n$input-padding-y-sm: $input-btn-padding-y-sm !default;\n$input-padding-x-sm: $input-btn-padding-x-sm !default;\n$input-font-size-sm: $input-btn-font-size-sm !default;\n\n$input-padding-y-lg: $input-btn-padding-y-lg !default;\n$input-padding-x-lg: $input-btn-padding-x-lg !default;\n$input-font-size-lg: $input-btn-font-size-lg !default;\n\n$input-bg: var(--#{$prefix}body-bg) !default;\n$input-disabled-color: null !default;\n$input-disabled-bg: var(--#{$prefix}secondary-bg) !default;\n$input-disabled-border-color: null !default;\n\n$input-color: var(--#{$prefix}body-color) !default;\n$input-border-color: var(--#{$prefix}border-color) !default;\n$input-border-width: $input-btn-border-width !default;\n$input-box-shadow: var(--#{$prefix}box-shadow-inset) !default;\n\n$input-border-radius: var(--#{$prefix}border-radius) !default;\n$input-border-radius-sm: var(--#{$prefix}border-radius-sm) !default;\n$input-border-radius-lg: var(--#{$prefix}border-radius-lg) !default;\n\n$input-focus-bg: $input-bg !default;\n$input-focus-border-color: tint-color($component-active-bg, 50%) !default;\n$input-focus-color: $input-color !default;\n$input-focus-width: $input-btn-focus-width !default;\n$input-focus-box-shadow: $input-btn-focus-box-shadow !default;\n\n$input-placeholder-color: var(--#{$prefix}secondary-color) !default;\n$input-plaintext-color: var(--#{$prefix}body-color) !default;\n\n$input-height-border: calc(#{$input-border-width} * 2) !default; // stylelint-disable-line function-disallowed-list\n\n$input-height-inner: add($input-line-height * 1em, $input-padding-y * 2) !default;\n$input-height-inner-half: add($input-line-height * .5em, $input-padding-y) !default;\n$input-height-inner-quarter: add($input-line-height * .25em, $input-padding-y * .5) !default;\n\n$input-height: add($input-line-height * 1em, add($input-padding-y * 2, $input-height-border, false)) !default;\n$input-height-sm: add($input-line-height * 1em, add($input-padding-y-sm * 2, $input-height-border, false)) !default;\n$input-height-lg: add($input-line-height * 1em, add($input-padding-y-lg * 2, $input-height-border, false)) !default;\n\n$input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;\n\n$form-color-width: 3rem !default;\n// scss-docs-end form-input-variables\n\n// scss-docs-start form-check-variables\n$form-check-input-width: 1em !default;\n$form-check-min-height: $font-size-base * $line-height-base !default;\n$form-check-padding-start: $form-check-input-width + .5em !default;\n$form-check-margin-bottom: .125rem !default;\n$form-check-label-color: null !default;\n$form-check-label-cursor: null !default;\n$form-check-transition: null !default;\n\n$form-check-input-active-filter: brightness(90%) !default;\n\n$form-check-input-bg: $input-bg !default;\n$form-check-input-border: var(--#{$prefix}border-width) solid var(--#{$prefix}border-color) !default;\n$form-check-input-border-radius: .25em !default;\n$form-check-radio-border-radius: 50% !default;\n$form-check-input-focus-border: $input-focus-border-color !default;\n$form-check-input-focus-box-shadow: $focus-ring-box-shadow !default;\n\n$form-check-input-checked-color: $component-active-color !default;\n$form-check-input-checked-bg-color: $component-active-bg !default;\n$form-check-input-checked-border-color: $form-check-input-checked-bg-color !default;\n$form-check-input-checked-bg-image: url(\"data:image/svg+xml,\") !default;\n$form-check-radio-checked-bg-image: url(\"data:image/svg+xml,\") !default;\n\n$form-check-input-indeterminate-color: $component-active-color !default;\n$form-check-input-indeterminate-bg-color: $component-active-bg !default;\n$form-check-input-indeterminate-border-color: $form-check-input-indeterminate-bg-color !default;\n$form-check-input-indeterminate-bg-image: url(\"data:image/svg+xml,\") !default;\n\n$form-check-input-disabled-opacity: .5 !default;\n$form-check-label-disabled-opacity: $form-check-input-disabled-opacity !default;\n$form-check-btn-check-disabled-opacity: $btn-disabled-opacity !default;\n\n$form-check-inline-margin-end: 1rem !default;\n// scss-docs-end form-check-variables\n\n// scss-docs-start form-switch-variables\n$form-switch-color: rgba($black, .25) !default;\n$form-switch-width: 2em !default;\n$form-switch-padding-start: $form-switch-width + .5em !default;\n$form-switch-bg-image: url(\"data:image/svg+xml,\") !default;\n$form-switch-border-radius: $form-switch-width !default;\n$form-switch-transition: background-position .15s ease-in-out !default;\n\n$form-switch-focus-color: $input-focus-border-color !default;\n$form-switch-focus-bg-image: url(\"data:image/svg+xml,\") !default;\n\n$form-switch-checked-color: $component-active-color !default;\n$form-switch-checked-bg-image: url(\"data:image/svg+xml,\") !default;\n$form-switch-checked-bg-position: right center !default;\n// scss-docs-end form-switch-variables\n\n// scss-docs-start input-group-variables\n$input-group-addon-padding-y: $input-padding-y !default;\n$input-group-addon-padding-x: $input-padding-x !default;\n$input-group-addon-font-weight: $input-font-weight !default;\n$input-group-addon-color: $input-color !default;\n$input-group-addon-bg: var(--#{$prefix}tertiary-bg) !default;\n$input-group-addon-border-color: $input-border-color !default;\n// scss-docs-end input-group-variables\n\n// scss-docs-start form-select-variables\n$form-select-padding-y: $input-padding-y !default;\n$form-select-padding-x: $input-padding-x !default;\n$form-select-font-family: $input-font-family !default;\n$form-select-font-size: $input-font-size !default;\n$form-select-indicator-padding: $form-select-padding-x * 3 !default; // Extra padding for background-image\n$form-select-font-weight: $input-font-weight !default;\n$form-select-line-height: $input-line-height !default;\n$form-select-color: $input-color !default;\n$form-select-bg: $input-bg !default;\n$form-select-disabled-color: null !default;\n$form-select-disabled-bg: $input-disabled-bg !default;\n$form-select-disabled-border-color: $input-disabled-border-color !default;\n$form-select-bg-position: right $form-select-padding-x center !default;\n$form-select-bg-size: 16px 12px !default; // In pixels because image dimensions\n$form-select-indicator-color: $gray-800 !default;\n$form-select-indicator: url(\"data:image/svg+xml,\") !default;\n\n$form-select-feedback-icon-padding-end: $form-select-padding-x * 2.5 + $form-select-indicator-padding !default;\n$form-select-feedback-icon-position: center right $form-select-indicator-padding !default;\n$form-select-feedback-icon-size: $input-height-inner-half $input-height-inner-half !default;\n\n$form-select-border-width: $input-border-width !default;\n$form-select-border-color: $input-border-color !default;\n$form-select-border-radius: $input-border-radius !default;\n$form-select-box-shadow: var(--#{$prefix}box-shadow-inset) !default;\n\n$form-select-focus-border-color: $input-focus-border-color !default;\n$form-select-focus-width: $input-focus-width !default;\n$form-select-focus-box-shadow: 0 0 0 $form-select-focus-width $input-btn-focus-color !default;\n\n$form-select-padding-y-sm: $input-padding-y-sm !default;\n$form-select-padding-x-sm: $input-padding-x-sm !default;\n$form-select-font-size-sm: $input-font-size-sm !default;\n$form-select-border-radius-sm: $input-border-radius-sm !default;\n\n$form-select-padding-y-lg: $input-padding-y-lg !default;\n$form-select-padding-x-lg: $input-padding-x-lg !default;\n$form-select-font-size-lg: $input-font-size-lg !default;\n$form-select-border-radius-lg: $input-border-radius-lg !default;\n\n$form-select-transition: $input-transition !default;\n// scss-docs-end form-select-variables\n\n// scss-docs-start form-range-variables\n$form-range-track-width: 100% !default;\n$form-range-track-height: .5rem !default;\n$form-range-track-cursor: pointer !default;\n$form-range-track-bg: var(--#{$prefix}secondary-bg) !default;\n$form-range-track-border-radius: 1rem !default;\n$form-range-track-box-shadow: var(--#{$prefix}box-shadow-inset) !default;\n\n$form-range-thumb-width: 1rem !default;\n$form-range-thumb-height: $form-range-thumb-width !default;\n$form-range-thumb-bg: $component-active-bg !default;\n$form-range-thumb-border: 0 !default;\n$form-range-thumb-border-radius: 1rem !default;\n$form-range-thumb-box-shadow: 0 .1rem .25rem rgba($black, .1) !default;\n$form-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-focus-box-shadow !default;\n$form-range-thumb-focus-box-shadow-width: $input-focus-width !default; // For focus box shadow issue in Edge\n$form-range-thumb-active-bg: tint-color($component-active-bg, 70%) !default;\n$form-range-thumb-disabled-bg: var(--#{$prefix}secondary-color) !default;\n$form-range-thumb-transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;\n// scss-docs-end form-range-variables\n\n// scss-docs-start form-file-variables\n$form-file-button-color: $input-color !default;\n$form-file-button-bg: var(--#{$prefix}tertiary-bg) !default;\n$form-file-button-hover-bg: var(--#{$prefix}secondary-bg) !default;\n// scss-docs-end form-file-variables\n\n// scss-docs-start form-floating-variables\n$form-floating-height: add(3.5rem, $input-height-border) !default;\n$form-floating-line-height: 1.25 !default;\n$form-floating-padding-x: $input-padding-x !default;\n$form-floating-padding-y: 1rem !default;\n$form-floating-input-padding-t: 1.625rem !default;\n$form-floating-input-padding-b: .625rem !default;\n$form-floating-label-height: 1.5em !default;\n$form-floating-label-opacity: .65 !default;\n$form-floating-label-transform: scale(.85) translateY(-.5rem) translateX(.15rem) !default;\n$form-floating-label-disabled-color: $gray-600 !default;\n$form-floating-transition: opacity .1s ease-in-out, transform .1s ease-in-out !default;\n// scss-docs-end form-floating-variables\n\n// Form validation\n\n// scss-docs-start form-feedback-variables\n$form-feedback-margin-top: $form-text-margin-top !default;\n$form-feedback-font-size: $form-text-font-size !default;\n$form-feedback-font-style: $form-text-font-style !default;\n$form-feedback-valid-color: $success !default;\n$form-feedback-invalid-color: $danger !default;\n\n$form-feedback-icon-valid-color: $form-feedback-valid-color !default;\n$form-feedback-icon-valid: url(\"data:image/svg+xml,\") !default;\n$form-feedback-icon-invalid-color: $form-feedback-invalid-color !default;\n$form-feedback-icon-invalid: url(\"data:image/svg+xml,\") !default;\n// scss-docs-end form-feedback-variables\n\n// scss-docs-start form-validation-colors\n$form-valid-color: $form-feedback-valid-color !default;\n$form-valid-border-color: $form-feedback-valid-color !default;\n$form-invalid-color: $form-feedback-invalid-color !default;\n$form-invalid-border-color: $form-feedback-invalid-color !default;\n// scss-docs-end form-validation-colors\n\n// scss-docs-start form-validation-states\n$form-validation-states: (\n \"valid\": (\n \"color\": var(--#{$prefix}form-valid-color),\n \"icon\": $form-feedback-icon-valid,\n \"tooltip-color\": #fff,\n \"tooltip-bg-color\": var(--#{$prefix}success),\n \"focus-box-shadow\": 0 0 $input-btn-focus-blur $input-focus-width rgba(var(--#{$prefix}success-rgb), $input-btn-focus-color-opacity),\n \"border-color\": var(--#{$prefix}form-valid-border-color),\n ),\n \"invalid\": (\n \"color\": var(--#{$prefix}form-invalid-color),\n \"icon\": $form-feedback-icon-invalid,\n \"tooltip-color\": #fff,\n \"tooltip-bg-color\": var(--#{$prefix}danger),\n \"focus-box-shadow\": 0 0 $input-btn-focus-blur $input-focus-width rgba(var(--#{$prefix}danger-rgb), $input-btn-focus-color-opacity),\n \"border-color\": var(--#{$prefix}form-invalid-border-color),\n )\n) !default;\n// scss-docs-end form-validation-states\n\n// Z-index master list\n//\n// Warning: Avoid customizing these values. They're used for a bird's eye view\n// of components dependent on the z-axis and are designed to all work together.\n\n// scss-docs-start zindex-stack\n$zindex-dropdown: 1000 !default;\n$zindex-sticky: 1020 !default;\n$zindex-fixed: 1030 !default;\n$zindex-offcanvas-backdrop: 1040 !default;\n$zindex-offcanvas: 1045 !default;\n$zindex-modal-backdrop: 1050 !default;\n$zindex-modal: 1055 !default;\n$zindex-popover: 1070 !default;\n$zindex-tooltip: 1080 !default;\n$zindex-toast: 1090 !default;\n// scss-docs-end zindex-stack\n\n// scss-docs-start zindex-levels-map\n$zindex-levels: (\n n1: -1,\n 0: 0,\n 1: 1,\n 2: 2,\n 3: 3\n) !default;\n// scss-docs-end zindex-levels-map\n\n\n// Navs\n\n// scss-docs-start nav-variables\n$nav-link-padding-y: .5rem !default;\n$nav-link-padding-x: 1rem !default;\n$nav-link-font-size: null !default;\n$nav-link-font-weight: null !default;\n$nav-link-color: var(--#{$prefix}link-color) !default;\n$nav-link-hover-color: var(--#{$prefix}link-hover-color) !default;\n$nav-link-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out !default;\n$nav-link-disabled-color: var(--#{$prefix}secondary-color) !default;\n$nav-link-focus-box-shadow: $focus-ring-box-shadow !default;\n\n$nav-tabs-border-color: var(--#{$prefix}border-color) !default;\n$nav-tabs-border-width: var(--#{$prefix}border-width) !default;\n$nav-tabs-border-radius: var(--#{$prefix}border-radius) !default;\n$nav-tabs-link-hover-border-color: var(--#{$prefix}secondary-bg) var(--#{$prefix}secondary-bg) $nav-tabs-border-color !default;\n$nav-tabs-link-active-color: var(--#{$prefix}emphasis-color) !default;\n$nav-tabs-link-active-bg: var(--#{$prefix}body-bg) !default;\n$nav-tabs-link-active-border-color: var(--#{$prefix}border-color) var(--#{$prefix}border-color) $nav-tabs-link-active-bg !default;\n\n$nav-pills-border-radius: var(--#{$prefix}border-radius) !default;\n$nav-pills-link-active-color: $component-active-color !default;\n$nav-pills-link-active-bg: $component-active-bg !default;\n\n$nav-underline-gap: 1rem !default;\n$nav-underline-border-width: .125rem !default;\n$nav-underline-link-active-color: var(--#{$prefix}emphasis-color) !default;\n// scss-docs-end nav-variables\n\n\n// Navbar\n\n// scss-docs-start navbar-variables\n$navbar-padding-y: $spacer * .5 !default;\n$navbar-padding-x: null !default;\n\n$navbar-nav-link-padding-x: .5rem !default;\n\n$navbar-brand-font-size: $font-size-lg !default;\n// Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link\n$nav-link-height: $font-size-base * $line-height-base + $nav-link-padding-y * 2 !default;\n$navbar-brand-height: $navbar-brand-font-size * $line-height-base !default;\n$navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) * .5 !default;\n$navbar-brand-margin-end: 1rem !default;\n\n$navbar-toggler-padding-y: .25rem !default;\n$navbar-toggler-padding-x: .75rem !default;\n$navbar-toggler-font-size: $font-size-lg !default;\n$navbar-toggler-border-radius: $btn-border-radius !default;\n$navbar-toggler-focus-width: $btn-focus-width !default;\n$navbar-toggler-transition: box-shadow .15s ease-in-out !default;\n\n$navbar-light-color: rgba(var(--#{$prefix}emphasis-color-rgb), .65) !default;\n$navbar-light-hover-color: rgba(var(--#{$prefix}emphasis-color-rgb), .8) !default;\n$navbar-light-active-color: rgba(var(--#{$prefix}emphasis-color-rgb), 1) !default;\n$navbar-light-disabled-color: rgba(var(--#{$prefix}emphasis-color-rgb), .3) !default;\n$navbar-light-icon-color: rgba($body-color, .75) !default;\n$navbar-light-toggler-icon-bg: url(\"data:image/svg+xml,\") !default;\n$navbar-light-toggler-border-color: rgba(var(--#{$prefix}emphasis-color-rgb), .15) !default;\n$navbar-light-brand-color: $navbar-light-active-color !default;\n$navbar-light-brand-hover-color: $navbar-light-active-color !default;\n// scss-docs-end navbar-variables\n\n// scss-docs-start navbar-dark-variables\n$navbar-dark-color: rgba($white, .55) !default;\n$navbar-dark-hover-color: rgba($white, .75) !default;\n$navbar-dark-active-color: $white !default;\n$navbar-dark-disabled-color: rgba($white, .25) !default;\n$navbar-dark-icon-color: $navbar-dark-color !default;\n$navbar-dark-toggler-icon-bg: url(\"data:image/svg+xml,\") !default;\n$navbar-dark-toggler-border-color: rgba($white, .1) !default;\n$navbar-dark-brand-color: $navbar-dark-active-color !default;\n$navbar-dark-brand-hover-color: $navbar-dark-active-color !default;\n// scss-docs-end navbar-dark-variables\n\n\n// Dropdowns\n//\n// Dropdown menu container and contents.\n\n// scss-docs-start dropdown-variables\n$dropdown-min-width: 10rem !default;\n$dropdown-padding-x: 0 !default;\n$dropdown-padding-y: .5rem !default;\n$dropdown-spacer: .125rem !default;\n$dropdown-font-size: $font-size-base !default;\n$dropdown-color: var(--#{$prefix}body-color) !default;\n$dropdown-bg: var(--#{$prefix}body-bg) !default;\n$dropdown-border-color: var(--#{$prefix}border-color-translucent) !default;\n$dropdown-border-radius: var(--#{$prefix}border-radius) !default;\n$dropdown-border-width: var(--#{$prefix}border-width) !default;\n$dropdown-inner-border-radius: calc(#{$dropdown-border-radius} - #{$dropdown-border-width}) !default; // stylelint-disable-line function-disallowed-list\n$dropdown-divider-bg: $dropdown-border-color !default;\n$dropdown-divider-margin-y: $spacer * .5 !default;\n$dropdown-box-shadow: var(--#{$prefix}box-shadow) !default;\n\n$dropdown-link-color: var(--#{$prefix}body-color) !default;\n$dropdown-link-hover-color: $dropdown-link-color !default;\n$dropdown-link-hover-bg: var(--#{$prefix}tertiary-bg) !default;\n\n$dropdown-link-active-color: $component-active-color !default;\n$dropdown-link-active-bg: $component-active-bg !default;\n\n$dropdown-link-disabled-color: var(--#{$prefix}tertiary-color) !default;\n\n$dropdown-item-padding-y: $spacer * .25 !default;\n$dropdown-item-padding-x: $spacer !default;\n\n$dropdown-header-color: $gray-600 !default;\n$dropdown-header-padding-x: $dropdown-item-padding-x !default;\n$dropdown-header-padding-y: $dropdown-padding-y !default;\n// fusv-disable\n$dropdown-header-padding: $dropdown-header-padding-y $dropdown-header-padding-x !default; // Deprecated in v5.2.0\n// fusv-enable\n// scss-docs-end dropdown-variables\n\n// scss-docs-start dropdown-dark-variables\n$dropdown-dark-color: $gray-300 !default;\n$dropdown-dark-bg: $gray-800 !default;\n$dropdown-dark-border-color: $dropdown-border-color !default;\n$dropdown-dark-divider-bg: $dropdown-divider-bg !default;\n$dropdown-dark-box-shadow: null !default;\n$dropdown-dark-link-color: $dropdown-dark-color !default;\n$dropdown-dark-link-hover-color: $white !default;\n$dropdown-dark-link-hover-bg: rgba($white, .15) !default;\n$dropdown-dark-link-active-color: $dropdown-link-active-color !default;\n$dropdown-dark-link-active-bg: $dropdown-link-active-bg !default;\n$dropdown-dark-link-disabled-color: $gray-500 !default;\n$dropdown-dark-header-color: $gray-500 !default;\n// scss-docs-end dropdown-dark-variables\n\n\n// Pagination\n\n// scss-docs-start pagination-variables\n$pagination-padding-y: .375rem !default;\n$pagination-padding-x: .75rem !default;\n$pagination-padding-y-sm: .25rem !default;\n$pagination-padding-x-sm: .5rem !default;\n$pagination-padding-y-lg: .75rem !default;\n$pagination-padding-x-lg: 1.5rem !default;\n\n$pagination-font-size: $font-size-base !default;\n\n$pagination-color: var(--#{$prefix}link-color) !default;\n$pagination-bg: var(--#{$prefix}body-bg) !default;\n$pagination-border-radius: var(--#{$prefix}border-radius) !default;\n$pagination-border-width: var(--#{$prefix}border-width) !default;\n$pagination-margin-start: calc(#{$pagination-border-width} * -1) !default; // stylelint-disable-line function-disallowed-list\n$pagination-border-color: var(--#{$prefix}border-color) !default;\n\n$pagination-focus-color: var(--#{$prefix}link-hover-color) !default;\n$pagination-focus-bg: var(--#{$prefix}secondary-bg) !default;\n$pagination-focus-box-shadow: $focus-ring-box-shadow !default;\n$pagination-focus-outline: 0 !default;\n\n$pagination-hover-color: var(--#{$prefix}link-hover-color) !default;\n$pagination-hover-bg: var(--#{$prefix}tertiary-bg) !default;\n$pagination-hover-border-color: var(--#{$prefix}border-color) !default; // Todo in v6: remove this?\n\n$pagination-active-color: $component-active-color !default;\n$pagination-active-bg: $component-active-bg !default;\n$pagination-active-border-color: $component-active-bg !default;\n\n$pagination-disabled-color: var(--#{$prefix}secondary-color) !default;\n$pagination-disabled-bg: var(--#{$prefix}secondary-bg) !default;\n$pagination-disabled-border-color: var(--#{$prefix}border-color) !default;\n\n$pagination-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;\n\n$pagination-border-radius-sm: var(--#{$prefix}border-radius-sm) !default;\n$pagination-border-radius-lg: var(--#{$prefix}border-radius-lg) !default;\n// scss-docs-end pagination-variables\n\n\n// Placeholders\n\n// scss-docs-start placeholders\n$placeholder-opacity-max: .5 !default;\n$placeholder-opacity-min: .2 !default;\n// scss-docs-end placeholders\n\n// Cards\n\n// scss-docs-start card-variables\n$card-spacer-y: $spacer !default;\n$card-spacer-x: $spacer !default;\n$card-title-spacer-y: $spacer * .5 !default;\n$card-title-color: null !default;\n$card-subtitle-color: null !default;\n$card-border-width: var(--#{$prefix}border-width) !default;\n$card-border-color: var(--#{$prefix}border-color-translucent) !default;\n$card-border-radius: var(--#{$prefix}border-radius) !default;\n$card-box-shadow: null !default;\n$card-inner-border-radius: subtract($card-border-radius, $card-border-width) !default;\n$card-cap-padding-y: $card-spacer-y * .5 !default;\n$card-cap-padding-x: $card-spacer-x !default;\n$card-cap-bg: rgba(var(--#{$prefix}body-color-rgb), .03) !default;\n$card-cap-color: null !default;\n$card-height: null !default;\n$card-color: null !default;\n$card-bg: var(--#{$prefix}body-bg) !default;\n$card-img-overlay-padding: $spacer !default;\n$card-group-margin: $grid-gutter-width * .5 !default;\n// scss-docs-end card-variables\n\n// Accordion\n\n// scss-docs-start accordion-variables\n$accordion-padding-y: 1rem !default;\n$accordion-padding-x: 1.25rem !default;\n$accordion-color: var(--#{$prefix}body-color) !default;\n$accordion-bg: var(--#{$prefix}body-bg) !default;\n$accordion-border-width: var(--#{$prefix}border-width) !default;\n$accordion-border-color: var(--#{$prefix}border-color) !default;\n$accordion-border-radius: var(--#{$prefix}border-radius) !default;\n$accordion-inner-border-radius: subtract($accordion-border-radius, $accordion-border-width) !default;\n\n$accordion-body-padding-y: $accordion-padding-y !default;\n$accordion-body-padding-x: $accordion-padding-x !default;\n\n$accordion-button-padding-y: $accordion-padding-y !default;\n$accordion-button-padding-x: $accordion-padding-x !default;\n$accordion-button-color: var(--#{$prefix}body-color) !default;\n$accordion-button-bg: var(--#{$prefix}accordion-bg) !default;\n$accordion-transition: $btn-transition, border-radius .15s ease !default;\n$accordion-button-active-bg: var(--#{$prefix}primary-bg-subtle) !default;\n$accordion-button-active-color: var(--#{$prefix}primary-text-emphasis) !default;\n\n// fusv-disable\n$accordion-button-focus-border-color: $input-focus-border-color !default; // Deprecated in v5.3.3\n// fusv-enable\n$accordion-button-focus-box-shadow: $btn-focus-box-shadow !default;\n\n$accordion-icon-width: 1.25rem !default;\n$accordion-icon-color: $body-color !default;\n$accordion-icon-active-color: $primary-text-emphasis !default;\n$accordion-icon-transition: transform .2s ease-in-out !default;\n$accordion-icon-transform: rotate(-180deg) !default;\n\n$accordion-button-icon: url(\"data:image/svg+xml,\") !default;\n$accordion-button-active-icon: url(\"data:image/svg+xml,\") !default;\n// scss-docs-end accordion-variables\n\n// Tooltips\n\n// scss-docs-start tooltip-variables\n$tooltip-font-size: $font-size-sm !default;\n$tooltip-max-width: 200px !default;\n$tooltip-color: var(--#{$prefix}body-bg) !default;\n$tooltip-bg: var(--#{$prefix}emphasis-color) !default;\n$tooltip-border-radius: var(--#{$prefix}border-radius) !default;\n$tooltip-opacity: .9 !default;\n$tooltip-padding-y: $spacer * .25 !default;\n$tooltip-padding-x: $spacer * .5 !default;\n$tooltip-margin: null !default; // TODO: remove this in v6\n\n$tooltip-arrow-width: .8rem !default;\n$tooltip-arrow-height: .4rem !default;\n// fusv-disable\n$tooltip-arrow-color: null !default; // Deprecated in Bootstrap 5.2.0 for CSS variables\n// fusv-enable\n// scss-docs-end tooltip-variables\n\n// Form tooltips must come after regular tooltips\n// scss-docs-start tooltip-feedback-variables\n$form-feedback-tooltip-padding-y: $tooltip-padding-y !default;\n$form-feedback-tooltip-padding-x: $tooltip-padding-x !default;\n$form-feedback-tooltip-font-size: $tooltip-font-size !default;\n$form-feedback-tooltip-line-height: null !default;\n$form-feedback-tooltip-opacity: $tooltip-opacity !default;\n$form-feedback-tooltip-border-radius: $tooltip-border-radius !default;\n// scss-docs-end tooltip-feedback-variables\n\n\n// Popovers\n\n// scss-docs-start popover-variables\n$popover-font-size: $font-size-sm !default;\n$popover-bg: var(--#{$prefix}body-bg) !default;\n$popover-max-width: 276px !default;\n$popover-border-width: var(--#{$prefix}border-width) !default;\n$popover-border-color: var(--#{$prefix}border-color-translucent) !default;\n$popover-border-radius: var(--#{$prefix}border-radius-lg) !default;\n$popover-inner-border-radius: calc(#{$popover-border-radius} - #{$popover-border-width}) !default; // stylelint-disable-line function-disallowed-list\n$popover-box-shadow: var(--#{$prefix}box-shadow) !default;\n\n$popover-header-font-size: $font-size-base !default;\n$popover-header-bg: var(--#{$prefix}secondary-bg) !default;\n$popover-header-color: $headings-color !default;\n$popover-header-padding-y: .5rem !default;\n$popover-header-padding-x: $spacer !default;\n\n$popover-body-color: var(--#{$prefix}body-color) !default;\n$popover-body-padding-y: $spacer !default;\n$popover-body-padding-x: $spacer !default;\n\n$popover-arrow-width: 1rem !default;\n$popover-arrow-height: .5rem !default;\n// scss-docs-end popover-variables\n\n// fusv-disable\n// Deprecated in Bootstrap 5.2.0 for CSS variables\n$popover-arrow-color: $popover-bg !default;\n$popover-arrow-outer-color: var(--#{$prefix}border-color-translucent) !default;\n// fusv-enable\n\n\n// Toasts\n\n// scss-docs-start toast-variables\n$toast-max-width: 350px !default;\n$toast-padding-x: .75rem !default;\n$toast-padding-y: .5rem !default;\n$toast-font-size: .875rem !default;\n$toast-color: null !default;\n$toast-background-color: rgba(var(--#{$prefix}body-bg-rgb), .85) !default;\n$toast-border-width: var(--#{$prefix}border-width) !default;\n$toast-border-color: var(--#{$prefix}border-color-translucent) !default;\n$toast-border-radius: var(--#{$prefix}border-radius) !default;\n$toast-box-shadow: var(--#{$prefix}box-shadow) !default;\n$toast-spacing: $container-padding-x !default;\n\n$toast-header-color: var(--#{$prefix}secondary-color) !default;\n$toast-header-background-color: rgba(var(--#{$prefix}body-bg-rgb), .85) !default;\n$toast-header-border-color: $toast-border-color !default;\n// scss-docs-end toast-variables\n\n\n// Badges\n\n// scss-docs-start badge-variables\n$badge-font-size: .75em !default;\n$badge-font-weight: $font-weight-bold !default;\n$badge-color: $white !default;\n$badge-padding-y: .35em !default;\n$badge-padding-x: .65em !default;\n$badge-border-radius: var(--#{$prefix}border-radius) !default;\n// scss-docs-end badge-variables\n\n\n// Modals\n\n// scss-docs-start modal-variables\n$modal-inner-padding: $spacer !default;\n\n$modal-footer-margin-between: .5rem !default;\n\n$modal-dialog-margin: .5rem !default;\n$modal-dialog-margin-y-sm-up: 1.75rem !default;\n\n$modal-title-line-height: $line-height-base !default;\n\n$modal-content-color: null !default;\n$modal-content-bg: var(--#{$prefix}body-bg) !default;\n$modal-content-border-color: var(--#{$prefix}border-color-translucent) !default;\n$modal-content-border-width: var(--#{$prefix}border-width) !default;\n$modal-content-border-radius: var(--#{$prefix}border-radius-lg) !default;\n$modal-content-inner-border-radius: subtract($modal-content-border-radius, $modal-content-border-width) !default;\n$modal-content-box-shadow-xs: var(--#{$prefix}box-shadow-sm) !default;\n$modal-content-box-shadow-sm-up: var(--#{$prefix}box-shadow) !default;\n\n$modal-backdrop-bg: $black !default;\n$modal-backdrop-opacity: .5 !default;\n\n$modal-header-border-color: var(--#{$prefix}border-color) !default;\n$modal-header-border-width: $modal-content-border-width !default;\n$modal-header-padding-y: $modal-inner-padding !default;\n$modal-header-padding-x: $modal-inner-padding !default;\n$modal-header-padding: $modal-header-padding-y $modal-header-padding-x !default; // Keep this for backwards compatibility\n\n$modal-footer-bg: null !default;\n$modal-footer-border-color: $modal-header-border-color !default;\n$modal-footer-border-width: $modal-header-border-width !default;\n\n$modal-sm: 300px !default;\n$modal-md: 500px !default;\n$modal-lg: 800px !default;\n$modal-xl: 1140px !default;\n\n$modal-fade-transform: translate(0, -50px) !default;\n$modal-show-transform: none !default;\n$modal-transition: transform .3s ease-out !default;\n$modal-scale-transform: scale(1.02) !default;\n// scss-docs-end modal-variables\n\n\n// Alerts\n//\n// Define alert colors, border radius, and padding.\n\n// scss-docs-start alert-variables\n$alert-padding-y: $spacer !default;\n$alert-padding-x: $spacer !default;\n$alert-margin-bottom: 1rem !default;\n$alert-border-radius: var(--#{$prefix}border-radius) !default;\n$alert-link-font-weight: $font-weight-bold !default;\n$alert-border-width: var(--#{$prefix}border-width) !default;\n$alert-dismissible-padding-r: $alert-padding-x * 3 !default; // 3x covers width of x plus default padding on either side\n// scss-docs-end alert-variables\n\n// fusv-disable\n$alert-bg-scale: -80% !default; // Deprecated in v5.2.0, to be removed in v6\n$alert-border-scale: -70% !default; // Deprecated in v5.2.0, to be removed in v6\n$alert-color-scale: 40% !default; // Deprecated in v5.2.0, to be removed in v6\n// fusv-enable\n\n// Progress bars\n\n// scss-docs-start progress-variables\n$progress-height: 1rem !default;\n$progress-font-size: $font-size-base * .75 !default;\n$progress-bg: var(--#{$prefix}secondary-bg) !default;\n$progress-border-radius: var(--#{$prefix}border-radius) !default;\n$progress-box-shadow: var(--#{$prefix}box-shadow-inset) !default;\n$progress-bar-color: $white !default;\n$progress-bar-bg: $primary !default;\n$progress-bar-animation-timing: 1s linear infinite !default;\n$progress-bar-transition: width .6s ease !default;\n// scss-docs-end progress-variables\n\n\n// List group\n\n// scss-docs-start list-group-variables\n$list-group-color: var(--#{$prefix}body-color) !default;\n$list-group-bg: var(--#{$prefix}body-bg) !default;\n$list-group-border-color: var(--#{$prefix}border-color) !default;\n$list-group-border-width: var(--#{$prefix}border-width) !default;\n$list-group-border-radius: var(--#{$prefix}border-radius) !default;\n\n$list-group-item-padding-y: $spacer * .5 !default;\n$list-group-item-padding-x: $spacer !default;\n// fusv-disable\n$list-group-item-bg-scale: -80% !default; // Deprecated in v5.3.0\n$list-group-item-color-scale: 40% !default; // Deprecated in v5.3.0\n// fusv-enable\n\n$list-group-hover-bg: var(--#{$prefix}tertiary-bg) !default;\n$list-group-active-color: $component-active-color !default;\n$list-group-active-bg: $component-active-bg !default;\n$list-group-active-border-color: $list-group-active-bg !default;\n\n$list-group-disabled-color: var(--#{$prefix}secondary-color) !default;\n$list-group-disabled-bg: $list-group-bg !default;\n\n$list-group-action-color: var(--#{$prefix}secondary-color) !default;\n$list-group-action-hover-color: var(--#{$prefix}emphasis-color) !default;\n\n$list-group-action-active-color: var(--#{$prefix}body-color) !default;\n$list-group-action-active-bg: var(--#{$prefix}secondary-bg) !default;\n// scss-docs-end list-group-variables\n\n\n// Image thumbnails\n\n// scss-docs-start thumbnail-variables\n$thumbnail-padding: .25rem !default;\n$thumbnail-bg: var(--#{$prefix}body-bg) !default;\n$thumbnail-border-width: var(--#{$prefix}border-width) !default;\n$thumbnail-border-color: var(--#{$prefix}border-color) !default;\n$thumbnail-border-radius: var(--#{$prefix}border-radius) !default;\n$thumbnail-box-shadow: var(--#{$prefix}box-shadow-sm) !default;\n// scss-docs-end thumbnail-variables\n\n\n// Figures\n\n// scss-docs-start figure-variables\n$figure-caption-font-size: $small-font-size !default;\n$figure-caption-color: var(--#{$prefix}secondary-color) !default;\n// scss-docs-end figure-variables\n\n\n// Breadcrumbs\n\n// scss-docs-start breadcrumb-variables\n$breadcrumb-font-size: null !default;\n$breadcrumb-padding-y: 0 !default;\n$breadcrumb-padding-x: 0 !default;\n$breadcrumb-item-padding-x: .5rem !default;\n$breadcrumb-margin-bottom: 1rem !default;\n$breadcrumb-bg: null !default;\n$breadcrumb-divider-color: var(--#{$prefix}secondary-color) !default;\n$breadcrumb-active-color: var(--#{$prefix}secondary-color) !default;\n$breadcrumb-divider: quote(\"/\") !default;\n$breadcrumb-divider-flipped: $breadcrumb-divider !default;\n$breadcrumb-border-radius: null !default;\n// scss-docs-end breadcrumb-variables\n\n// Carousel\n\n// scss-docs-start carousel-variables\n$carousel-control-color: $white !default;\n$carousel-control-width: 15% !default;\n$carousel-control-opacity: .5 !default;\n$carousel-control-hover-opacity: .9 !default;\n$carousel-control-transition: opacity .15s ease !default;\n\n$carousel-indicator-width: 30px !default;\n$carousel-indicator-height: 3px !default;\n$carousel-indicator-hit-area-height: 10px !default;\n$carousel-indicator-spacer: 3px !default;\n$carousel-indicator-opacity: .5 !default;\n$carousel-indicator-active-bg: $white !default;\n$carousel-indicator-active-opacity: 1 !default;\n$carousel-indicator-transition: opacity .6s ease !default;\n\n$carousel-caption-width: 70% !default;\n$carousel-caption-color: $white !default;\n$carousel-caption-padding-y: 1.25rem !default;\n$carousel-caption-spacer: 1.25rem !default;\n\n$carousel-control-icon-width: 2rem !default;\n\n$carousel-control-prev-icon-bg: url(\"data:image/svg+xml,\") !default;\n$carousel-control-next-icon-bg: url(\"data:image/svg+xml,\") !default;\n\n$carousel-transition-duration: .6s !default;\n$carousel-transition: transform $carousel-transition-duration ease-in-out !default; // Define transform transition first if using multiple transitions (e.g., `transform 2s ease, opacity .5s ease-out`)\n// scss-docs-end carousel-variables\n\n// scss-docs-start carousel-dark-variables\n$carousel-dark-indicator-active-bg: $black !default;\n$carousel-dark-caption-color: $black !default;\n$carousel-dark-control-icon-filter: invert(1) grayscale(100) !default;\n// scss-docs-end carousel-dark-variables\n\n\n// Spinners\n\n// scss-docs-start spinner-variables\n$spinner-width: 2rem !default;\n$spinner-height: $spinner-width !default;\n$spinner-vertical-align: -.125em !default;\n$spinner-border-width: .25em !default;\n$spinner-animation-speed: .75s !default;\n\n$spinner-width-sm: 1rem !default;\n$spinner-height-sm: $spinner-width-sm !default;\n$spinner-border-width-sm: .2em !default;\n// scss-docs-end spinner-variables\n\n\n// Close\n\n// scss-docs-start close-variables\n$btn-close-width: 1em !default;\n$btn-close-height: $btn-close-width !default;\n$btn-close-padding-x: .25em !default;\n$btn-close-padding-y: $btn-close-padding-x !default;\n$btn-close-color: $black !default;\n$btn-close-bg: url(\"data:image/svg+xml,\") !default;\n$btn-close-focus-shadow: $focus-ring-box-shadow !default;\n$btn-close-opacity: .5 !default;\n$btn-close-hover-opacity: .75 !default;\n$btn-close-focus-opacity: 1 !default;\n$btn-close-disabled-opacity: .25 !default;\n$btn-close-white-filter: invert(1) grayscale(100%) brightness(200%) !default;\n// scss-docs-end close-variables\n\n\n// Offcanvas\n\n// scss-docs-start offcanvas-variables\n$offcanvas-padding-y: $modal-inner-padding !default;\n$offcanvas-padding-x: $modal-inner-padding !default;\n$offcanvas-horizontal-width: 400px !default;\n$offcanvas-vertical-height: 30vh !default;\n$offcanvas-transition-duration: .3s !default;\n$offcanvas-border-color: $modal-content-border-color !default;\n$offcanvas-border-width: $modal-content-border-width !default;\n$offcanvas-title-line-height: $modal-title-line-height !default;\n$offcanvas-bg-color: var(--#{$prefix}body-bg) !default;\n$offcanvas-color: var(--#{$prefix}body-color) !default;\n$offcanvas-box-shadow: $modal-content-box-shadow-xs !default;\n$offcanvas-backdrop-bg: $modal-backdrop-bg !default;\n$offcanvas-backdrop-opacity: $modal-backdrop-opacity !default;\n// scss-docs-end offcanvas-variables\n\n// Code\n\n$code-font-size: $small-font-size !default;\n$code-color: $pink !default;\n\n$kbd-padding-y: .1875rem !default;\n$kbd-padding-x: .375rem !default;\n$kbd-font-size: $code-font-size !default;\n$kbd-color: var(--#{$prefix}body-bg) !default;\n$kbd-bg: var(--#{$prefix}body-color) !default;\n$nested-kbd-font-weight: null !default; // Deprecated in v5.2.0, removing in v6\n\n$pre-color: null !default;\n\n@import \"variables-dark\"; // TODO: can be removed safely in v6, only here to avoid breaking changes in v5.3\n","// Row\n//\n// Rows contain your columns.\n\n:root {\n @each $name, $value in $grid-breakpoints {\n --#{$prefix}breakpoint-#{$name}: #{$value};\n }\n}\n\n@if $enable-grid-classes {\n .row {\n @include make-row();\n\n > * {\n @include make-col-ready();\n }\n }\n}\n\n@if $enable-cssgrid {\n .grid {\n display: grid;\n grid-template-rows: repeat(var(--#{$prefix}rows, 1), 1fr);\n grid-template-columns: repeat(var(--#{$prefix}columns, #{$grid-columns}), 1fr);\n gap: var(--#{$prefix}gap, #{$grid-gutter-width});\n\n @include make-cssgrid();\n }\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n@if $enable-grid-classes {\n @include make-grid-columns();\n}\n","// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n@mixin make-row($gutter: $grid-gutter-width) {\n --#{$prefix}gutter-x: #{$gutter};\n --#{$prefix}gutter-y: 0;\n display: flex;\n flex-wrap: wrap;\n // TODO: Revisit calc order after https://github.com/react-bootstrap/react-bootstrap/issues/6039 is fixed\n margin-top: calc(-1 * var(--#{$prefix}gutter-y)); // stylelint-disable-line function-disallowed-list\n margin-right: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list\n margin-left: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list\n}\n\n@mixin make-col-ready() {\n // Add box sizing if only the grid is loaded\n box-sizing: if(variable-exists(include-column-box-sizing) and $include-column-box-sizing, border-box, null);\n // Prevent columns from becoming too narrow when at smaller grid tiers by\n // always setting `width: 100%;`. This works because we set the width\n // later on to override this initial width.\n flex-shrink: 0;\n width: 100%;\n max-width: 100%; // Prevent `.col-auto`, `.col` (& responsive variants) from breaking out the grid\n padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n margin-top: var(--#{$prefix}gutter-y);\n}\n\n@mixin make-col($size: false, $columns: $grid-columns) {\n @if $size {\n flex: 0 0 auto;\n width: percentage(divide($size, $columns));\n\n } @else {\n flex: 1 1 0;\n max-width: 100%;\n }\n}\n\n@mixin make-col-auto() {\n flex: 0 0 auto;\n width: auto;\n}\n\n@mixin make-col-offset($size, $columns: $grid-columns) {\n $num: divide($size, $columns);\n margin-left: if($num == 0, 0, percentage($num));\n}\n\n// Row columns\n//\n// Specify on a parent element(e.g., .row) to force immediate children into NN\n// number of columns. Supports wrapping to new lines, but does not do a Masonry\n// style grid.\n@mixin row-cols($count) {\n > * {\n flex: 0 0 auto;\n width: percentage(divide(1, $count));\n }\n}\n\n// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `$grid-columns`.\n\n@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) {\n @each $breakpoint in map-keys($breakpoints) {\n $infix: breakpoint-infix($breakpoint, $breakpoints);\n\n @include media-breakpoint-up($breakpoint, $breakpoints) {\n // Provide basic `.col-{bp}` classes for equal-width flexbox columns\n .col#{$infix} {\n flex: 1 0 0%; // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4\n }\n\n .row-cols#{$infix}-auto > * {\n @include make-col-auto();\n }\n\n @if $grid-row-columns > 0 {\n @for $i from 1 through $grid-row-columns {\n .row-cols#{$infix}-#{$i} {\n @include row-cols($i);\n }\n }\n }\n\n .col#{$infix}-auto {\n @include make-col-auto();\n }\n\n @if $columns > 0 {\n @for $i from 1 through $columns {\n .col#{$infix}-#{$i} {\n @include make-col($i, $columns);\n }\n }\n\n // `$columns - 1` because offsetting by the width of an entire row isn't possible\n @for $i from 0 through ($columns - 1) {\n @if not ($infix == \"\" and $i == 0) { // Avoid emitting useless .offset-0\n .offset#{$infix}-#{$i} {\n @include make-col-offset($i, $columns);\n }\n }\n }\n }\n\n // Gutters\n //\n // Make use of `.g-*`, `.gx-*` or `.gy-*` utilities to change spacing between the columns.\n @each $key, $value in $gutters {\n .g#{$infix}-#{$key},\n .gx#{$infix}-#{$key} {\n --#{$prefix}gutter-x: #{$value};\n }\n\n .g#{$infix}-#{$key},\n .gy#{$infix}-#{$key} {\n --#{$prefix}gutter-y: #{$value};\n }\n }\n }\n }\n}\n\n@mixin make-cssgrid($columns: $grid-columns, $breakpoints: $grid-breakpoints) {\n @each $breakpoint in map-keys($breakpoints) {\n $infix: breakpoint-infix($breakpoint, $breakpoints);\n\n @include media-breakpoint-up($breakpoint, $breakpoints) {\n @if $columns > 0 {\n @for $i from 1 through $columns {\n .g-col#{$infix}-#{$i} {\n grid-column: auto / span $i;\n }\n }\n\n // Start with `1` because `0` is an invalid value.\n // Ends with `$columns - 1` because offsetting by the width of an entire row isn't possible.\n @for $i from 1 through ($columns - 1) {\n .g-start#{$infix}-#{$i} {\n grid-column-start: $i;\n }\n }\n }\n }\n }\n}\n","// Utility generator\n// Used to generate utilities & print utilities\n@mixin generate-utility($utility, $infix: \"\", $is-rfs-media-query: false) {\n $values: map-get($utility, values);\n\n // If the values are a list or string, convert it into a map\n @if type-of($values) == \"string\" or type-of(nth($values, 1)) != \"list\" {\n $values: zip($values, $values);\n }\n\n @each $key, $value in $values {\n $properties: map-get($utility, property);\n\n // Multiple properties are possible, for example with vertical or horizontal margins or paddings\n @if type-of($properties) == \"string\" {\n $properties: append((), $properties);\n }\n\n // Use custom class if present\n $property-class: if(map-has-key($utility, class), map-get($utility, class), nth($properties, 1));\n $property-class: if($property-class == null, \"\", $property-class);\n\n // Use custom CSS variable name if present, otherwise default to `class`\n $css-variable-name: if(map-has-key($utility, css-variable-name), map-get($utility, css-variable-name), map-get($utility, class));\n\n // State params to generate pseudo-classes\n $state: if(map-has-key($utility, state), map-get($utility, state), ());\n\n $infix: if($property-class == \"\" and str-slice($infix, 1, 1) == \"-\", str-slice($infix, 2), $infix);\n\n // Don't prefix if value key is null (e.g. with shadow class)\n $property-class-modifier: if($key, if($property-class == \"\" and $infix == \"\", \"\", \"-\") + $key, \"\");\n\n @if map-get($utility, rfs) {\n // Inside the media query\n @if $is-rfs-media-query {\n $val: rfs-value($value);\n\n // Do not render anything if fluid and non fluid values are the same\n $value: if($val == rfs-fluid-value($value), null, $val);\n }\n @else {\n $value: rfs-fluid-value($value);\n }\n }\n\n $is-css-var: map-get($utility, css-var);\n $is-local-vars: map-get($utility, local-vars);\n $is-rtl: map-get($utility, rtl);\n\n @if $value != null {\n @if $is-rtl == false {\n /* rtl:begin:remove */\n }\n\n @if $is-css-var {\n .#{$property-class + $infix + $property-class-modifier} {\n --#{$prefix}#{$css-variable-name}: #{$value};\n }\n\n @each $pseudo in $state {\n .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {\n --#{$prefix}#{$css-variable-name}: #{$value};\n }\n }\n } @else {\n .#{$property-class + $infix + $property-class-modifier} {\n @each $property in $properties {\n @if $is-local-vars {\n @each $local-var, $variable in $is-local-vars {\n --#{$prefix}#{$local-var}: #{$variable};\n }\n }\n #{$property}: $value if($enable-important-utilities, !important, null);\n }\n }\n\n @each $pseudo in $state {\n .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {\n @each $property in $properties {\n @if $is-local-vars {\n @each $local-var, $variable in $is-local-vars {\n --#{$prefix}#{$local-var}: #{$variable};\n }\n }\n #{$property}: $value if($enable-important-utilities, !important, null);\n }\n }\n }\n }\n\n @if $is-rtl == false {\n /* rtl:end:remove */\n }\n }\n }\n}\n","// Loop over each breakpoint\n@each $breakpoint in map-keys($grid-breakpoints) {\n\n // Generate media query if needed\n @include media-breakpoint-up($breakpoint) {\n $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\n\n // Loop over each utility property\n @each $key, $utility in $utilities {\n // The utility can be disabled with `false`, thus check if the utility is a map first\n // Only proceed if responsive media queries are enabled or if it's the base media query\n @if type-of($utility) == \"map\" and (map-get($utility, responsive) or $infix == \"\") {\n @include generate-utility($utility, $infix);\n }\n }\n }\n}\n\n// RFS rescaling\n@media (min-width: $rfs-mq-value) {\n @each $breakpoint in map-keys($grid-breakpoints) {\n $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\n\n @if (map-get($grid-breakpoints, $breakpoint) < $rfs-breakpoint) {\n // Loop over each utility property\n @each $key, $utility in $utilities {\n // The utility can be disabled with `false`, thus check if the utility is a map first\n // Only proceed if responsive media queries are enabled or if it's the base media query\n @if type-of($utility) == \"map\" and map-get($utility, rfs) and (map-get($utility, responsive) or $infix == \"\") {\n @include generate-utility($utility, $infix, true);\n }\n }\n }\n }\n}\n\n\n// Print utilities\n@media print {\n @each $key, $utility in $utilities {\n // The utility can be disabled with `false`, thus check if the utility is a map first\n // Then check if the utility needs print styles\n @if type-of($utility) == \"map\" and map-get($utility, print) == true {\n @include generate-utility($utility, \"-print\");\n }\n }\n}\n"]} \ No newline at end of file diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css new file mode 100644 index 0000000..672cbc2 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css @@ -0,0 +1,6 @@ +/*! + * Bootstrap Grid v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{--bs-gutter-x:1.5rem;--bs-gutter-y:0;width:100%;padding-left:calc(var(--bs-gutter-x) * .5);padding-right:calc(var(--bs-gutter-x) * .5);margin-left:auto;margin-right:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}:root{--bs-breakpoint-xs:0;--bs-breakpoint-sm:576px;--bs-breakpoint-md:768px;--bs-breakpoint-lg:992px;--bs-breakpoint-xl:1200px;--bs-breakpoint-xxl:1400px}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-left:calc(-.5 * var(--bs-gutter-x));margin-right:calc(-.5 * var(--bs-gutter-x))}.row>*{box-sizing:border-box;flex-shrink:0;width:100%;max-width:100%;padding-left:calc(var(--bs-gutter-x) * .5);padding-right:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.66666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-right:8.33333333%}.offset-2{margin-right:16.66666667%}.offset-3{margin-right:25%}.offset-4{margin-right:33.33333333%}.offset-5{margin-right:41.66666667%}.offset-6{margin-right:50%}.offset-7{margin-right:58.33333333%}.offset-8{margin-right:66.66666667%}.offset-9{margin-right:75%}.offset-10{margin-right:83.33333333%}.offset-11{margin-right:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.66666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-right:0}.offset-sm-1{margin-right:8.33333333%}.offset-sm-2{margin-right:16.66666667%}.offset-sm-3{margin-right:25%}.offset-sm-4{margin-right:33.33333333%}.offset-sm-5{margin-right:41.66666667%}.offset-sm-6{margin-right:50%}.offset-sm-7{margin-right:58.33333333%}.offset-sm-8{margin-right:66.66666667%}.offset-sm-9{margin-right:75%}.offset-sm-10{margin-right:83.33333333%}.offset-sm-11{margin-right:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.66666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-right:0}.offset-md-1{margin-right:8.33333333%}.offset-md-2{margin-right:16.66666667%}.offset-md-3{margin-right:25%}.offset-md-4{margin-right:33.33333333%}.offset-md-5{margin-right:41.66666667%}.offset-md-6{margin-right:50%}.offset-md-7{margin-right:58.33333333%}.offset-md-8{margin-right:66.66666667%}.offset-md-9{margin-right:75%}.offset-md-10{margin-right:83.33333333%}.offset-md-11{margin-right:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.66666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-right:0}.offset-lg-1{margin-right:8.33333333%}.offset-lg-2{margin-right:16.66666667%}.offset-lg-3{margin-right:25%}.offset-lg-4{margin-right:33.33333333%}.offset-lg-5{margin-right:41.66666667%}.offset-lg-6{margin-right:50%}.offset-lg-7{margin-right:58.33333333%}.offset-lg-8{margin-right:66.66666667%}.offset-lg-9{margin-right:75%}.offset-lg-10{margin-right:83.33333333%}.offset-lg-11{margin-right:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.66666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-right:0}.offset-xl-1{margin-right:8.33333333%}.offset-xl-2{margin-right:16.66666667%}.offset-xl-3{margin-right:25%}.offset-xl-4{margin-right:33.33333333%}.offset-xl-5{margin-right:41.66666667%}.offset-xl-6{margin-right:50%}.offset-xl-7{margin-right:58.33333333%}.offset-xl-8{margin-right:66.66666667%}.offset-xl-9{margin-right:75%}.offset-xl-10{margin-right:83.33333333%}.offset-xl-11{margin-right:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.66666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-right:0}.offset-xxl-1{margin-right:8.33333333%}.offset-xxl-2{margin-right:16.66666667%}.offset-xxl-3{margin-right:25%}.offset-xxl-4{margin-right:33.33333333%}.offset-xxl-5{margin-right:41.66666667%}.offset-xxl-6{margin-right:50%}.offset-xxl-7{margin-right:58.33333333%}.offset-xxl-8{margin-right:66.66666667%}.offset-xxl-9{margin-right:75%}.offset-xxl-10{margin-right:83.33333333%}.offset-xxl-11{margin-right:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-inline-grid{display:inline-grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-left:0!important;margin-right:0!important}.mx-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-3{margin-left:1rem!important;margin-right:1rem!important}.mx-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-5{margin-left:3rem!important;margin-right:3rem!important}.mx-auto{margin-left:auto!important;margin-right:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-left:0!important}.me-1{margin-left:.25rem!important}.me-2{margin-left:.5rem!important}.me-3{margin-left:1rem!important}.me-4{margin-left:1.5rem!important}.me-5{margin-left:3rem!important}.me-auto{margin-left:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-right:0!important}.ms-1{margin-right:.25rem!important}.ms-2{margin-right:.5rem!important}.ms-3{margin-right:1rem!important}.ms-4{margin-right:1.5rem!important}.ms-5{margin-right:3rem!important}.ms-auto{margin-right:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-left:0!important;padding-right:0!important}.px-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-3{padding-left:1rem!important;padding-right:1rem!important}.px-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-5{padding-left:3rem!important;padding-right:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-left:0!important}.pe-1{padding-left:.25rem!important}.pe-2{padding-left:.5rem!important}.pe-3{padding-left:1rem!important}.pe-4{padding-left:1.5rem!important}.pe-5{padding-left:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-right:0!important}.ps-1{padding-right:.25rem!important}.ps-2{padding-right:.5rem!important}.ps-3{padding-right:1rem!important}.ps-4{padding-right:1.5rem!important}.ps-5{padding-right:3rem!important}@media (min-width:576px){.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-inline-grid{display:inline-grid!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:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-left:0!important;margin-right:0!important}.mx-sm-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-sm-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-sm-3{margin-left:1rem!important;margin-right:1rem!important}.mx-sm-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-sm-5{margin-left:3rem!important;margin-right:3rem!important}.mx-sm-auto{margin-left:auto!important;margin-right:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-left:0!important}.me-sm-1{margin-left:.25rem!important}.me-sm-2{margin-left:.5rem!important}.me-sm-3{margin-left:1rem!important}.me-sm-4{margin-left:1.5rem!important}.me-sm-5{margin-left:3rem!important}.me-sm-auto{margin-left:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-right:0!important}.ms-sm-1{margin-right:.25rem!important}.ms-sm-2{margin-right:.5rem!important}.ms-sm-3{margin-right:1rem!important}.ms-sm-4{margin-right:1.5rem!important}.ms-sm-5{margin-right:3rem!important}.ms-sm-auto{margin-right:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-left:0!important;padding-right:0!important}.px-sm-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-sm-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-sm-3{padding-left:1rem!important;padding-right:1rem!important}.px-sm-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-sm-5{padding-left:3rem!important;padding-right:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-left:0!important}.pe-sm-1{padding-left:.25rem!important}.pe-sm-2{padding-left:.5rem!important}.pe-sm-3{padding-left:1rem!important}.pe-sm-4{padding-left:1.5rem!important}.pe-sm-5{padding-left:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-right:0!important}.ps-sm-1{padding-right:.25rem!important}.ps-sm-2{padding-right:.5rem!important}.ps-sm-3{padding-right:1rem!important}.ps-sm-4{padding-right:1.5rem!important}.ps-sm-5{padding-right:3rem!important}}@media (min-width:768px){.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-inline-grid{display:inline-grid!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:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-left:0!important;margin-right:0!important}.mx-md-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-md-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-md-3{margin-left:1rem!important;margin-right:1rem!important}.mx-md-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-md-5{margin-left:3rem!important;margin-right:3rem!important}.mx-md-auto{margin-left:auto!important;margin-right:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-left:0!important}.me-md-1{margin-left:.25rem!important}.me-md-2{margin-left:.5rem!important}.me-md-3{margin-left:1rem!important}.me-md-4{margin-left:1.5rem!important}.me-md-5{margin-left:3rem!important}.me-md-auto{margin-left:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-right:0!important}.ms-md-1{margin-right:.25rem!important}.ms-md-2{margin-right:.5rem!important}.ms-md-3{margin-right:1rem!important}.ms-md-4{margin-right:1.5rem!important}.ms-md-5{margin-right:3rem!important}.ms-md-auto{margin-right:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-left:0!important;padding-right:0!important}.px-md-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-md-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-md-3{padding-left:1rem!important;padding-right:1rem!important}.px-md-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-md-5{padding-left:3rem!important;padding-right:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-left:0!important}.pe-md-1{padding-left:.25rem!important}.pe-md-2{padding-left:.5rem!important}.pe-md-3{padding-left:1rem!important}.pe-md-4{padding-left:1.5rem!important}.pe-md-5{padding-left:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-right:0!important}.ps-md-1{padding-right:.25rem!important}.ps-md-2{padding-right:.5rem!important}.ps-md-3{padding-right:1rem!important}.ps-md-4{padding-right:1.5rem!important}.ps-md-5{padding-right:3rem!important}}@media (min-width:992px){.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-inline-grid{display:inline-grid!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:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-left:0!important;margin-right:0!important}.mx-lg-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-lg-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-lg-3{margin-left:1rem!important;margin-right:1rem!important}.mx-lg-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-lg-5{margin-left:3rem!important;margin-right:3rem!important}.mx-lg-auto{margin-left:auto!important;margin-right:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-left:0!important}.me-lg-1{margin-left:.25rem!important}.me-lg-2{margin-left:.5rem!important}.me-lg-3{margin-left:1rem!important}.me-lg-4{margin-left:1.5rem!important}.me-lg-5{margin-left:3rem!important}.me-lg-auto{margin-left:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-right:0!important}.ms-lg-1{margin-right:.25rem!important}.ms-lg-2{margin-right:.5rem!important}.ms-lg-3{margin-right:1rem!important}.ms-lg-4{margin-right:1.5rem!important}.ms-lg-5{margin-right:3rem!important}.ms-lg-auto{margin-right:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-left:0!important;padding-right:0!important}.px-lg-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-lg-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-lg-3{padding-left:1rem!important;padding-right:1rem!important}.px-lg-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-lg-5{padding-left:3rem!important;padding-right:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-left:0!important}.pe-lg-1{padding-left:.25rem!important}.pe-lg-2{padding-left:.5rem!important}.pe-lg-3{padding-left:1rem!important}.pe-lg-4{padding-left:1.5rem!important}.pe-lg-5{padding-left:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-right:0!important}.ps-lg-1{padding-right:.25rem!important}.ps-lg-2{padding-right:.5rem!important}.ps-lg-3{padding-right:1rem!important}.ps-lg-4{padding-right:1.5rem!important}.ps-lg-5{padding-right:3rem!important}}@media (min-width:1200px){.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-inline-grid{display:inline-grid!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:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-left:0!important;margin-right:0!important}.mx-xl-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-xl-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-xl-3{margin-left:1rem!important;margin-right:1rem!important}.mx-xl-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-xl-5{margin-left:3rem!important;margin-right:3rem!important}.mx-xl-auto{margin-left:auto!important;margin-right:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-left:0!important}.me-xl-1{margin-left:.25rem!important}.me-xl-2{margin-left:.5rem!important}.me-xl-3{margin-left:1rem!important}.me-xl-4{margin-left:1.5rem!important}.me-xl-5{margin-left:3rem!important}.me-xl-auto{margin-left:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-right:0!important}.ms-xl-1{margin-right:.25rem!important}.ms-xl-2{margin-right:.5rem!important}.ms-xl-3{margin-right:1rem!important}.ms-xl-4{margin-right:1.5rem!important}.ms-xl-5{margin-right:3rem!important}.ms-xl-auto{margin-right:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-left:0!important;padding-right:0!important}.px-xl-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-xl-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-xl-3{padding-left:1rem!important;padding-right:1rem!important}.px-xl-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-xl-5{padding-left:3rem!important;padding-right:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-left:0!important}.pe-xl-1{padding-left:.25rem!important}.pe-xl-2{padding-left:.5rem!important}.pe-xl-3{padding-left:1rem!important}.pe-xl-4{padding-left:1.5rem!important}.pe-xl-5{padding-left:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-right:0!important}.ps-xl-1{padding-right:.25rem!important}.ps-xl-2{padding-right:.5rem!important}.ps-xl-3{padding-right:1rem!important}.ps-xl-4{padding-right:1.5rem!important}.ps-xl-5{padding-right:3rem!important}}@media (min-width:1400px){.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-inline-grid{display:inline-grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-left:0!important;margin-right:0!important}.mx-xxl-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-xxl-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-xxl-3{margin-left:1rem!important;margin-right:1rem!important}.mx-xxl-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-xxl-5{margin-left:3rem!important;margin-right:3rem!important}.mx-xxl-auto{margin-left:auto!important;margin-right:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-left:0!important}.me-xxl-1{margin-left:.25rem!important}.me-xxl-2{margin-left:.5rem!important}.me-xxl-3{margin-left:1rem!important}.me-xxl-4{margin-left:1.5rem!important}.me-xxl-5{margin-left:3rem!important}.me-xxl-auto{margin-left:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-right:0!important}.ms-xxl-1{margin-right:.25rem!important}.ms-xxl-2{margin-right:.5rem!important}.ms-xxl-3{margin-right:1rem!important}.ms-xxl-4{margin-right:1.5rem!important}.ms-xxl-5{margin-right:3rem!important}.ms-xxl-auto{margin-right:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-left:0!important;padding-right:0!important}.px-xxl-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-xxl-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-xxl-3{padding-left:1rem!important;padding-right:1rem!important}.px-xxl-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-xxl-5{padding-left:3rem!important;padding-right:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-left:0!important}.pe-xxl-1{padding-left:.25rem!important}.pe-xxl-2{padding-left:.5rem!important}.pe-xxl-3{padding-left:1rem!important}.pe-xxl-4{padding-left:1.5rem!important}.pe-xxl-5{padding-left:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-right:0!important}.ps-xxl-1{padding-right:.25rem!important}.ps-xxl-2{padding-right:.5rem!important}.ps-xxl-3{padding-right:1rem!important}.ps-xxl-4{padding-right:1.5rem!important}.ps-xxl-5{padding-right:3rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-inline-grid{display:inline-grid!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:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} +/*# sourceMappingURL=bootstrap-grid.rtl.min.css.map */ \ No newline at end of file diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css.map b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css.map new file mode 100644 index 0000000..1c926af --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../scss/mixins/_banner.scss","../../scss/_containers.scss","dist/css/bootstrap-grid.rtl.css","../../scss/mixins/_container.scss","../../scss/mixins/_breakpoints.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/mixins/_utilities.scss","../../scss/utilities/_api.scss"],"names":[],"mappings":"AACE;;;;ACKA,WCAF,iBAGA,cACA,cACA,cAHA,cADA,eCJE,cAAA,OACA,cAAA,EACA,MAAA,KACA,aAAA,8BACA,cAAA,8BACA,YAAA,KACA,aAAA,KCsDE,yBH5CE,WAAA,cACE,UAAA,OG2CJ,yBH5CE,WAAA,cAAA,cACE,UAAA,OG2CJ,yBH5CE,WAAA,cAAA,cAAA,cACE,UAAA,OG2CJ,0BH5CE,WAAA,cAAA,cAAA,cAAA,cACE,UAAA,QG2CJ,0BH5CE,WAAA,cAAA,cAAA,cAAA,cAAA,eACE,UAAA,QIhBR,MAEI,mBAAA,EAAA,mBAAA,MAAA,mBAAA,MAAA,mBAAA,MAAA,mBAAA,OAAA,oBAAA,OAKF,KCNA,cAAA,OACA,cAAA,EACA,QAAA,KACA,UAAA,KAEA,WAAA,8BACA,YAAA,+BACA,aAAA,+BDEE,OCGF,WAAA,WAIA,YAAA,EACA,MAAA,KACA,UAAA,KACA,aAAA,8BACA,cAAA,8BACA,WAAA,mBA+CI,KACE,KAAA,EAAA,EAAA,GAGF,iBApCJ,KAAA,EAAA,EAAA,KACA,MAAA,KAcA,cACE,KAAA,EAAA,EAAA,KACA,MAAA,KAFF,cACE,KAAA,EAAA,EAAA,KACA,MAAA,IAFF,cACE,KAAA,EAAA,EAAA,KACA,MAAA,aAFF,cACE,KAAA,EAAA,EAAA,KACA,MAAA,IAFF,cACE,KAAA,EAAA,EAAA,KACA,MAAA,IAFF,cACE,KAAA,EAAA,EAAA,KACA,MAAA,aA+BE,UAhDJ,KAAA,EAAA,EAAA,KACA,MAAA,KAqDQ,OAhEN,KAAA,EAAA,EAAA,KACA,MAAA,YA+DM,OAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,OAhEN,KAAA,EAAA,EAAA,KACA,MAAA,IA+DM,OAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,OAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,OAhEN,KAAA,EAAA,EAAA,KACA,MAAA,IA+DM,OAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,OAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,OAhEN,KAAA,EAAA,EAAA,KACA,MAAA,IA+DM,QAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,QAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,QAhEN,KAAA,EAAA,EAAA,KACA,MAAA,KAuEQ,UAxDV,aAAA,YAwDU,UAxDV,aAAA,aAwDU,UAxDV,aAAA,IAwDU,UAxDV,aAAA,aAwDU,UAxDV,aAAA,aAwDU,UAxDV,aAAA,IAwDU,UAxDV,aAAA,aAwDU,UAxDV,aAAA,aAwDU,UAxDV,aAAA,IAwDU,WAxDV,aAAA,aAwDU,WAxDV,aAAA,aAmEM,KJ6GR,MI3GU,cAAA,EAGF,KJ6GR,MI3GU,cAAA,EAPF,KJuHR,MIrHU,cAAA,QAGF,KJuHR,MIrHU,cAAA,QAPF,KJiIR,MI/HU,cAAA,OAGF,KJiIR,MI/HU,cAAA,OAPF,KJ2IR,MIzIU,cAAA,KAGF,KJ2IR,MIzIU,cAAA,KAPF,KJqJR,MInJU,cAAA,OAGF,KJqJR,MInJU,cAAA,OAPF,KJ+JR,MI7JU,cAAA,KAGF,KJ+JR,MI7JU,cAAA,KF1DN,yBEUE,QACE,KAAA,EAAA,EAAA,GAGF,oBApCJ,KAAA,EAAA,EAAA,KACA,MAAA,KAcA,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,KAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,IAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,aAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,IAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,IAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,aA+BE,aAhDJ,KAAA,EAAA,EAAA,KACA,MAAA,KAqDQ,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,YA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,IA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,IA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,IA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,KAuEQ,aAxDV,aAAA,EAwDU,aAxDV,aAAA,YAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,IAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,IAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,IAwDU,cAxDV,aAAA,aAwDU,cAxDV,aAAA,aAmEM,QJiSN,SI/RQ,cAAA,EAGF,QJgSN,SI9RQ,cAAA,EAPF,QJySN,SIvSQ,cAAA,QAGF,QJwSN,SItSQ,cAAA,QAPF,QJiTN,SI/SQ,cAAA,OAGF,QJgTN,SI9SQ,cAAA,OAPF,QJyTN,SIvTQ,cAAA,KAGF,QJwTN,SItTQ,cAAA,KAPF,QJiUN,SI/TQ,cAAA,OAGF,QJgUN,SI9TQ,cAAA,OAPF,QJyUN,SIvUQ,cAAA,KAGF,QJwUN,SItUQ,cAAA,MF1DN,yBEUE,QACE,KAAA,EAAA,EAAA,GAGF,oBApCJ,KAAA,EAAA,EAAA,KACA,MAAA,KAcA,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,KAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,IAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,aAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,IAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,IAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,aA+BE,aAhDJ,KAAA,EAAA,EAAA,KACA,MAAA,KAqDQ,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,YA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,IA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,IA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,IA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,KAuEQ,aAxDV,aAAA,EAwDU,aAxDV,aAAA,YAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,IAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,IAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,IAwDU,cAxDV,aAAA,aAwDU,cAxDV,aAAA,aAmEM,QJ0cN,SIxcQ,cAAA,EAGF,QJycN,SIvcQ,cAAA,EAPF,QJkdN,SIhdQ,cAAA,QAGF,QJidN,SI/cQ,cAAA,QAPF,QJ0dN,SIxdQ,cAAA,OAGF,QJydN,SIvdQ,cAAA,OAPF,QJkeN,SIheQ,cAAA,KAGF,QJieN,SI/dQ,cAAA,KAPF,QJ0eN,SIxeQ,cAAA,OAGF,QJyeN,SIveQ,cAAA,OAPF,QJkfN,SIhfQ,cAAA,KAGF,QJifN,SI/eQ,cAAA,MF1DN,yBEUE,QACE,KAAA,EAAA,EAAA,GAGF,oBApCJ,KAAA,EAAA,EAAA,KACA,MAAA,KAcA,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,KAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,IAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,aAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,IAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,IAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,aA+BE,aAhDJ,KAAA,EAAA,EAAA,KACA,MAAA,KAqDQ,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,YA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,IA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,IA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,IA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,KAuEQ,aAxDV,aAAA,EAwDU,aAxDV,aAAA,YAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,IAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,IAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,IAwDU,cAxDV,aAAA,aAwDU,cAxDV,aAAA,aAmEM,QJmnBN,SIjnBQ,cAAA,EAGF,QJknBN,SIhnBQ,cAAA,EAPF,QJ2nBN,SIznBQ,cAAA,QAGF,QJ0nBN,SIxnBQ,cAAA,QAPF,QJmoBN,SIjoBQ,cAAA,OAGF,QJkoBN,SIhoBQ,cAAA,OAPF,QJ2oBN,SIzoBQ,cAAA,KAGF,QJ0oBN,SIxoBQ,cAAA,KAPF,QJmpBN,SIjpBQ,cAAA,OAGF,QJkpBN,SIhpBQ,cAAA,OAPF,QJ2pBN,SIzpBQ,cAAA,KAGF,QJ0pBN,SIxpBQ,cAAA,MF1DN,0BEUE,QACE,KAAA,EAAA,EAAA,GAGF,oBApCJ,KAAA,EAAA,EAAA,KACA,MAAA,KAcA,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,KAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,IAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,aAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,IAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,IAFF,iBACE,KAAA,EAAA,EAAA,KACA,MAAA,aA+BE,aAhDJ,KAAA,EAAA,EAAA,KACA,MAAA,KAqDQ,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,YA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,IA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,IA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,UAhEN,KAAA,EAAA,EAAA,KACA,MAAA,IA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,KAuEQ,aAxDV,aAAA,EAwDU,aAxDV,aAAA,YAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,IAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,IAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,aAwDU,aAxDV,aAAA,IAwDU,cAxDV,aAAA,aAwDU,cAxDV,aAAA,aAmEM,QJ4xBN,SI1xBQ,cAAA,EAGF,QJ2xBN,SIzxBQ,cAAA,EAPF,QJoyBN,SIlyBQ,cAAA,QAGF,QJmyBN,SIjyBQ,cAAA,QAPF,QJ4yBN,SI1yBQ,cAAA,OAGF,QJ2yBN,SIzyBQ,cAAA,OAPF,QJozBN,SIlzBQ,cAAA,KAGF,QJmzBN,SIjzBQ,cAAA,KAPF,QJ4zBN,SI1zBQ,cAAA,OAGF,QJ2zBN,SIzzBQ,cAAA,OAPF,QJo0BN,SIl0BQ,cAAA,KAGF,QJm0BN,SIj0BQ,cAAA,MF1DN,0BEUE,SACE,KAAA,EAAA,EAAA,GAGF,qBApCJ,KAAA,EAAA,EAAA,KACA,MAAA,KAcA,kBACE,KAAA,EAAA,EAAA,KACA,MAAA,KAFF,kBACE,KAAA,EAAA,EAAA,KACA,MAAA,IAFF,kBACE,KAAA,EAAA,EAAA,KACA,MAAA,aAFF,kBACE,KAAA,EAAA,EAAA,KACA,MAAA,IAFF,kBACE,KAAA,EAAA,EAAA,KACA,MAAA,IAFF,kBACE,KAAA,EAAA,EAAA,KACA,MAAA,aA+BE,cAhDJ,KAAA,EAAA,EAAA,KACA,MAAA,KAqDQ,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,YA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,IA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,IA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,WAhEN,KAAA,EAAA,EAAA,KACA,MAAA,IA+DM,YAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,YAhEN,KAAA,EAAA,EAAA,KACA,MAAA,aA+DM,YAhEN,KAAA,EAAA,EAAA,KACA,MAAA,KAuEQ,cAxDV,aAAA,EAwDU,cAxDV,aAAA,YAwDU,cAxDV,aAAA,aAwDU,cAxDV,aAAA,IAwDU,cAxDV,aAAA,aAwDU,cAxDV,aAAA,aAwDU,cAxDV,aAAA,IAwDU,cAxDV,aAAA,aAwDU,cAxDV,aAAA,aAwDU,cAxDV,aAAA,IAwDU,eAxDV,aAAA,aAwDU,eAxDV,aAAA,aAmEM,SJq8BN,UIn8BQ,cAAA,EAGF,SJo8BN,UIl8BQ,cAAA,EAPF,SJ68BN,UI38BQ,cAAA,QAGF,SJ48BN,UI18BQ,cAAA,QAPF,SJq9BN,UIn9BQ,cAAA,OAGF,SJo9BN,UIl9BQ,cAAA,OAPF,SJ69BN,UI39BQ,cAAA,KAGF,SJ49BN,UI19BQ,cAAA,KAPF,SJq+BN,UIn+BQ,cAAA,OAGF,SJo+BN,UIl+BQ,cAAA,OAPF,SJ6+BN,UI3+BQ,cAAA,KAGF,SJ4+BN,UI1+BQ,cAAA,MCvDF,UAOI,QAAA,iBAPJ,gBAOI,QAAA,uBAPJ,SAOI,QAAA,gBAPJ,QAOI,QAAA,eAPJ,eAOI,QAAA,sBAPJ,SAOI,QAAA,gBAPJ,aAOI,QAAA,oBAPJ,cAOI,QAAA,qBAPJ,QAOI,QAAA,eAPJ,eAOI,QAAA,sBAPJ,QAOI,QAAA,eAPJ,WAOI,KAAA,EAAA,EAAA,eAPJ,UAOI,eAAA,cAPJ,aAOI,eAAA,iBAPJ,kBAOI,eAAA,sBAPJ,qBAOI,eAAA,yBAPJ,aAOI,UAAA,YAPJ,aAOI,UAAA,YAPJ,eAOI,YAAA,YAPJ,eAOI,YAAA,YAPJ,WAOI,UAAA,eAPJ,aAOI,UAAA,iBAPJ,mBAOI,UAAA,uBAPJ,uBAOI,gBAAA,qBAPJ,qBAOI,gBAAA,mBAPJ,wBAOI,gBAAA,iBAPJ,yBAOI,gBAAA,wBAPJ,wBAOI,gBAAA,uBAPJ,wBAOI,gBAAA,uBAPJ,mBAOI,YAAA,qBAPJ,iBAOI,YAAA,mBAPJ,oBAOI,YAAA,iBAPJ,sBAOI,YAAA,mBAPJ,qBAOI,YAAA,kBAPJ,qBAOI,cAAA,qBAPJ,mBAOI,cAAA,mBAPJ,sBAOI,cAAA,iBAPJ,uBAOI,cAAA,wBAPJ,sBAOI,cAAA,uBAPJ,uBAOI,cAAA,kBAPJ,iBAOI,WAAA,eAPJ,kBAOI,WAAA,qBAPJ,gBAOI,WAAA,mBAPJ,mBAOI,WAAA,iBAPJ,qBAOI,WAAA,mBAPJ,oBAOI,WAAA,kBAPJ,aAOI,MAAA,aAPJ,SAOI,MAAA,YAPJ,SAOI,MAAA,YAPJ,SAOI,MAAA,YAPJ,SAOI,MAAA,YAPJ,SAOI,MAAA,YAPJ,SAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,KAOI,OAAA,YAPJ,KAOI,OAAA,iBAPJ,KAOI,OAAA,gBAPJ,KAOI,OAAA,eAPJ,KAOI,OAAA,iBAPJ,KAOI,OAAA,eAPJ,QAOI,OAAA,eAPJ,MAOI,YAAA,YAAA,aAAA,YAPJ,MAOI,YAAA,iBAAA,aAAA,iBAPJ,MAOI,YAAA,gBAAA,aAAA,gBAPJ,MAOI,YAAA,eAAA,aAAA,eAPJ,MAOI,YAAA,iBAAA,aAAA,iBAPJ,MAOI,YAAA,eAAA,aAAA,eAPJ,SAOI,YAAA,eAAA,aAAA,eAPJ,MAOI,WAAA,YAAA,cAAA,YAPJ,MAOI,WAAA,iBAAA,cAAA,iBAPJ,MAOI,WAAA,gBAAA,cAAA,gBAPJ,MAOI,WAAA,eAAA,cAAA,eAPJ,MAOI,WAAA,iBAAA,cAAA,iBAPJ,MAOI,WAAA,eAAA,cAAA,eAPJ,SAOI,WAAA,eAAA,cAAA,eAPJ,MAOI,WAAA,YAPJ,MAOI,WAAA,iBAPJ,MAOI,WAAA,gBAPJ,MAOI,WAAA,eAPJ,MAOI,WAAA,iBAPJ,MAOI,WAAA,eAPJ,SAOI,WAAA,eAPJ,MAOI,YAAA,YAPJ,MAOI,YAAA,iBAPJ,MAOI,YAAA,gBAPJ,MAOI,YAAA,eAPJ,MAOI,YAAA,iBAPJ,MAOI,YAAA,eAPJ,SAOI,YAAA,eAPJ,MAOI,cAAA,YAPJ,MAOI,cAAA,iBAPJ,MAOI,cAAA,gBAPJ,MAOI,cAAA,eAPJ,MAOI,cAAA,iBAPJ,MAOI,cAAA,eAPJ,SAOI,cAAA,eAPJ,MAOI,aAAA,YAPJ,MAOI,aAAA,iBAPJ,MAOI,aAAA,gBAPJ,MAOI,aAAA,eAPJ,MAOI,aAAA,iBAPJ,MAOI,aAAA,eAPJ,SAOI,aAAA,eAPJ,KAOI,QAAA,YAPJ,KAOI,QAAA,iBAPJ,KAOI,QAAA,gBAPJ,KAOI,QAAA,eAPJ,KAOI,QAAA,iBAPJ,KAOI,QAAA,eAPJ,MAOI,aAAA,YAAA,cAAA,YAPJ,MAOI,aAAA,iBAAA,cAAA,iBAPJ,MAOI,aAAA,gBAAA,cAAA,gBAPJ,MAOI,aAAA,eAAA,cAAA,eAPJ,MAOI,aAAA,iBAAA,cAAA,iBAPJ,MAOI,aAAA,eAAA,cAAA,eAPJ,MAOI,YAAA,YAAA,eAAA,YAPJ,MAOI,YAAA,iBAAA,eAAA,iBAPJ,MAOI,YAAA,gBAAA,eAAA,gBAPJ,MAOI,YAAA,eAAA,eAAA,eAPJ,MAOI,YAAA,iBAAA,eAAA,iBAPJ,MAOI,YAAA,eAAA,eAAA,eAPJ,MAOI,YAAA,YAPJ,MAOI,YAAA,iBAPJ,MAOI,YAAA,gBAPJ,MAOI,YAAA,eAPJ,MAOI,YAAA,iBAPJ,MAOI,YAAA,eAPJ,MAOI,aAAA,YAPJ,MAOI,aAAA,iBAPJ,MAOI,aAAA,gBAPJ,MAOI,aAAA,eAPJ,MAOI,aAAA,iBAPJ,MAOI,aAAA,eAPJ,MAOI,eAAA,YAPJ,MAOI,eAAA,iBAPJ,MAOI,eAAA,gBAPJ,MAOI,eAAA,eAPJ,MAOI,eAAA,iBAPJ,MAOI,eAAA,eAPJ,MAOI,cAAA,YAPJ,MAOI,cAAA,iBAPJ,MAOI,cAAA,gBAPJ,MAOI,cAAA,eAPJ,MAOI,cAAA,iBAPJ,MAOI,cAAA,eHVR,yBGGI,aAOI,QAAA,iBAPJ,mBAOI,QAAA,uBAPJ,YAOI,QAAA,gBAPJ,WAOI,QAAA,eAPJ,kBAOI,QAAA,sBAPJ,YAOI,QAAA,gBAPJ,gBAOI,QAAA,oBAPJ,iBAOI,QAAA,qBAPJ,WAOI,QAAA,eAPJ,kBAOI,QAAA,sBAPJ,WAOI,QAAA,eAPJ,cAOI,KAAA,EAAA,EAAA,eAPJ,aAOI,eAAA,cAPJ,gBAOI,eAAA,iBAPJ,qBAOI,eAAA,sBAPJ,wBAOI,eAAA,yBAPJ,gBAOI,UAAA,YAPJ,gBAOI,UAAA,YAPJ,kBAOI,YAAA,YAPJ,kBAOI,YAAA,YAPJ,cAOI,UAAA,eAPJ,gBAOI,UAAA,iBAPJ,sBAOI,UAAA,uBAPJ,0BAOI,gBAAA,qBAPJ,wBAOI,gBAAA,mBAPJ,2BAOI,gBAAA,iBAPJ,4BAOI,gBAAA,wBAPJ,2BAOI,gBAAA,uBAPJ,2BAOI,gBAAA,uBAPJ,sBAOI,YAAA,qBAPJ,oBAOI,YAAA,mBAPJ,uBAOI,YAAA,iBAPJ,yBAOI,YAAA,mBAPJ,wBAOI,YAAA,kBAPJ,wBAOI,cAAA,qBAPJ,sBAOI,cAAA,mBAPJ,yBAOI,cAAA,iBAPJ,0BAOI,cAAA,wBAPJ,yBAOI,cAAA,uBAPJ,0BAOI,cAAA,kBAPJ,oBAOI,WAAA,eAPJ,qBAOI,WAAA,qBAPJ,mBAOI,WAAA,mBAPJ,sBAOI,WAAA,iBAPJ,wBAOI,WAAA,mBAPJ,uBAOI,WAAA,kBAPJ,gBAOI,MAAA,aAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,eAOI,MAAA,YAPJ,QAOI,OAAA,YAPJ,QAOI,OAAA,iBAPJ,QAOI,OAAA,gBAPJ,QAOI,OAAA,eAPJ,QAOI,OAAA,iBAPJ,QAOI,OAAA,eAPJ,WAOI,OAAA,eAPJ,SAOI,YAAA,YAAA,aAAA,YAPJ,SAOI,YAAA,iBAAA,aAAA,iBAPJ,SAOI,YAAA,gBAAA,aAAA,gBAPJ,SAOI,YAAA,eAAA,aAAA,eAPJ,SAOI,YAAA,iBAAA,aAAA,iBAPJ,SAOI,YAAA,eAAA,aAAA,eAPJ,YAOI,YAAA,eAAA,aAAA,eAPJ,SAOI,WAAA,YAAA,cAAA,YAPJ,SAOI,WAAA,iBAAA,cAAA,iBAPJ,SAOI,WAAA,gBAAA,cAAA,gBAPJ,SAOI,WAAA,eAAA,cAAA,eAPJ,SAOI,WAAA,iBAAA,cAAA,iBAPJ,SAOI,WAAA,eAAA,cAAA,eAPJ,YAOI,WAAA,eAAA,cAAA,eAPJ,SAOI,WAAA,YAPJ,SAOI,WAAA,iBAPJ,SAOI,WAAA,gBAPJ,SAOI,WAAA,eAPJ,SAOI,WAAA,iBAPJ,SAOI,WAAA,eAPJ,YAOI,WAAA,eAPJ,SAOI,YAAA,YAPJ,SAOI,YAAA,iBAPJ,SAOI,YAAA,gBAPJ,SAOI,YAAA,eAPJ,SAOI,YAAA,iBAPJ,SAOI,YAAA,eAPJ,YAOI,YAAA,eAPJ,SAOI,cAAA,YAPJ,SAOI,cAAA,iBAPJ,SAOI,cAAA,gBAPJ,SAOI,cAAA,eAPJ,SAOI,cAAA,iBAPJ,SAOI,cAAA,eAPJ,YAOI,cAAA,eAPJ,SAOI,aAAA,YAPJ,SAOI,aAAA,iBAPJ,SAOI,aAAA,gBAPJ,SAOI,aAAA,eAPJ,SAOI,aAAA,iBAPJ,SAOI,aAAA,eAPJ,YAOI,aAAA,eAPJ,QAOI,QAAA,YAPJ,QAOI,QAAA,iBAPJ,QAOI,QAAA,gBAPJ,QAOI,QAAA,eAPJ,QAOI,QAAA,iBAPJ,QAOI,QAAA,eAPJ,SAOI,aAAA,YAAA,cAAA,YAPJ,SAOI,aAAA,iBAAA,cAAA,iBAPJ,SAOI,aAAA,gBAAA,cAAA,gBAPJ,SAOI,aAAA,eAAA,cAAA,eAPJ,SAOI,aAAA,iBAAA,cAAA,iBAPJ,SAOI,aAAA,eAAA,cAAA,eAPJ,SAOI,YAAA,YAAA,eAAA,YAPJ,SAOI,YAAA,iBAAA,eAAA,iBAPJ,SAOI,YAAA,gBAAA,eAAA,gBAPJ,SAOI,YAAA,eAAA,eAAA,eAPJ,SAOI,YAAA,iBAAA,eAAA,iBAPJ,SAOI,YAAA,eAAA,eAAA,eAPJ,SAOI,YAAA,YAPJ,SAOI,YAAA,iBAPJ,SAOI,YAAA,gBAPJ,SAOI,YAAA,eAPJ,SAOI,YAAA,iBAPJ,SAOI,YAAA,eAPJ,SAOI,aAAA,YAPJ,SAOI,aAAA,iBAPJ,SAOI,aAAA,gBAPJ,SAOI,aAAA,eAPJ,SAOI,aAAA,iBAPJ,SAOI,aAAA,eAPJ,SAOI,eAAA,YAPJ,SAOI,eAAA,iBAPJ,SAOI,eAAA,gBAPJ,SAOI,eAAA,eAPJ,SAOI,eAAA,iBAPJ,SAOI,eAAA,eAPJ,SAOI,cAAA,YAPJ,SAOI,cAAA,iBAPJ,SAOI,cAAA,gBAPJ,SAOI,cAAA,eAPJ,SAOI,cAAA,iBAPJ,SAOI,cAAA,gBHVR,yBGGI,aAOI,QAAA,iBAPJ,mBAOI,QAAA,uBAPJ,YAOI,QAAA,gBAPJ,WAOI,QAAA,eAPJ,kBAOI,QAAA,sBAPJ,YAOI,QAAA,gBAPJ,gBAOI,QAAA,oBAPJ,iBAOI,QAAA,qBAPJ,WAOI,QAAA,eAPJ,kBAOI,QAAA,sBAPJ,WAOI,QAAA,eAPJ,cAOI,KAAA,EAAA,EAAA,eAPJ,aAOI,eAAA,cAPJ,gBAOI,eAAA,iBAPJ,qBAOI,eAAA,sBAPJ,wBAOI,eAAA,yBAPJ,gBAOI,UAAA,YAPJ,gBAOI,UAAA,YAPJ,kBAOI,YAAA,YAPJ,kBAOI,YAAA,YAPJ,cAOI,UAAA,eAPJ,gBAOI,UAAA,iBAPJ,sBAOI,UAAA,uBAPJ,0BAOI,gBAAA,qBAPJ,wBAOI,gBAAA,mBAPJ,2BAOI,gBAAA,iBAPJ,4BAOI,gBAAA,wBAPJ,2BAOI,gBAAA,uBAPJ,2BAOI,gBAAA,uBAPJ,sBAOI,YAAA,qBAPJ,oBAOI,YAAA,mBAPJ,uBAOI,YAAA,iBAPJ,yBAOI,YAAA,mBAPJ,wBAOI,YAAA,kBAPJ,wBAOI,cAAA,qBAPJ,sBAOI,cAAA,mBAPJ,yBAOI,cAAA,iBAPJ,0BAOI,cAAA,wBAPJ,yBAOI,cAAA,uBAPJ,0BAOI,cAAA,kBAPJ,oBAOI,WAAA,eAPJ,qBAOI,WAAA,qBAPJ,mBAOI,WAAA,mBAPJ,sBAOI,WAAA,iBAPJ,wBAOI,WAAA,mBAPJ,uBAOI,WAAA,kBAPJ,gBAOI,MAAA,aAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,eAOI,MAAA,YAPJ,QAOI,OAAA,YAPJ,QAOI,OAAA,iBAPJ,QAOI,OAAA,gBAPJ,QAOI,OAAA,eAPJ,QAOI,OAAA,iBAPJ,QAOI,OAAA,eAPJ,WAOI,OAAA,eAPJ,SAOI,YAAA,YAAA,aAAA,YAPJ,SAOI,YAAA,iBAAA,aAAA,iBAPJ,SAOI,YAAA,gBAAA,aAAA,gBAPJ,SAOI,YAAA,eAAA,aAAA,eAPJ,SAOI,YAAA,iBAAA,aAAA,iBAPJ,SAOI,YAAA,eAAA,aAAA,eAPJ,YAOI,YAAA,eAAA,aAAA,eAPJ,SAOI,WAAA,YAAA,cAAA,YAPJ,SAOI,WAAA,iBAAA,cAAA,iBAPJ,SAOI,WAAA,gBAAA,cAAA,gBAPJ,SAOI,WAAA,eAAA,cAAA,eAPJ,SAOI,WAAA,iBAAA,cAAA,iBAPJ,SAOI,WAAA,eAAA,cAAA,eAPJ,YAOI,WAAA,eAAA,cAAA,eAPJ,SAOI,WAAA,YAPJ,SAOI,WAAA,iBAPJ,SAOI,WAAA,gBAPJ,SAOI,WAAA,eAPJ,SAOI,WAAA,iBAPJ,SAOI,WAAA,eAPJ,YAOI,WAAA,eAPJ,SAOI,YAAA,YAPJ,SAOI,YAAA,iBAPJ,SAOI,YAAA,gBAPJ,SAOI,YAAA,eAPJ,SAOI,YAAA,iBAPJ,SAOI,YAAA,eAPJ,YAOI,YAAA,eAPJ,SAOI,cAAA,YAPJ,SAOI,cAAA,iBAPJ,SAOI,cAAA,gBAPJ,SAOI,cAAA,eAPJ,SAOI,cAAA,iBAPJ,SAOI,cAAA,eAPJ,YAOI,cAAA,eAPJ,SAOI,aAAA,YAPJ,SAOI,aAAA,iBAPJ,SAOI,aAAA,gBAPJ,SAOI,aAAA,eAPJ,SAOI,aAAA,iBAPJ,SAOI,aAAA,eAPJ,YAOI,aAAA,eAPJ,QAOI,QAAA,YAPJ,QAOI,QAAA,iBAPJ,QAOI,QAAA,gBAPJ,QAOI,QAAA,eAPJ,QAOI,QAAA,iBAPJ,QAOI,QAAA,eAPJ,SAOI,aAAA,YAAA,cAAA,YAPJ,SAOI,aAAA,iBAAA,cAAA,iBAPJ,SAOI,aAAA,gBAAA,cAAA,gBAPJ,SAOI,aAAA,eAAA,cAAA,eAPJ,SAOI,aAAA,iBAAA,cAAA,iBAPJ,SAOI,aAAA,eAAA,cAAA,eAPJ,SAOI,YAAA,YAAA,eAAA,YAPJ,SAOI,YAAA,iBAAA,eAAA,iBAPJ,SAOI,YAAA,gBAAA,eAAA,gBAPJ,SAOI,YAAA,eAAA,eAAA,eAPJ,SAOI,YAAA,iBAAA,eAAA,iBAPJ,SAOI,YAAA,eAAA,eAAA,eAPJ,SAOI,YAAA,YAPJ,SAOI,YAAA,iBAPJ,SAOI,YAAA,gBAPJ,SAOI,YAAA,eAPJ,SAOI,YAAA,iBAPJ,SAOI,YAAA,eAPJ,SAOI,aAAA,YAPJ,SAOI,aAAA,iBAPJ,SAOI,aAAA,gBAPJ,SAOI,aAAA,eAPJ,SAOI,aAAA,iBAPJ,SAOI,aAAA,eAPJ,SAOI,eAAA,YAPJ,SAOI,eAAA,iBAPJ,SAOI,eAAA,gBAPJ,SAOI,eAAA,eAPJ,SAOI,eAAA,iBAPJ,SAOI,eAAA,eAPJ,SAOI,cAAA,YAPJ,SAOI,cAAA,iBAPJ,SAOI,cAAA,gBAPJ,SAOI,cAAA,eAPJ,SAOI,cAAA,iBAPJ,SAOI,cAAA,gBHVR,yBGGI,aAOI,QAAA,iBAPJ,mBAOI,QAAA,uBAPJ,YAOI,QAAA,gBAPJ,WAOI,QAAA,eAPJ,kBAOI,QAAA,sBAPJ,YAOI,QAAA,gBAPJ,gBAOI,QAAA,oBAPJ,iBAOI,QAAA,qBAPJ,WAOI,QAAA,eAPJ,kBAOI,QAAA,sBAPJ,WAOI,QAAA,eAPJ,cAOI,KAAA,EAAA,EAAA,eAPJ,aAOI,eAAA,cAPJ,gBAOI,eAAA,iBAPJ,qBAOI,eAAA,sBAPJ,wBAOI,eAAA,yBAPJ,gBAOI,UAAA,YAPJ,gBAOI,UAAA,YAPJ,kBAOI,YAAA,YAPJ,kBAOI,YAAA,YAPJ,cAOI,UAAA,eAPJ,gBAOI,UAAA,iBAPJ,sBAOI,UAAA,uBAPJ,0BAOI,gBAAA,qBAPJ,wBAOI,gBAAA,mBAPJ,2BAOI,gBAAA,iBAPJ,4BAOI,gBAAA,wBAPJ,2BAOI,gBAAA,uBAPJ,2BAOI,gBAAA,uBAPJ,sBAOI,YAAA,qBAPJ,oBAOI,YAAA,mBAPJ,uBAOI,YAAA,iBAPJ,yBAOI,YAAA,mBAPJ,wBAOI,YAAA,kBAPJ,wBAOI,cAAA,qBAPJ,sBAOI,cAAA,mBAPJ,yBAOI,cAAA,iBAPJ,0BAOI,cAAA,wBAPJ,yBAOI,cAAA,uBAPJ,0BAOI,cAAA,kBAPJ,oBAOI,WAAA,eAPJ,qBAOI,WAAA,qBAPJ,mBAOI,WAAA,mBAPJ,sBAOI,WAAA,iBAPJ,wBAOI,WAAA,mBAPJ,uBAOI,WAAA,kBAPJ,gBAOI,MAAA,aAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,eAOI,MAAA,YAPJ,QAOI,OAAA,YAPJ,QAOI,OAAA,iBAPJ,QAOI,OAAA,gBAPJ,QAOI,OAAA,eAPJ,QAOI,OAAA,iBAPJ,QAOI,OAAA,eAPJ,WAOI,OAAA,eAPJ,SAOI,YAAA,YAAA,aAAA,YAPJ,SAOI,YAAA,iBAAA,aAAA,iBAPJ,SAOI,YAAA,gBAAA,aAAA,gBAPJ,SAOI,YAAA,eAAA,aAAA,eAPJ,SAOI,YAAA,iBAAA,aAAA,iBAPJ,SAOI,YAAA,eAAA,aAAA,eAPJ,YAOI,YAAA,eAAA,aAAA,eAPJ,SAOI,WAAA,YAAA,cAAA,YAPJ,SAOI,WAAA,iBAAA,cAAA,iBAPJ,SAOI,WAAA,gBAAA,cAAA,gBAPJ,SAOI,WAAA,eAAA,cAAA,eAPJ,SAOI,WAAA,iBAAA,cAAA,iBAPJ,SAOI,WAAA,eAAA,cAAA,eAPJ,YAOI,WAAA,eAAA,cAAA,eAPJ,SAOI,WAAA,YAPJ,SAOI,WAAA,iBAPJ,SAOI,WAAA,gBAPJ,SAOI,WAAA,eAPJ,SAOI,WAAA,iBAPJ,SAOI,WAAA,eAPJ,YAOI,WAAA,eAPJ,SAOI,YAAA,YAPJ,SAOI,YAAA,iBAPJ,SAOI,YAAA,gBAPJ,SAOI,YAAA,eAPJ,SAOI,YAAA,iBAPJ,SAOI,YAAA,eAPJ,YAOI,YAAA,eAPJ,SAOI,cAAA,YAPJ,SAOI,cAAA,iBAPJ,SAOI,cAAA,gBAPJ,SAOI,cAAA,eAPJ,SAOI,cAAA,iBAPJ,SAOI,cAAA,eAPJ,YAOI,cAAA,eAPJ,SAOI,aAAA,YAPJ,SAOI,aAAA,iBAPJ,SAOI,aAAA,gBAPJ,SAOI,aAAA,eAPJ,SAOI,aAAA,iBAPJ,SAOI,aAAA,eAPJ,YAOI,aAAA,eAPJ,QAOI,QAAA,YAPJ,QAOI,QAAA,iBAPJ,QAOI,QAAA,gBAPJ,QAOI,QAAA,eAPJ,QAOI,QAAA,iBAPJ,QAOI,QAAA,eAPJ,SAOI,aAAA,YAAA,cAAA,YAPJ,SAOI,aAAA,iBAAA,cAAA,iBAPJ,SAOI,aAAA,gBAAA,cAAA,gBAPJ,SAOI,aAAA,eAAA,cAAA,eAPJ,SAOI,aAAA,iBAAA,cAAA,iBAPJ,SAOI,aAAA,eAAA,cAAA,eAPJ,SAOI,YAAA,YAAA,eAAA,YAPJ,SAOI,YAAA,iBAAA,eAAA,iBAPJ,SAOI,YAAA,gBAAA,eAAA,gBAPJ,SAOI,YAAA,eAAA,eAAA,eAPJ,SAOI,YAAA,iBAAA,eAAA,iBAPJ,SAOI,YAAA,eAAA,eAAA,eAPJ,SAOI,YAAA,YAPJ,SAOI,YAAA,iBAPJ,SAOI,YAAA,gBAPJ,SAOI,YAAA,eAPJ,SAOI,YAAA,iBAPJ,SAOI,YAAA,eAPJ,SAOI,aAAA,YAPJ,SAOI,aAAA,iBAPJ,SAOI,aAAA,gBAPJ,SAOI,aAAA,eAPJ,SAOI,aAAA,iBAPJ,SAOI,aAAA,eAPJ,SAOI,eAAA,YAPJ,SAOI,eAAA,iBAPJ,SAOI,eAAA,gBAPJ,SAOI,eAAA,eAPJ,SAOI,eAAA,iBAPJ,SAOI,eAAA,eAPJ,SAOI,cAAA,YAPJ,SAOI,cAAA,iBAPJ,SAOI,cAAA,gBAPJ,SAOI,cAAA,eAPJ,SAOI,cAAA,iBAPJ,SAOI,cAAA,gBHVR,0BGGI,aAOI,QAAA,iBAPJ,mBAOI,QAAA,uBAPJ,YAOI,QAAA,gBAPJ,WAOI,QAAA,eAPJ,kBAOI,QAAA,sBAPJ,YAOI,QAAA,gBAPJ,gBAOI,QAAA,oBAPJ,iBAOI,QAAA,qBAPJ,WAOI,QAAA,eAPJ,kBAOI,QAAA,sBAPJ,WAOI,QAAA,eAPJ,cAOI,KAAA,EAAA,EAAA,eAPJ,aAOI,eAAA,cAPJ,gBAOI,eAAA,iBAPJ,qBAOI,eAAA,sBAPJ,wBAOI,eAAA,yBAPJ,gBAOI,UAAA,YAPJ,gBAOI,UAAA,YAPJ,kBAOI,YAAA,YAPJ,kBAOI,YAAA,YAPJ,cAOI,UAAA,eAPJ,gBAOI,UAAA,iBAPJ,sBAOI,UAAA,uBAPJ,0BAOI,gBAAA,qBAPJ,wBAOI,gBAAA,mBAPJ,2BAOI,gBAAA,iBAPJ,4BAOI,gBAAA,wBAPJ,2BAOI,gBAAA,uBAPJ,2BAOI,gBAAA,uBAPJ,sBAOI,YAAA,qBAPJ,oBAOI,YAAA,mBAPJ,uBAOI,YAAA,iBAPJ,yBAOI,YAAA,mBAPJ,wBAOI,YAAA,kBAPJ,wBAOI,cAAA,qBAPJ,sBAOI,cAAA,mBAPJ,yBAOI,cAAA,iBAPJ,0BAOI,cAAA,wBAPJ,yBAOI,cAAA,uBAPJ,0BAOI,cAAA,kBAPJ,oBAOI,WAAA,eAPJ,qBAOI,WAAA,qBAPJ,mBAOI,WAAA,mBAPJ,sBAOI,WAAA,iBAPJ,wBAOI,WAAA,mBAPJ,uBAOI,WAAA,kBAPJ,gBAOI,MAAA,aAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,YAOI,MAAA,YAPJ,eAOI,MAAA,YAPJ,QAOI,OAAA,YAPJ,QAOI,OAAA,iBAPJ,QAOI,OAAA,gBAPJ,QAOI,OAAA,eAPJ,QAOI,OAAA,iBAPJ,QAOI,OAAA,eAPJ,WAOI,OAAA,eAPJ,SAOI,YAAA,YAAA,aAAA,YAPJ,SAOI,YAAA,iBAAA,aAAA,iBAPJ,SAOI,YAAA,gBAAA,aAAA,gBAPJ,SAOI,YAAA,eAAA,aAAA,eAPJ,SAOI,YAAA,iBAAA,aAAA,iBAPJ,SAOI,YAAA,eAAA,aAAA,eAPJ,YAOI,YAAA,eAAA,aAAA,eAPJ,SAOI,WAAA,YAAA,cAAA,YAPJ,SAOI,WAAA,iBAAA,cAAA,iBAPJ,SAOI,WAAA,gBAAA,cAAA,gBAPJ,SAOI,WAAA,eAAA,cAAA,eAPJ,SAOI,WAAA,iBAAA,cAAA,iBAPJ,SAOI,WAAA,eAAA,cAAA,eAPJ,YAOI,WAAA,eAAA,cAAA,eAPJ,SAOI,WAAA,YAPJ,SAOI,WAAA,iBAPJ,SAOI,WAAA,gBAPJ,SAOI,WAAA,eAPJ,SAOI,WAAA,iBAPJ,SAOI,WAAA,eAPJ,YAOI,WAAA,eAPJ,SAOI,YAAA,YAPJ,SAOI,YAAA,iBAPJ,SAOI,YAAA,gBAPJ,SAOI,YAAA,eAPJ,SAOI,YAAA,iBAPJ,SAOI,YAAA,eAPJ,YAOI,YAAA,eAPJ,SAOI,cAAA,YAPJ,SAOI,cAAA,iBAPJ,SAOI,cAAA,gBAPJ,SAOI,cAAA,eAPJ,SAOI,cAAA,iBAPJ,SAOI,cAAA,eAPJ,YAOI,cAAA,eAPJ,SAOI,aAAA,YAPJ,SAOI,aAAA,iBAPJ,SAOI,aAAA,gBAPJ,SAOI,aAAA,eAPJ,SAOI,aAAA,iBAPJ,SAOI,aAAA,eAPJ,YAOI,aAAA,eAPJ,QAOI,QAAA,YAPJ,QAOI,QAAA,iBAPJ,QAOI,QAAA,gBAPJ,QAOI,QAAA,eAPJ,QAOI,QAAA,iBAPJ,QAOI,QAAA,eAPJ,SAOI,aAAA,YAAA,cAAA,YAPJ,SAOI,aAAA,iBAAA,cAAA,iBAPJ,SAOI,aAAA,gBAAA,cAAA,gBAPJ,SAOI,aAAA,eAAA,cAAA,eAPJ,SAOI,aAAA,iBAAA,cAAA,iBAPJ,SAOI,aAAA,eAAA,cAAA,eAPJ,SAOI,YAAA,YAAA,eAAA,YAPJ,SAOI,YAAA,iBAAA,eAAA,iBAPJ,SAOI,YAAA,gBAAA,eAAA,gBAPJ,SAOI,YAAA,eAAA,eAAA,eAPJ,SAOI,YAAA,iBAAA,eAAA,iBAPJ,SAOI,YAAA,eAAA,eAAA,eAPJ,SAOI,YAAA,YAPJ,SAOI,YAAA,iBAPJ,SAOI,YAAA,gBAPJ,SAOI,YAAA,eAPJ,SAOI,YAAA,iBAPJ,SAOI,YAAA,eAPJ,SAOI,aAAA,YAPJ,SAOI,aAAA,iBAPJ,SAOI,aAAA,gBAPJ,SAOI,aAAA,eAPJ,SAOI,aAAA,iBAPJ,SAOI,aAAA,eAPJ,SAOI,eAAA,YAPJ,SAOI,eAAA,iBAPJ,SAOI,eAAA,gBAPJ,SAOI,eAAA,eAPJ,SAOI,eAAA,iBAPJ,SAOI,eAAA,eAPJ,SAOI,cAAA,YAPJ,SAOI,cAAA,iBAPJ,SAOI,cAAA,gBAPJ,SAOI,cAAA,eAPJ,SAOI,cAAA,iBAPJ,SAOI,cAAA,gBHVR,0BGGI,cAOI,QAAA,iBAPJ,oBAOI,QAAA,uBAPJ,aAOI,QAAA,gBAPJ,YAOI,QAAA,eAPJ,mBAOI,QAAA,sBAPJ,aAOI,QAAA,gBAPJ,iBAOI,QAAA,oBAPJ,kBAOI,QAAA,qBAPJ,YAOI,QAAA,eAPJ,mBAOI,QAAA,sBAPJ,YAOI,QAAA,eAPJ,eAOI,KAAA,EAAA,EAAA,eAPJ,cAOI,eAAA,cAPJ,iBAOI,eAAA,iBAPJ,sBAOI,eAAA,sBAPJ,yBAOI,eAAA,yBAPJ,iBAOI,UAAA,YAPJ,iBAOI,UAAA,YAPJ,mBAOI,YAAA,YAPJ,mBAOI,YAAA,YAPJ,eAOI,UAAA,eAPJ,iBAOI,UAAA,iBAPJ,uBAOI,UAAA,uBAPJ,2BAOI,gBAAA,qBAPJ,yBAOI,gBAAA,mBAPJ,4BAOI,gBAAA,iBAPJ,6BAOI,gBAAA,wBAPJ,4BAOI,gBAAA,uBAPJ,4BAOI,gBAAA,uBAPJ,uBAOI,YAAA,qBAPJ,qBAOI,YAAA,mBAPJ,wBAOI,YAAA,iBAPJ,0BAOI,YAAA,mBAPJ,yBAOI,YAAA,kBAPJ,yBAOI,cAAA,qBAPJ,uBAOI,cAAA,mBAPJ,0BAOI,cAAA,iBAPJ,2BAOI,cAAA,wBAPJ,0BAOI,cAAA,uBAPJ,2BAOI,cAAA,kBAPJ,qBAOI,WAAA,eAPJ,sBAOI,WAAA,qBAPJ,oBAOI,WAAA,mBAPJ,uBAOI,WAAA,iBAPJ,yBAOI,WAAA,mBAPJ,wBAOI,WAAA,kBAPJ,iBAOI,MAAA,aAPJ,aAOI,MAAA,YAPJ,aAOI,MAAA,YAPJ,aAOI,MAAA,YAPJ,aAOI,MAAA,YAPJ,aAOI,MAAA,YAPJ,aAOI,MAAA,YAPJ,gBAOI,MAAA,YAPJ,SAOI,OAAA,YAPJ,SAOI,OAAA,iBAPJ,SAOI,OAAA,gBAPJ,SAOI,OAAA,eAPJ,SAOI,OAAA,iBAPJ,SAOI,OAAA,eAPJ,YAOI,OAAA,eAPJ,UAOI,YAAA,YAAA,aAAA,YAPJ,UAOI,YAAA,iBAAA,aAAA,iBAPJ,UAOI,YAAA,gBAAA,aAAA,gBAPJ,UAOI,YAAA,eAAA,aAAA,eAPJ,UAOI,YAAA,iBAAA,aAAA,iBAPJ,UAOI,YAAA,eAAA,aAAA,eAPJ,aAOI,YAAA,eAAA,aAAA,eAPJ,UAOI,WAAA,YAAA,cAAA,YAPJ,UAOI,WAAA,iBAAA,cAAA,iBAPJ,UAOI,WAAA,gBAAA,cAAA,gBAPJ,UAOI,WAAA,eAAA,cAAA,eAPJ,UAOI,WAAA,iBAAA,cAAA,iBAPJ,UAOI,WAAA,eAAA,cAAA,eAPJ,aAOI,WAAA,eAAA,cAAA,eAPJ,UAOI,WAAA,YAPJ,UAOI,WAAA,iBAPJ,UAOI,WAAA,gBAPJ,UAOI,WAAA,eAPJ,UAOI,WAAA,iBAPJ,UAOI,WAAA,eAPJ,aAOI,WAAA,eAPJ,UAOI,YAAA,YAPJ,UAOI,YAAA,iBAPJ,UAOI,YAAA,gBAPJ,UAOI,YAAA,eAPJ,UAOI,YAAA,iBAPJ,UAOI,YAAA,eAPJ,aAOI,YAAA,eAPJ,UAOI,cAAA,YAPJ,UAOI,cAAA,iBAPJ,UAOI,cAAA,gBAPJ,UAOI,cAAA,eAPJ,UAOI,cAAA,iBAPJ,UAOI,cAAA,eAPJ,aAOI,cAAA,eAPJ,UAOI,aAAA,YAPJ,UAOI,aAAA,iBAPJ,UAOI,aAAA,gBAPJ,UAOI,aAAA,eAPJ,UAOI,aAAA,iBAPJ,UAOI,aAAA,eAPJ,aAOI,aAAA,eAPJ,SAOI,QAAA,YAPJ,SAOI,QAAA,iBAPJ,SAOI,QAAA,gBAPJ,SAOI,QAAA,eAPJ,SAOI,QAAA,iBAPJ,SAOI,QAAA,eAPJ,UAOI,aAAA,YAAA,cAAA,YAPJ,UAOI,aAAA,iBAAA,cAAA,iBAPJ,UAOI,aAAA,gBAAA,cAAA,gBAPJ,UAOI,aAAA,eAAA,cAAA,eAPJ,UAOI,aAAA,iBAAA,cAAA,iBAPJ,UAOI,aAAA,eAAA,cAAA,eAPJ,UAOI,YAAA,YAAA,eAAA,YAPJ,UAOI,YAAA,iBAAA,eAAA,iBAPJ,UAOI,YAAA,gBAAA,eAAA,gBAPJ,UAOI,YAAA,eAAA,eAAA,eAPJ,UAOI,YAAA,iBAAA,eAAA,iBAPJ,UAOI,YAAA,eAAA,eAAA,eAPJ,UAOI,YAAA,YAPJ,UAOI,YAAA,iBAPJ,UAOI,YAAA,gBAPJ,UAOI,YAAA,eAPJ,UAOI,YAAA,iBAPJ,UAOI,YAAA,eAPJ,UAOI,aAAA,YAPJ,UAOI,aAAA,iBAPJ,UAOI,aAAA,gBAPJ,UAOI,aAAA,eAPJ,UAOI,aAAA,iBAPJ,UAOI,aAAA,eAPJ,UAOI,eAAA,YAPJ,UAOI,eAAA,iBAPJ,UAOI,eAAA,gBAPJ,UAOI,eAAA,eAPJ,UAOI,eAAA,iBAPJ,UAOI,eAAA,eAPJ,UAOI,cAAA,YAPJ,UAOI,cAAA,iBAPJ,UAOI,cAAA,gBAPJ,UAOI,cAAA,eAPJ,UAOI,cAAA,iBAPJ,UAOI,cAAA,gBCnCZ,aD4BQ,gBAOI,QAAA,iBAPJ,sBAOI,QAAA,uBAPJ,eAOI,QAAA,gBAPJ,cAOI,QAAA,eAPJ,qBAOI,QAAA,sBAPJ,eAOI,QAAA,gBAPJ,mBAOI,QAAA,oBAPJ,oBAOI,QAAA,qBAPJ,cAOI,QAAA,eAPJ,qBAOI,QAAA,sBAPJ,cAOI,QAAA","sourcesContent":["@mixin bsBanner($file) {\n /*!\n * Bootstrap #{$file} v5.3.3 (https://getbootstrap.com/)\n * Copyright 2011-2024 The Bootstrap Authors\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n}\n","// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n@if $enable-container-classes {\n // Single container class with breakpoint max-widths\n .container,\n // 100% wide container at all breakpoints\n .container-fluid {\n @include make-container();\n }\n\n // Responsive containers that are 100% wide until a breakpoint\n @each $breakpoint, $container-max-width in $container-max-widths {\n .container-#{$breakpoint} {\n @extend .container-fluid;\n }\n\n @include media-breakpoint-up($breakpoint, $grid-breakpoints) {\n %responsive-container-#{$breakpoint} {\n max-width: $container-max-width;\n }\n\n // Extend each breakpoint which is smaller or equal to the current breakpoint\n $extend-breakpoint: true;\n\n @each $name, $width in $grid-breakpoints {\n @if ($extend-breakpoint) {\n .container#{breakpoint-infix($name, $grid-breakpoints)} {\n @extend %responsive-container-#{$breakpoint};\n }\n\n // Once the current breakpoint is reached, stop extending\n @if ($breakpoint == $name) {\n $extend-breakpoint: false;\n }\n }\n }\n }\n }\n}\n","/*!\n * Bootstrap Grid v5.3.3 (https://getbootstrap.com/)\n * Copyright 2011-2024 The Bootstrap Authors\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n.container,\n.container-fluid,\n.container-xxl,\n.container-xl,\n.container-lg,\n.container-md,\n.container-sm {\n --bs-gutter-x: 1.5rem;\n --bs-gutter-y: 0;\n width: 100%;\n padding-left: calc(var(--bs-gutter-x) * 0.5);\n padding-right: calc(var(--bs-gutter-x) * 0.5);\n margin-left: auto;\n margin-right: auto;\n}\n\n@media (min-width: 576px) {\n .container-sm, .container {\n max-width: 540px;\n }\n}\n@media (min-width: 768px) {\n .container-md, .container-sm, .container {\n max-width: 720px;\n }\n}\n@media (min-width: 992px) {\n .container-lg, .container-md, .container-sm, .container {\n max-width: 960px;\n }\n}\n@media (min-width: 1200px) {\n .container-xl, .container-lg, .container-md, .container-sm, .container {\n max-width: 1140px;\n }\n}\n@media (min-width: 1400px) {\n .container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container {\n max-width: 1320px;\n }\n}\n:root {\n --bs-breakpoint-xs: 0;\n --bs-breakpoint-sm: 576px;\n --bs-breakpoint-md: 768px;\n --bs-breakpoint-lg: 992px;\n --bs-breakpoint-xl: 1200px;\n --bs-breakpoint-xxl: 1400px;\n}\n\n.row {\n --bs-gutter-x: 1.5rem;\n --bs-gutter-y: 0;\n display: flex;\n flex-wrap: wrap;\n margin-top: calc(-1 * var(--bs-gutter-y));\n margin-left: calc(-0.5 * var(--bs-gutter-x));\n margin-right: calc(-0.5 * var(--bs-gutter-x));\n}\n.row > * {\n box-sizing: border-box;\n flex-shrink: 0;\n width: 100%;\n max-width: 100%;\n padding-left: calc(var(--bs-gutter-x) * 0.5);\n padding-right: calc(var(--bs-gutter-x) * 0.5);\n margin-top: var(--bs-gutter-y);\n}\n\n.col {\n flex: 1 0 0%;\n}\n\n.row-cols-auto > * {\n flex: 0 0 auto;\n width: auto;\n}\n\n.row-cols-1 > * {\n flex: 0 0 auto;\n width: 100%;\n}\n\n.row-cols-2 > * {\n flex: 0 0 auto;\n width: 50%;\n}\n\n.row-cols-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n}\n\n.row-cols-4 > * {\n flex: 0 0 auto;\n width: 25%;\n}\n\n.row-cols-5 > * {\n flex: 0 0 auto;\n width: 20%;\n}\n\n.row-cols-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n}\n\n.col-auto {\n flex: 0 0 auto;\n width: auto;\n}\n\n.col-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n}\n\n.col-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n}\n\n.col-3 {\n flex: 0 0 auto;\n width: 25%;\n}\n\n.col-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n}\n\n.col-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n}\n\n.col-6 {\n flex: 0 0 auto;\n width: 50%;\n}\n\n.col-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n}\n\n.col-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n}\n\n.col-9 {\n flex: 0 0 auto;\n width: 75%;\n}\n\n.col-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n}\n\n.col-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n}\n\n.col-12 {\n flex: 0 0 auto;\n width: 100%;\n}\n\n.offset-1 {\n margin-right: 8.33333333%;\n}\n\n.offset-2 {\n margin-right: 16.66666667%;\n}\n\n.offset-3 {\n margin-right: 25%;\n}\n\n.offset-4 {\n margin-right: 33.33333333%;\n}\n\n.offset-5 {\n margin-right: 41.66666667%;\n}\n\n.offset-6 {\n margin-right: 50%;\n}\n\n.offset-7 {\n margin-right: 58.33333333%;\n}\n\n.offset-8 {\n margin-right: 66.66666667%;\n}\n\n.offset-9 {\n margin-right: 75%;\n}\n\n.offset-10 {\n margin-right: 83.33333333%;\n}\n\n.offset-11 {\n margin-right: 91.66666667%;\n}\n\n.g-0,\n.gx-0 {\n --bs-gutter-x: 0;\n}\n\n.g-0,\n.gy-0 {\n --bs-gutter-y: 0;\n}\n\n.g-1,\n.gx-1 {\n --bs-gutter-x: 0.25rem;\n}\n\n.g-1,\n.gy-1 {\n --bs-gutter-y: 0.25rem;\n}\n\n.g-2,\n.gx-2 {\n --bs-gutter-x: 0.5rem;\n}\n\n.g-2,\n.gy-2 {\n --bs-gutter-y: 0.5rem;\n}\n\n.g-3,\n.gx-3 {\n --bs-gutter-x: 1rem;\n}\n\n.g-3,\n.gy-3 {\n --bs-gutter-y: 1rem;\n}\n\n.g-4,\n.gx-4 {\n --bs-gutter-x: 1.5rem;\n}\n\n.g-4,\n.gy-4 {\n --bs-gutter-y: 1.5rem;\n}\n\n.g-5,\n.gx-5 {\n --bs-gutter-x: 3rem;\n}\n\n.g-5,\n.gy-5 {\n --bs-gutter-y: 3rem;\n}\n\n@media (min-width: 576px) {\n .col-sm {\n flex: 1 0 0%;\n }\n .row-cols-sm-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-sm-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-sm-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-sm-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-sm-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-sm-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-sm-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-sm-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-sm-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-sm-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-sm-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-sm-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-sm-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-sm-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-sm-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-sm-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-sm-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-sm-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-sm-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-sm-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-sm-0 {\n margin-right: 0;\n }\n .offset-sm-1 {\n margin-right: 8.33333333%;\n }\n .offset-sm-2 {\n margin-right: 16.66666667%;\n }\n .offset-sm-3 {\n margin-right: 25%;\n }\n .offset-sm-4 {\n margin-right: 33.33333333%;\n }\n .offset-sm-5 {\n margin-right: 41.66666667%;\n }\n .offset-sm-6 {\n margin-right: 50%;\n }\n .offset-sm-7 {\n margin-right: 58.33333333%;\n }\n .offset-sm-8 {\n margin-right: 66.66666667%;\n }\n .offset-sm-9 {\n margin-right: 75%;\n }\n .offset-sm-10 {\n margin-right: 83.33333333%;\n }\n .offset-sm-11 {\n margin-right: 91.66666667%;\n }\n .g-sm-0,\n .gx-sm-0 {\n --bs-gutter-x: 0;\n }\n .g-sm-0,\n .gy-sm-0 {\n --bs-gutter-y: 0;\n }\n .g-sm-1,\n .gx-sm-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-sm-1,\n .gy-sm-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-sm-2,\n .gx-sm-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-sm-2,\n .gy-sm-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-sm-3,\n .gx-sm-3 {\n --bs-gutter-x: 1rem;\n }\n .g-sm-3,\n .gy-sm-3 {\n --bs-gutter-y: 1rem;\n }\n .g-sm-4,\n .gx-sm-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-sm-4,\n .gy-sm-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-sm-5,\n .gx-sm-5 {\n --bs-gutter-x: 3rem;\n }\n .g-sm-5,\n .gy-sm-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 768px) {\n .col-md {\n flex: 1 0 0%;\n }\n .row-cols-md-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-md-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-md-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-md-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-md-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-md-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-md-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-md-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-md-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-md-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-md-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-md-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-md-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-md-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-md-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-md-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-md-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-md-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-md-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-md-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-md-0 {\n margin-right: 0;\n }\n .offset-md-1 {\n margin-right: 8.33333333%;\n }\n .offset-md-2 {\n margin-right: 16.66666667%;\n }\n .offset-md-3 {\n margin-right: 25%;\n }\n .offset-md-4 {\n margin-right: 33.33333333%;\n }\n .offset-md-5 {\n margin-right: 41.66666667%;\n }\n .offset-md-6 {\n margin-right: 50%;\n }\n .offset-md-7 {\n margin-right: 58.33333333%;\n }\n .offset-md-8 {\n margin-right: 66.66666667%;\n }\n .offset-md-9 {\n margin-right: 75%;\n }\n .offset-md-10 {\n margin-right: 83.33333333%;\n }\n .offset-md-11 {\n margin-right: 91.66666667%;\n }\n .g-md-0,\n .gx-md-0 {\n --bs-gutter-x: 0;\n }\n .g-md-0,\n .gy-md-0 {\n --bs-gutter-y: 0;\n }\n .g-md-1,\n .gx-md-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-md-1,\n .gy-md-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-md-2,\n .gx-md-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-md-2,\n .gy-md-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-md-3,\n .gx-md-3 {\n --bs-gutter-x: 1rem;\n }\n .g-md-3,\n .gy-md-3 {\n --bs-gutter-y: 1rem;\n }\n .g-md-4,\n .gx-md-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-md-4,\n .gy-md-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-md-5,\n .gx-md-5 {\n --bs-gutter-x: 3rem;\n }\n .g-md-5,\n .gy-md-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 992px) {\n .col-lg {\n flex: 1 0 0%;\n }\n .row-cols-lg-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-lg-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-lg-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-lg-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-lg-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-lg-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-lg-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-lg-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-lg-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-lg-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-lg-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-lg-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-lg-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-lg-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-lg-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-lg-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-lg-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-lg-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-lg-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-lg-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-lg-0 {\n margin-right: 0;\n }\n .offset-lg-1 {\n margin-right: 8.33333333%;\n }\n .offset-lg-2 {\n margin-right: 16.66666667%;\n }\n .offset-lg-3 {\n margin-right: 25%;\n }\n .offset-lg-4 {\n margin-right: 33.33333333%;\n }\n .offset-lg-5 {\n margin-right: 41.66666667%;\n }\n .offset-lg-6 {\n margin-right: 50%;\n }\n .offset-lg-7 {\n margin-right: 58.33333333%;\n }\n .offset-lg-8 {\n margin-right: 66.66666667%;\n }\n .offset-lg-9 {\n margin-right: 75%;\n }\n .offset-lg-10 {\n margin-right: 83.33333333%;\n }\n .offset-lg-11 {\n margin-right: 91.66666667%;\n }\n .g-lg-0,\n .gx-lg-0 {\n --bs-gutter-x: 0;\n }\n .g-lg-0,\n .gy-lg-0 {\n --bs-gutter-y: 0;\n }\n .g-lg-1,\n .gx-lg-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-lg-1,\n .gy-lg-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-lg-2,\n .gx-lg-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-lg-2,\n .gy-lg-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-lg-3,\n .gx-lg-3 {\n --bs-gutter-x: 1rem;\n }\n .g-lg-3,\n .gy-lg-3 {\n --bs-gutter-y: 1rem;\n }\n .g-lg-4,\n .gx-lg-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-lg-4,\n .gy-lg-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-lg-5,\n .gx-lg-5 {\n --bs-gutter-x: 3rem;\n }\n .g-lg-5,\n .gy-lg-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 1200px) {\n .col-xl {\n flex: 1 0 0%;\n }\n .row-cols-xl-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-xl-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-xl-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-xl-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-xl-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-xl-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-xl-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xl-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-xl-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-xl-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xl-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-xl-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-xl-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-xl-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-xl-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-xl-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-xl-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-xl-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-xl-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-xl-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-xl-0 {\n margin-right: 0;\n }\n .offset-xl-1 {\n margin-right: 8.33333333%;\n }\n .offset-xl-2 {\n margin-right: 16.66666667%;\n }\n .offset-xl-3 {\n margin-right: 25%;\n }\n .offset-xl-4 {\n margin-right: 33.33333333%;\n }\n .offset-xl-5 {\n margin-right: 41.66666667%;\n }\n .offset-xl-6 {\n margin-right: 50%;\n }\n .offset-xl-7 {\n margin-right: 58.33333333%;\n }\n .offset-xl-8 {\n margin-right: 66.66666667%;\n }\n .offset-xl-9 {\n margin-right: 75%;\n }\n .offset-xl-10 {\n margin-right: 83.33333333%;\n }\n .offset-xl-11 {\n margin-right: 91.66666667%;\n }\n .g-xl-0,\n .gx-xl-0 {\n --bs-gutter-x: 0;\n }\n .g-xl-0,\n .gy-xl-0 {\n --bs-gutter-y: 0;\n }\n .g-xl-1,\n .gx-xl-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-xl-1,\n .gy-xl-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-xl-2,\n .gx-xl-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-xl-2,\n .gy-xl-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-xl-3,\n .gx-xl-3 {\n --bs-gutter-x: 1rem;\n }\n .g-xl-3,\n .gy-xl-3 {\n --bs-gutter-y: 1rem;\n }\n .g-xl-4,\n .gx-xl-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-xl-4,\n .gy-xl-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-xl-5,\n .gx-xl-5 {\n --bs-gutter-x: 3rem;\n }\n .g-xl-5,\n .gy-xl-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 1400px) {\n .col-xxl {\n flex: 1 0 0%;\n }\n .row-cols-xxl-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-xxl-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-xxl-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-xxl-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-xxl-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-xxl-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-xxl-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xxl-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-xxl-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-xxl-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xxl-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-xxl-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-xxl-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-xxl-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-xxl-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-xxl-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-xxl-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-xxl-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-xxl-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-xxl-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-xxl-0 {\n margin-right: 0;\n }\n .offset-xxl-1 {\n margin-right: 8.33333333%;\n }\n .offset-xxl-2 {\n margin-right: 16.66666667%;\n }\n .offset-xxl-3 {\n margin-right: 25%;\n }\n .offset-xxl-4 {\n margin-right: 33.33333333%;\n }\n .offset-xxl-5 {\n margin-right: 41.66666667%;\n }\n .offset-xxl-6 {\n margin-right: 50%;\n }\n .offset-xxl-7 {\n margin-right: 58.33333333%;\n }\n .offset-xxl-8 {\n margin-right: 66.66666667%;\n }\n .offset-xxl-9 {\n margin-right: 75%;\n }\n .offset-xxl-10 {\n margin-right: 83.33333333%;\n }\n .offset-xxl-11 {\n margin-right: 91.66666667%;\n }\n .g-xxl-0,\n .gx-xxl-0 {\n --bs-gutter-x: 0;\n }\n .g-xxl-0,\n .gy-xxl-0 {\n --bs-gutter-y: 0;\n }\n .g-xxl-1,\n .gx-xxl-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-xxl-1,\n .gy-xxl-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-xxl-2,\n .gx-xxl-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-xxl-2,\n .gy-xxl-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-xxl-3,\n .gx-xxl-3 {\n --bs-gutter-x: 1rem;\n }\n .g-xxl-3,\n .gy-xxl-3 {\n --bs-gutter-y: 1rem;\n }\n .g-xxl-4,\n .gx-xxl-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-xxl-4,\n .gy-xxl-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-xxl-5,\n .gx-xxl-5 {\n --bs-gutter-x: 3rem;\n }\n .g-xxl-5,\n .gy-xxl-5 {\n --bs-gutter-y: 3rem;\n }\n}\n.d-inline {\n display: inline !important;\n}\n\n.d-inline-block {\n display: inline-block !important;\n}\n\n.d-block {\n display: block !important;\n}\n\n.d-grid {\n display: grid !important;\n}\n\n.d-inline-grid {\n display: inline-grid !important;\n}\n\n.d-table {\n display: table !important;\n}\n\n.d-table-row {\n display: table-row !important;\n}\n\n.d-table-cell {\n display: table-cell !important;\n}\n\n.d-flex {\n display: flex !important;\n}\n\n.d-inline-flex {\n display: inline-flex !important;\n}\n\n.d-none {\n display: none !important;\n}\n\n.flex-fill {\n flex: 1 1 auto !important;\n}\n\n.flex-row {\n flex-direction: row !important;\n}\n\n.flex-column {\n flex-direction: column !important;\n}\n\n.flex-row-reverse {\n flex-direction: row-reverse !important;\n}\n\n.flex-column-reverse {\n flex-direction: column-reverse !important;\n}\n\n.flex-grow-0 {\n flex-grow: 0 !important;\n}\n\n.flex-grow-1 {\n flex-grow: 1 !important;\n}\n\n.flex-shrink-0 {\n flex-shrink: 0 !important;\n}\n\n.flex-shrink-1 {\n flex-shrink: 1 !important;\n}\n\n.flex-wrap {\n flex-wrap: wrap !important;\n}\n\n.flex-nowrap {\n flex-wrap: nowrap !important;\n}\n\n.flex-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n}\n\n.justify-content-start {\n justify-content: flex-start !important;\n}\n\n.justify-content-end {\n justify-content: flex-end !important;\n}\n\n.justify-content-center {\n justify-content: center !important;\n}\n\n.justify-content-between {\n justify-content: space-between !important;\n}\n\n.justify-content-around {\n justify-content: space-around !important;\n}\n\n.justify-content-evenly {\n justify-content: space-evenly !important;\n}\n\n.align-items-start {\n align-items: flex-start !important;\n}\n\n.align-items-end {\n align-items: flex-end !important;\n}\n\n.align-items-center {\n align-items: center !important;\n}\n\n.align-items-baseline {\n align-items: baseline !important;\n}\n\n.align-items-stretch {\n align-items: stretch !important;\n}\n\n.align-content-start {\n align-content: flex-start !important;\n}\n\n.align-content-end {\n align-content: flex-end !important;\n}\n\n.align-content-center {\n align-content: center !important;\n}\n\n.align-content-between {\n align-content: space-between !important;\n}\n\n.align-content-around {\n align-content: space-around !important;\n}\n\n.align-content-stretch {\n align-content: stretch !important;\n}\n\n.align-self-auto {\n align-self: auto !important;\n}\n\n.align-self-start {\n align-self: flex-start !important;\n}\n\n.align-self-end {\n align-self: flex-end !important;\n}\n\n.align-self-center {\n align-self: center !important;\n}\n\n.align-self-baseline {\n align-self: baseline !important;\n}\n\n.align-self-stretch {\n align-self: stretch !important;\n}\n\n.order-first {\n order: -1 !important;\n}\n\n.order-0 {\n order: 0 !important;\n}\n\n.order-1 {\n order: 1 !important;\n}\n\n.order-2 {\n order: 2 !important;\n}\n\n.order-3 {\n order: 3 !important;\n}\n\n.order-4 {\n order: 4 !important;\n}\n\n.order-5 {\n order: 5 !important;\n}\n\n.order-last {\n order: 6 !important;\n}\n\n.m-0 {\n margin: 0 !important;\n}\n\n.m-1 {\n margin: 0.25rem !important;\n}\n\n.m-2 {\n margin: 0.5rem !important;\n}\n\n.m-3 {\n margin: 1rem !important;\n}\n\n.m-4 {\n margin: 1.5rem !important;\n}\n\n.m-5 {\n margin: 3rem !important;\n}\n\n.m-auto {\n margin: auto !important;\n}\n\n.mx-0 {\n margin-left: 0 !important;\n margin-right: 0 !important;\n}\n\n.mx-1 {\n margin-left: 0.25rem !important;\n margin-right: 0.25rem !important;\n}\n\n.mx-2 {\n margin-left: 0.5rem !important;\n margin-right: 0.5rem !important;\n}\n\n.mx-3 {\n margin-left: 1rem !important;\n margin-right: 1rem !important;\n}\n\n.mx-4 {\n margin-left: 1.5rem !important;\n margin-right: 1.5rem !important;\n}\n\n.mx-5 {\n margin-left: 3rem !important;\n margin-right: 3rem !important;\n}\n\n.mx-auto {\n margin-left: auto !important;\n margin-right: auto !important;\n}\n\n.my-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n.my-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n}\n\n.my-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n}\n\n.my-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n}\n\n.my-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n}\n\n.my-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n}\n\n.my-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n}\n\n.mt-0 {\n margin-top: 0 !important;\n}\n\n.mt-1 {\n margin-top: 0.25rem !important;\n}\n\n.mt-2 {\n margin-top: 0.5rem !important;\n}\n\n.mt-3 {\n margin-top: 1rem !important;\n}\n\n.mt-4 {\n margin-top: 1.5rem !important;\n}\n\n.mt-5 {\n margin-top: 3rem !important;\n}\n\n.mt-auto {\n margin-top: auto !important;\n}\n\n.me-0 {\n margin-left: 0 !important;\n}\n\n.me-1 {\n margin-left: 0.25rem !important;\n}\n\n.me-2 {\n margin-left: 0.5rem !important;\n}\n\n.me-3 {\n margin-left: 1rem !important;\n}\n\n.me-4 {\n margin-left: 1.5rem !important;\n}\n\n.me-5 {\n margin-left: 3rem !important;\n}\n\n.me-auto {\n margin-left: auto !important;\n}\n\n.mb-0 {\n margin-bottom: 0 !important;\n}\n\n.mb-1 {\n margin-bottom: 0.25rem !important;\n}\n\n.mb-2 {\n margin-bottom: 0.5rem !important;\n}\n\n.mb-3 {\n margin-bottom: 1rem !important;\n}\n\n.mb-4 {\n margin-bottom: 1.5rem !important;\n}\n\n.mb-5 {\n margin-bottom: 3rem !important;\n}\n\n.mb-auto {\n margin-bottom: auto !important;\n}\n\n.ms-0 {\n margin-right: 0 !important;\n}\n\n.ms-1 {\n margin-right: 0.25rem !important;\n}\n\n.ms-2 {\n margin-right: 0.5rem !important;\n}\n\n.ms-3 {\n margin-right: 1rem !important;\n}\n\n.ms-4 {\n margin-right: 1.5rem !important;\n}\n\n.ms-5 {\n margin-right: 3rem !important;\n}\n\n.ms-auto {\n margin-right: auto !important;\n}\n\n.p-0 {\n padding: 0 !important;\n}\n\n.p-1 {\n padding: 0.25rem !important;\n}\n\n.p-2 {\n padding: 0.5rem !important;\n}\n\n.p-3 {\n padding: 1rem !important;\n}\n\n.p-4 {\n padding: 1.5rem !important;\n}\n\n.p-5 {\n padding: 3rem !important;\n}\n\n.px-0 {\n padding-left: 0 !important;\n padding-right: 0 !important;\n}\n\n.px-1 {\n padding-left: 0.25rem !important;\n padding-right: 0.25rem !important;\n}\n\n.px-2 {\n padding-left: 0.5rem !important;\n padding-right: 0.5rem !important;\n}\n\n.px-3 {\n padding-left: 1rem !important;\n padding-right: 1rem !important;\n}\n\n.px-4 {\n padding-left: 1.5rem !important;\n padding-right: 1.5rem !important;\n}\n\n.px-5 {\n padding-left: 3rem !important;\n padding-right: 3rem !important;\n}\n\n.py-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n}\n\n.py-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n}\n\n.py-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n}\n\n.py-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n}\n\n.py-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n}\n\n.py-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n}\n\n.pt-0 {\n padding-top: 0 !important;\n}\n\n.pt-1 {\n padding-top: 0.25rem !important;\n}\n\n.pt-2 {\n padding-top: 0.5rem !important;\n}\n\n.pt-3 {\n padding-top: 1rem !important;\n}\n\n.pt-4 {\n padding-top: 1.5rem !important;\n}\n\n.pt-5 {\n padding-top: 3rem !important;\n}\n\n.pe-0 {\n padding-left: 0 !important;\n}\n\n.pe-1 {\n padding-left: 0.25rem !important;\n}\n\n.pe-2 {\n padding-left: 0.5rem !important;\n}\n\n.pe-3 {\n padding-left: 1rem !important;\n}\n\n.pe-4 {\n padding-left: 1.5rem !important;\n}\n\n.pe-5 {\n padding-left: 3rem !important;\n}\n\n.pb-0 {\n padding-bottom: 0 !important;\n}\n\n.pb-1 {\n padding-bottom: 0.25rem !important;\n}\n\n.pb-2 {\n padding-bottom: 0.5rem !important;\n}\n\n.pb-3 {\n padding-bottom: 1rem !important;\n}\n\n.pb-4 {\n padding-bottom: 1.5rem !important;\n}\n\n.pb-5 {\n padding-bottom: 3rem !important;\n}\n\n.ps-0 {\n padding-right: 0 !important;\n}\n\n.ps-1 {\n padding-right: 0.25rem !important;\n}\n\n.ps-2 {\n padding-right: 0.5rem !important;\n}\n\n.ps-3 {\n padding-right: 1rem !important;\n}\n\n.ps-4 {\n padding-right: 1.5rem !important;\n}\n\n.ps-5 {\n padding-right: 3rem !important;\n}\n\n@media (min-width: 576px) {\n .d-sm-inline {\n display: inline !important;\n }\n .d-sm-inline-block {\n display: inline-block !important;\n }\n .d-sm-block {\n display: block !important;\n }\n .d-sm-grid {\n display: grid !important;\n }\n .d-sm-inline-grid {\n display: inline-grid !important;\n }\n .d-sm-table {\n display: table !important;\n }\n .d-sm-table-row {\n display: table-row !important;\n }\n .d-sm-table-cell {\n display: table-cell !important;\n }\n .d-sm-flex {\n display: flex !important;\n }\n .d-sm-inline-flex {\n display: inline-flex !important;\n }\n .d-sm-none {\n display: none !important;\n }\n .flex-sm-fill {\n flex: 1 1 auto !important;\n }\n .flex-sm-row {\n flex-direction: row !important;\n }\n .flex-sm-column {\n flex-direction: column !important;\n }\n .flex-sm-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-sm-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-sm-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-sm-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-sm-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-sm-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-sm-wrap {\n flex-wrap: wrap !important;\n }\n .flex-sm-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-sm-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-sm-start {\n justify-content: flex-start !important;\n }\n .justify-content-sm-end {\n justify-content: flex-end !important;\n }\n .justify-content-sm-center {\n justify-content: center !important;\n }\n .justify-content-sm-between {\n justify-content: space-between !important;\n }\n .justify-content-sm-around {\n justify-content: space-around !important;\n }\n .justify-content-sm-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-sm-start {\n align-items: flex-start !important;\n }\n .align-items-sm-end {\n align-items: flex-end !important;\n }\n .align-items-sm-center {\n align-items: center !important;\n }\n .align-items-sm-baseline {\n align-items: baseline !important;\n }\n .align-items-sm-stretch {\n align-items: stretch !important;\n }\n .align-content-sm-start {\n align-content: flex-start !important;\n }\n .align-content-sm-end {\n align-content: flex-end !important;\n }\n .align-content-sm-center {\n align-content: center !important;\n }\n .align-content-sm-between {\n align-content: space-between !important;\n }\n .align-content-sm-around {\n align-content: space-around !important;\n }\n .align-content-sm-stretch {\n align-content: stretch !important;\n }\n .align-self-sm-auto {\n align-self: auto !important;\n }\n .align-self-sm-start {\n align-self: flex-start !important;\n }\n .align-self-sm-end {\n align-self: flex-end !important;\n }\n .align-self-sm-center {\n align-self: center !important;\n }\n .align-self-sm-baseline {\n align-self: baseline !important;\n }\n .align-self-sm-stretch {\n align-self: stretch !important;\n }\n .order-sm-first {\n order: -1 !important;\n }\n .order-sm-0 {\n order: 0 !important;\n }\n .order-sm-1 {\n order: 1 !important;\n }\n .order-sm-2 {\n order: 2 !important;\n }\n .order-sm-3 {\n order: 3 !important;\n }\n .order-sm-4 {\n order: 4 !important;\n }\n .order-sm-5 {\n order: 5 !important;\n }\n .order-sm-last {\n order: 6 !important;\n }\n .m-sm-0 {\n margin: 0 !important;\n }\n .m-sm-1 {\n margin: 0.25rem !important;\n }\n .m-sm-2 {\n margin: 0.5rem !important;\n }\n .m-sm-3 {\n margin: 1rem !important;\n }\n .m-sm-4 {\n margin: 1.5rem !important;\n }\n .m-sm-5 {\n margin: 3rem !important;\n }\n .m-sm-auto {\n margin: auto !important;\n }\n .mx-sm-0 {\n margin-left: 0 !important;\n margin-right: 0 !important;\n }\n .mx-sm-1 {\n margin-left: 0.25rem !important;\n margin-right: 0.25rem !important;\n }\n .mx-sm-2 {\n margin-left: 0.5rem !important;\n margin-right: 0.5rem !important;\n }\n .mx-sm-3 {\n margin-left: 1rem !important;\n margin-right: 1rem !important;\n }\n .mx-sm-4 {\n margin-left: 1.5rem !important;\n margin-right: 1.5rem !important;\n }\n .mx-sm-5 {\n margin-left: 3rem !important;\n margin-right: 3rem !important;\n }\n .mx-sm-auto {\n margin-left: auto !important;\n margin-right: auto !important;\n }\n .my-sm-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-sm-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-sm-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-sm-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-sm-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-sm-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-sm-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-sm-0 {\n margin-top: 0 !important;\n }\n .mt-sm-1 {\n margin-top: 0.25rem !important;\n }\n .mt-sm-2 {\n margin-top: 0.5rem !important;\n }\n .mt-sm-3 {\n margin-top: 1rem !important;\n }\n .mt-sm-4 {\n margin-top: 1.5rem !important;\n }\n .mt-sm-5 {\n margin-top: 3rem !important;\n }\n .mt-sm-auto {\n margin-top: auto !important;\n }\n .me-sm-0 {\n margin-left: 0 !important;\n }\n .me-sm-1 {\n margin-left: 0.25rem !important;\n }\n .me-sm-2 {\n margin-left: 0.5rem !important;\n }\n .me-sm-3 {\n margin-left: 1rem !important;\n }\n .me-sm-4 {\n margin-left: 1.5rem !important;\n }\n .me-sm-5 {\n margin-left: 3rem !important;\n }\n .me-sm-auto {\n margin-left: auto !important;\n }\n .mb-sm-0 {\n margin-bottom: 0 !important;\n }\n .mb-sm-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-sm-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-sm-3 {\n margin-bottom: 1rem !important;\n }\n .mb-sm-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-sm-5 {\n margin-bottom: 3rem !important;\n }\n .mb-sm-auto {\n margin-bottom: auto !important;\n }\n .ms-sm-0 {\n margin-right: 0 !important;\n }\n .ms-sm-1 {\n margin-right: 0.25rem !important;\n }\n .ms-sm-2 {\n margin-right: 0.5rem !important;\n }\n .ms-sm-3 {\n margin-right: 1rem !important;\n }\n .ms-sm-4 {\n margin-right: 1.5rem !important;\n }\n .ms-sm-5 {\n margin-right: 3rem !important;\n }\n .ms-sm-auto {\n margin-right: auto !important;\n }\n .p-sm-0 {\n padding: 0 !important;\n }\n .p-sm-1 {\n padding: 0.25rem !important;\n }\n .p-sm-2 {\n padding: 0.5rem !important;\n }\n .p-sm-3 {\n padding: 1rem !important;\n }\n .p-sm-4 {\n padding: 1.5rem !important;\n }\n .p-sm-5 {\n padding: 3rem !important;\n }\n .px-sm-0 {\n padding-left: 0 !important;\n padding-right: 0 !important;\n }\n .px-sm-1 {\n padding-left: 0.25rem !important;\n padding-right: 0.25rem !important;\n }\n .px-sm-2 {\n padding-left: 0.5rem !important;\n padding-right: 0.5rem !important;\n }\n .px-sm-3 {\n padding-left: 1rem !important;\n padding-right: 1rem !important;\n }\n .px-sm-4 {\n padding-left: 1.5rem !important;\n padding-right: 1.5rem !important;\n }\n .px-sm-5 {\n padding-left: 3rem !important;\n padding-right: 3rem !important;\n }\n .py-sm-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-sm-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-sm-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-sm-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-sm-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-sm-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-sm-0 {\n padding-top: 0 !important;\n }\n .pt-sm-1 {\n padding-top: 0.25rem !important;\n }\n .pt-sm-2 {\n padding-top: 0.5rem !important;\n }\n .pt-sm-3 {\n padding-top: 1rem !important;\n }\n .pt-sm-4 {\n padding-top: 1.5rem !important;\n }\n .pt-sm-5 {\n padding-top: 3rem !important;\n }\n .pe-sm-0 {\n padding-left: 0 !important;\n }\n .pe-sm-1 {\n padding-left: 0.25rem !important;\n }\n .pe-sm-2 {\n padding-left: 0.5rem !important;\n }\n .pe-sm-3 {\n padding-left: 1rem !important;\n }\n .pe-sm-4 {\n padding-left: 1.5rem !important;\n }\n .pe-sm-5 {\n padding-left: 3rem !important;\n }\n .pb-sm-0 {\n padding-bottom: 0 !important;\n }\n .pb-sm-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-sm-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-sm-3 {\n padding-bottom: 1rem !important;\n }\n .pb-sm-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-sm-5 {\n padding-bottom: 3rem !important;\n }\n .ps-sm-0 {\n padding-right: 0 !important;\n }\n .ps-sm-1 {\n padding-right: 0.25rem !important;\n }\n .ps-sm-2 {\n padding-right: 0.5rem !important;\n }\n .ps-sm-3 {\n padding-right: 1rem !important;\n }\n .ps-sm-4 {\n padding-right: 1.5rem !important;\n }\n .ps-sm-5 {\n padding-right: 3rem !important;\n }\n}\n@media (min-width: 768px) {\n .d-md-inline {\n display: inline !important;\n }\n .d-md-inline-block {\n display: inline-block !important;\n }\n .d-md-block {\n display: block !important;\n }\n .d-md-grid {\n display: grid !important;\n }\n .d-md-inline-grid {\n display: inline-grid !important;\n }\n .d-md-table {\n display: table !important;\n }\n .d-md-table-row {\n display: table-row !important;\n }\n .d-md-table-cell {\n display: table-cell !important;\n }\n .d-md-flex {\n display: flex !important;\n }\n .d-md-inline-flex {\n display: inline-flex !important;\n }\n .d-md-none {\n display: none !important;\n }\n .flex-md-fill {\n flex: 1 1 auto !important;\n }\n .flex-md-row {\n flex-direction: row !important;\n }\n .flex-md-column {\n flex-direction: column !important;\n }\n .flex-md-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-md-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-md-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-md-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-md-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-md-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-md-wrap {\n flex-wrap: wrap !important;\n }\n .flex-md-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-md-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-md-start {\n justify-content: flex-start !important;\n }\n .justify-content-md-end {\n justify-content: flex-end !important;\n }\n .justify-content-md-center {\n justify-content: center !important;\n }\n .justify-content-md-between {\n justify-content: space-between !important;\n }\n .justify-content-md-around {\n justify-content: space-around !important;\n }\n .justify-content-md-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-md-start {\n align-items: flex-start !important;\n }\n .align-items-md-end {\n align-items: flex-end !important;\n }\n .align-items-md-center {\n align-items: center !important;\n }\n .align-items-md-baseline {\n align-items: baseline !important;\n }\n .align-items-md-stretch {\n align-items: stretch !important;\n }\n .align-content-md-start {\n align-content: flex-start !important;\n }\n .align-content-md-end {\n align-content: flex-end !important;\n }\n .align-content-md-center {\n align-content: center !important;\n }\n .align-content-md-between {\n align-content: space-between !important;\n }\n .align-content-md-around {\n align-content: space-around !important;\n }\n .align-content-md-stretch {\n align-content: stretch !important;\n }\n .align-self-md-auto {\n align-self: auto !important;\n }\n .align-self-md-start {\n align-self: flex-start !important;\n }\n .align-self-md-end {\n align-self: flex-end !important;\n }\n .align-self-md-center {\n align-self: center !important;\n }\n .align-self-md-baseline {\n align-self: baseline !important;\n }\n .align-self-md-stretch {\n align-self: stretch !important;\n }\n .order-md-first {\n order: -1 !important;\n }\n .order-md-0 {\n order: 0 !important;\n }\n .order-md-1 {\n order: 1 !important;\n }\n .order-md-2 {\n order: 2 !important;\n }\n .order-md-3 {\n order: 3 !important;\n }\n .order-md-4 {\n order: 4 !important;\n }\n .order-md-5 {\n order: 5 !important;\n }\n .order-md-last {\n order: 6 !important;\n }\n .m-md-0 {\n margin: 0 !important;\n }\n .m-md-1 {\n margin: 0.25rem !important;\n }\n .m-md-2 {\n margin: 0.5rem !important;\n }\n .m-md-3 {\n margin: 1rem !important;\n }\n .m-md-4 {\n margin: 1.5rem !important;\n }\n .m-md-5 {\n margin: 3rem !important;\n }\n .m-md-auto {\n margin: auto !important;\n }\n .mx-md-0 {\n margin-left: 0 !important;\n margin-right: 0 !important;\n }\n .mx-md-1 {\n margin-left: 0.25rem !important;\n margin-right: 0.25rem !important;\n }\n .mx-md-2 {\n margin-left: 0.5rem !important;\n margin-right: 0.5rem !important;\n }\n .mx-md-3 {\n margin-left: 1rem !important;\n margin-right: 1rem !important;\n }\n .mx-md-4 {\n margin-left: 1.5rem !important;\n margin-right: 1.5rem !important;\n }\n .mx-md-5 {\n margin-left: 3rem !important;\n margin-right: 3rem !important;\n }\n .mx-md-auto {\n margin-left: auto !important;\n margin-right: auto !important;\n }\n .my-md-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-md-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-md-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-md-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-md-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-md-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-md-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-md-0 {\n margin-top: 0 !important;\n }\n .mt-md-1 {\n margin-top: 0.25rem !important;\n }\n .mt-md-2 {\n margin-top: 0.5rem !important;\n }\n .mt-md-3 {\n margin-top: 1rem !important;\n }\n .mt-md-4 {\n margin-top: 1.5rem !important;\n }\n .mt-md-5 {\n margin-top: 3rem !important;\n }\n .mt-md-auto {\n margin-top: auto !important;\n }\n .me-md-0 {\n margin-left: 0 !important;\n }\n .me-md-1 {\n margin-left: 0.25rem !important;\n }\n .me-md-2 {\n margin-left: 0.5rem !important;\n }\n .me-md-3 {\n margin-left: 1rem !important;\n }\n .me-md-4 {\n margin-left: 1.5rem !important;\n }\n .me-md-5 {\n margin-left: 3rem !important;\n }\n .me-md-auto {\n margin-left: auto !important;\n }\n .mb-md-0 {\n margin-bottom: 0 !important;\n }\n .mb-md-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-md-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-md-3 {\n margin-bottom: 1rem !important;\n }\n .mb-md-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-md-5 {\n margin-bottom: 3rem !important;\n }\n .mb-md-auto {\n margin-bottom: auto !important;\n }\n .ms-md-0 {\n margin-right: 0 !important;\n }\n .ms-md-1 {\n margin-right: 0.25rem !important;\n }\n .ms-md-2 {\n margin-right: 0.5rem !important;\n }\n .ms-md-3 {\n margin-right: 1rem !important;\n }\n .ms-md-4 {\n margin-right: 1.5rem !important;\n }\n .ms-md-5 {\n margin-right: 3rem !important;\n }\n .ms-md-auto {\n margin-right: auto !important;\n }\n .p-md-0 {\n padding: 0 !important;\n }\n .p-md-1 {\n padding: 0.25rem !important;\n }\n .p-md-2 {\n padding: 0.5rem !important;\n }\n .p-md-3 {\n padding: 1rem !important;\n }\n .p-md-4 {\n padding: 1.5rem !important;\n }\n .p-md-5 {\n padding: 3rem !important;\n }\n .px-md-0 {\n padding-left: 0 !important;\n padding-right: 0 !important;\n }\n .px-md-1 {\n padding-left: 0.25rem !important;\n padding-right: 0.25rem !important;\n }\n .px-md-2 {\n padding-left: 0.5rem !important;\n padding-right: 0.5rem !important;\n }\n .px-md-3 {\n padding-left: 1rem !important;\n padding-right: 1rem !important;\n }\n .px-md-4 {\n padding-left: 1.5rem !important;\n padding-right: 1.5rem !important;\n }\n .px-md-5 {\n padding-left: 3rem !important;\n padding-right: 3rem !important;\n }\n .py-md-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-md-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-md-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-md-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-md-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-md-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-md-0 {\n padding-top: 0 !important;\n }\n .pt-md-1 {\n padding-top: 0.25rem !important;\n }\n .pt-md-2 {\n padding-top: 0.5rem !important;\n }\n .pt-md-3 {\n padding-top: 1rem !important;\n }\n .pt-md-4 {\n padding-top: 1.5rem !important;\n }\n .pt-md-5 {\n padding-top: 3rem !important;\n }\n .pe-md-0 {\n padding-left: 0 !important;\n }\n .pe-md-1 {\n padding-left: 0.25rem !important;\n }\n .pe-md-2 {\n padding-left: 0.5rem !important;\n }\n .pe-md-3 {\n padding-left: 1rem !important;\n }\n .pe-md-4 {\n padding-left: 1.5rem !important;\n }\n .pe-md-5 {\n padding-left: 3rem !important;\n }\n .pb-md-0 {\n padding-bottom: 0 !important;\n }\n .pb-md-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-md-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-md-3 {\n padding-bottom: 1rem !important;\n }\n .pb-md-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-md-5 {\n padding-bottom: 3rem !important;\n }\n .ps-md-0 {\n padding-right: 0 !important;\n }\n .ps-md-1 {\n padding-right: 0.25rem !important;\n }\n .ps-md-2 {\n padding-right: 0.5rem !important;\n }\n .ps-md-3 {\n padding-right: 1rem !important;\n }\n .ps-md-4 {\n padding-right: 1.5rem !important;\n }\n .ps-md-5 {\n padding-right: 3rem !important;\n }\n}\n@media (min-width: 992px) {\n .d-lg-inline {\n display: inline !important;\n }\n .d-lg-inline-block {\n display: inline-block !important;\n }\n .d-lg-block {\n display: block !important;\n }\n .d-lg-grid {\n display: grid !important;\n }\n .d-lg-inline-grid {\n display: inline-grid !important;\n }\n .d-lg-table {\n display: table !important;\n }\n .d-lg-table-row {\n display: table-row !important;\n }\n .d-lg-table-cell {\n display: table-cell !important;\n }\n .d-lg-flex {\n display: flex !important;\n }\n .d-lg-inline-flex {\n display: inline-flex !important;\n }\n .d-lg-none {\n display: none !important;\n }\n .flex-lg-fill {\n flex: 1 1 auto !important;\n }\n .flex-lg-row {\n flex-direction: row !important;\n }\n .flex-lg-column {\n flex-direction: column !important;\n }\n .flex-lg-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-lg-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-lg-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-lg-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-lg-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-lg-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-lg-wrap {\n flex-wrap: wrap !important;\n }\n .flex-lg-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-lg-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-lg-start {\n justify-content: flex-start !important;\n }\n .justify-content-lg-end {\n justify-content: flex-end !important;\n }\n .justify-content-lg-center {\n justify-content: center !important;\n }\n .justify-content-lg-between {\n justify-content: space-between !important;\n }\n .justify-content-lg-around {\n justify-content: space-around !important;\n }\n .justify-content-lg-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-lg-start {\n align-items: flex-start !important;\n }\n .align-items-lg-end {\n align-items: flex-end !important;\n }\n .align-items-lg-center {\n align-items: center !important;\n }\n .align-items-lg-baseline {\n align-items: baseline !important;\n }\n .align-items-lg-stretch {\n align-items: stretch !important;\n }\n .align-content-lg-start {\n align-content: flex-start !important;\n }\n .align-content-lg-end {\n align-content: flex-end !important;\n }\n .align-content-lg-center {\n align-content: center !important;\n }\n .align-content-lg-between {\n align-content: space-between !important;\n }\n .align-content-lg-around {\n align-content: space-around !important;\n }\n .align-content-lg-stretch {\n align-content: stretch !important;\n }\n .align-self-lg-auto {\n align-self: auto !important;\n }\n .align-self-lg-start {\n align-self: flex-start !important;\n }\n .align-self-lg-end {\n align-self: flex-end !important;\n }\n .align-self-lg-center {\n align-self: center !important;\n }\n .align-self-lg-baseline {\n align-self: baseline !important;\n }\n .align-self-lg-stretch {\n align-self: stretch !important;\n }\n .order-lg-first {\n order: -1 !important;\n }\n .order-lg-0 {\n order: 0 !important;\n }\n .order-lg-1 {\n order: 1 !important;\n }\n .order-lg-2 {\n order: 2 !important;\n }\n .order-lg-3 {\n order: 3 !important;\n }\n .order-lg-4 {\n order: 4 !important;\n }\n .order-lg-5 {\n order: 5 !important;\n }\n .order-lg-last {\n order: 6 !important;\n }\n .m-lg-0 {\n margin: 0 !important;\n }\n .m-lg-1 {\n margin: 0.25rem !important;\n }\n .m-lg-2 {\n margin: 0.5rem !important;\n }\n .m-lg-3 {\n margin: 1rem !important;\n }\n .m-lg-4 {\n margin: 1.5rem !important;\n }\n .m-lg-5 {\n margin: 3rem !important;\n }\n .m-lg-auto {\n margin: auto !important;\n }\n .mx-lg-0 {\n margin-left: 0 !important;\n margin-right: 0 !important;\n }\n .mx-lg-1 {\n margin-left: 0.25rem !important;\n margin-right: 0.25rem !important;\n }\n .mx-lg-2 {\n margin-left: 0.5rem !important;\n margin-right: 0.5rem !important;\n }\n .mx-lg-3 {\n margin-left: 1rem !important;\n margin-right: 1rem !important;\n }\n .mx-lg-4 {\n margin-left: 1.5rem !important;\n margin-right: 1.5rem !important;\n }\n .mx-lg-5 {\n margin-left: 3rem !important;\n margin-right: 3rem !important;\n }\n .mx-lg-auto {\n margin-left: auto !important;\n margin-right: auto !important;\n }\n .my-lg-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-lg-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-lg-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-lg-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-lg-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-lg-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-lg-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-lg-0 {\n margin-top: 0 !important;\n }\n .mt-lg-1 {\n margin-top: 0.25rem !important;\n }\n .mt-lg-2 {\n margin-top: 0.5rem !important;\n }\n .mt-lg-3 {\n margin-top: 1rem !important;\n }\n .mt-lg-4 {\n margin-top: 1.5rem !important;\n }\n .mt-lg-5 {\n margin-top: 3rem !important;\n }\n .mt-lg-auto {\n margin-top: auto !important;\n }\n .me-lg-0 {\n margin-left: 0 !important;\n }\n .me-lg-1 {\n margin-left: 0.25rem !important;\n }\n .me-lg-2 {\n margin-left: 0.5rem !important;\n }\n .me-lg-3 {\n margin-left: 1rem !important;\n }\n .me-lg-4 {\n margin-left: 1.5rem !important;\n }\n .me-lg-5 {\n margin-left: 3rem !important;\n }\n .me-lg-auto {\n margin-left: auto !important;\n }\n .mb-lg-0 {\n margin-bottom: 0 !important;\n }\n .mb-lg-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-lg-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-lg-3 {\n margin-bottom: 1rem !important;\n }\n .mb-lg-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-lg-5 {\n margin-bottom: 3rem !important;\n }\n .mb-lg-auto {\n margin-bottom: auto !important;\n }\n .ms-lg-0 {\n margin-right: 0 !important;\n }\n .ms-lg-1 {\n margin-right: 0.25rem !important;\n }\n .ms-lg-2 {\n margin-right: 0.5rem !important;\n }\n .ms-lg-3 {\n margin-right: 1rem !important;\n }\n .ms-lg-4 {\n margin-right: 1.5rem !important;\n }\n .ms-lg-5 {\n margin-right: 3rem !important;\n }\n .ms-lg-auto {\n margin-right: auto !important;\n }\n .p-lg-0 {\n padding: 0 !important;\n }\n .p-lg-1 {\n padding: 0.25rem !important;\n }\n .p-lg-2 {\n padding: 0.5rem !important;\n }\n .p-lg-3 {\n padding: 1rem !important;\n }\n .p-lg-4 {\n padding: 1.5rem !important;\n }\n .p-lg-5 {\n padding: 3rem !important;\n }\n .px-lg-0 {\n padding-left: 0 !important;\n padding-right: 0 !important;\n }\n .px-lg-1 {\n padding-left: 0.25rem !important;\n padding-right: 0.25rem !important;\n }\n .px-lg-2 {\n padding-left: 0.5rem !important;\n padding-right: 0.5rem !important;\n }\n .px-lg-3 {\n padding-left: 1rem !important;\n padding-right: 1rem !important;\n }\n .px-lg-4 {\n padding-left: 1.5rem !important;\n padding-right: 1.5rem !important;\n }\n .px-lg-5 {\n padding-left: 3rem !important;\n padding-right: 3rem !important;\n }\n .py-lg-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-lg-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-lg-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-lg-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-lg-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-lg-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-lg-0 {\n padding-top: 0 !important;\n }\n .pt-lg-1 {\n padding-top: 0.25rem !important;\n }\n .pt-lg-2 {\n padding-top: 0.5rem !important;\n }\n .pt-lg-3 {\n padding-top: 1rem !important;\n }\n .pt-lg-4 {\n padding-top: 1.5rem !important;\n }\n .pt-lg-5 {\n padding-top: 3rem !important;\n }\n .pe-lg-0 {\n padding-left: 0 !important;\n }\n .pe-lg-1 {\n padding-left: 0.25rem !important;\n }\n .pe-lg-2 {\n padding-left: 0.5rem !important;\n }\n .pe-lg-3 {\n padding-left: 1rem !important;\n }\n .pe-lg-4 {\n padding-left: 1.5rem !important;\n }\n .pe-lg-5 {\n padding-left: 3rem !important;\n }\n .pb-lg-0 {\n padding-bottom: 0 !important;\n }\n .pb-lg-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-lg-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-lg-3 {\n padding-bottom: 1rem !important;\n }\n .pb-lg-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-lg-5 {\n padding-bottom: 3rem !important;\n }\n .ps-lg-0 {\n padding-right: 0 !important;\n }\n .ps-lg-1 {\n padding-right: 0.25rem !important;\n }\n .ps-lg-2 {\n padding-right: 0.5rem !important;\n }\n .ps-lg-3 {\n padding-right: 1rem !important;\n }\n .ps-lg-4 {\n padding-right: 1.5rem !important;\n }\n .ps-lg-5 {\n padding-right: 3rem !important;\n }\n}\n@media (min-width: 1200px) {\n .d-xl-inline {\n display: inline !important;\n }\n .d-xl-inline-block {\n display: inline-block !important;\n }\n .d-xl-block {\n display: block !important;\n }\n .d-xl-grid {\n display: grid !important;\n }\n .d-xl-inline-grid {\n display: inline-grid !important;\n }\n .d-xl-table {\n display: table !important;\n }\n .d-xl-table-row {\n display: table-row !important;\n }\n .d-xl-table-cell {\n display: table-cell !important;\n }\n .d-xl-flex {\n display: flex !important;\n }\n .d-xl-inline-flex {\n display: inline-flex !important;\n }\n .d-xl-none {\n display: none !important;\n }\n .flex-xl-fill {\n flex: 1 1 auto !important;\n }\n .flex-xl-row {\n flex-direction: row !important;\n }\n .flex-xl-column {\n flex-direction: column !important;\n }\n .flex-xl-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-xl-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-xl-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-xl-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-xl-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-xl-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-xl-wrap {\n flex-wrap: wrap !important;\n }\n .flex-xl-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-xl-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-xl-start {\n justify-content: flex-start !important;\n }\n .justify-content-xl-end {\n justify-content: flex-end !important;\n }\n .justify-content-xl-center {\n justify-content: center !important;\n }\n .justify-content-xl-between {\n justify-content: space-between !important;\n }\n .justify-content-xl-around {\n justify-content: space-around !important;\n }\n .justify-content-xl-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-xl-start {\n align-items: flex-start !important;\n }\n .align-items-xl-end {\n align-items: flex-end !important;\n }\n .align-items-xl-center {\n align-items: center !important;\n }\n .align-items-xl-baseline {\n align-items: baseline !important;\n }\n .align-items-xl-stretch {\n align-items: stretch !important;\n }\n .align-content-xl-start {\n align-content: flex-start !important;\n }\n .align-content-xl-end {\n align-content: flex-end !important;\n }\n .align-content-xl-center {\n align-content: center !important;\n }\n .align-content-xl-between {\n align-content: space-between !important;\n }\n .align-content-xl-around {\n align-content: space-around !important;\n }\n .align-content-xl-stretch {\n align-content: stretch !important;\n }\n .align-self-xl-auto {\n align-self: auto !important;\n }\n .align-self-xl-start {\n align-self: flex-start !important;\n }\n .align-self-xl-end {\n align-self: flex-end !important;\n }\n .align-self-xl-center {\n align-self: center !important;\n }\n .align-self-xl-baseline {\n align-self: baseline !important;\n }\n .align-self-xl-stretch {\n align-self: stretch !important;\n }\n .order-xl-first {\n order: -1 !important;\n }\n .order-xl-0 {\n order: 0 !important;\n }\n .order-xl-1 {\n order: 1 !important;\n }\n .order-xl-2 {\n order: 2 !important;\n }\n .order-xl-3 {\n order: 3 !important;\n }\n .order-xl-4 {\n order: 4 !important;\n }\n .order-xl-5 {\n order: 5 !important;\n }\n .order-xl-last {\n order: 6 !important;\n }\n .m-xl-0 {\n margin: 0 !important;\n }\n .m-xl-1 {\n margin: 0.25rem !important;\n }\n .m-xl-2 {\n margin: 0.5rem !important;\n }\n .m-xl-3 {\n margin: 1rem !important;\n }\n .m-xl-4 {\n margin: 1.5rem !important;\n }\n .m-xl-5 {\n margin: 3rem !important;\n }\n .m-xl-auto {\n margin: auto !important;\n }\n .mx-xl-0 {\n margin-left: 0 !important;\n margin-right: 0 !important;\n }\n .mx-xl-1 {\n margin-left: 0.25rem !important;\n margin-right: 0.25rem !important;\n }\n .mx-xl-2 {\n margin-left: 0.5rem !important;\n margin-right: 0.5rem !important;\n }\n .mx-xl-3 {\n margin-left: 1rem !important;\n margin-right: 1rem !important;\n }\n .mx-xl-4 {\n margin-left: 1.5rem !important;\n margin-right: 1.5rem !important;\n }\n .mx-xl-5 {\n margin-left: 3rem !important;\n margin-right: 3rem !important;\n }\n .mx-xl-auto {\n margin-left: auto !important;\n margin-right: auto !important;\n }\n .my-xl-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-xl-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-xl-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-xl-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-xl-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-xl-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-xl-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-xl-0 {\n margin-top: 0 !important;\n }\n .mt-xl-1 {\n margin-top: 0.25rem !important;\n }\n .mt-xl-2 {\n margin-top: 0.5rem !important;\n }\n .mt-xl-3 {\n margin-top: 1rem !important;\n }\n .mt-xl-4 {\n margin-top: 1.5rem !important;\n }\n .mt-xl-5 {\n margin-top: 3rem !important;\n }\n .mt-xl-auto {\n margin-top: auto !important;\n }\n .me-xl-0 {\n margin-left: 0 !important;\n }\n .me-xl-1 {\n margin-left: 0.25rem !important;\n }\n .me-xl-2 {\n margin-left: 0.5rem !important;\n }\n .me-xl-3 {\n margin-left: 1rem !important;\n }\n .me-xl-4 {\n margin-left: 1.5rem !important;\n }\n .me-xl-5 {\n margin-left: 3rem !important;\n }\n .me-xl-auto {\n margin-left: auto !important;\n }\n .mb-xl-0 {\n margin-bottom: 0 !important;\n }\n .mb-xl-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-xl-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-xl-3 {\n margin-bottom: 1rem !important;\n }\n .mb-xl-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-xl-5 {\n margin-bottom: 3rem !important;\n }\n .mb-xl-auto {\n margin-bottom: auto !important;\n }\n .ms-xl-0 {\n margin-right: 0 !important;\n }\n .ms-xl-1 {\n margin-right: 0.25rem !important;\n }\n .ms-xl-2 {\n margin-right: 0.5rem !important;\n }\n .ms-xl-3 {\n margin-right: 1rem !important;\n }\n .ms-xl-4 {\n margin-right: 1.5rem !important;\n }\n .ms-xl-5 {\n margin-right: 3rem !important;\n }\n .ms-xl-auto {\n margin-right: auto !important;\n }\n .p-xl-0 {\n padding: 0 !important;\n }\n .p-xl-1 {\n padding: 0.25rem !important;\n }\n .p-xl-2 {\n padding: 0.5rem !important;\n }\n .p-xl-3 {\n padding: 1rem !important;\n }\n .p-xl-4 {\n padding: 1.5rem !important;\n }\n .p-xl-5 {\n padding: 3rem !important;\n }\n .px-xl-0 {\n padding-left: 0 !important;\n padding-right: 0 !important;\n }\n .px-xl-1 {\n padding-left: 0.25rem !important;\n padding-right: 0.25rem !important;\n }\n .px-xl-2 {\n padding-left: 0.5rem !important;\n padding-right: 0.5rem !important;\n }\n .px-xl-3 {\n padding-left: 1rem !important;\n padding-right: 1rem !important;\n }\n .px-xl-4 {\n padding-left: 1.5rem !important;\n padding-right: 1.5rem !important;\n }\n .px-xl-5 {\n padding-left: 3rem !important;\n padding-right: 3rem !important;\n }\n .py-xl-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-xl-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-xl-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-xl-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-xl-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-xl-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-xl-0 {\n padding-top: 0 !important;\n }\n .pt-xl-1 {\n padding-top: 0.25rem !important;\n }\n .pt-xl-2 {\n padding-top: 0.5rem !important;\n }\n .pt-xl-3 {\n padding-top: 1rem !important;\n }\n .pt-xl-4 {\n padding-top: 1.5rem !important;\n }\n .pt-xl-5 {\n padding-top: 3rem !important;\n }\n .pe-xl-0 {\n padding-left: 0 !important;\n }\n .pe-xl-1 {\n padding-left: 0.25rem !important;\n }\n .pe-xl-2 {\n padding-left: 0.5rem !important;\n }\n .pe-xl-3 {\n padding-left: 1rem !important;\n }\n .pe-xl-4 {\n padding-left: 1.5rem !important;\n }\n .pe-xl-5 {\n padding-left: 3rem !important;\n }\n .pb-xl-0 {\n padding-bottom: 0 !important;\n }\n .pb-xl-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-xl-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-xl-3 {\n padding-bottom: 1rem !important;\n }\n .pb-xl-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-xl-5 {\n padding-bottom: 3rem !important;\n }\n .ps-xl-0 {\n padding-right: 0 !important;\n }\n .ps-xl-1 {\n padding-right: 0.25rem !important;\n }\n .ps-xl-2 {\n padding-right: 0.5rem !important;\n }\n .ps-xl-3 {\n padding-right: 1rem !important;\n }\n .ps-xl-4 {\n padding-right: 1.5rem !important;\n }\n .ps-xl-5 {\n padding-right: 3rem !important;\n }\n}\n@media (min-width: 1400px) {\n .d-xxl-inline {\n display: inline !important;\n }\n .d-xxl-inline-block {\n display: inline-block !important;\n }\n .d-xxl-block {\n display: block !important;\n }\n .d-xxl-grid {\n display: grid !important;\n }\n .d-xxl-inline-grid {\n display: inline-grid !important;\n }\n .d-xxl-table {\n display: table !important;\n }\n .d-xxl-table-row {\n display: table-row !important;\n }\n .d-xxl-table-cell {\n display: table-cell !important;\n }\n .d-xxl-flex {\n display: flex !important;\n }\n .d-xxl-inline-flex {\n display: inline-flex !important;\n }\n .d-xxl-none {\n display: none !important;\n }\n .flex-xxl-fill {\n flex: 1 1 auto !important;\n }\n .flex-xxl-row {\n flex-direction: row !important;\n }\n .flex-xxl-column {\n flex-direction: column !important;\n }\n .flex-xxl-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-xxl-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-xxl-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-xxl-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-xxl-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-xxl-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-xxl-wrap {\n flex-wrap: wrap !important;\n }\n .flex-xxl-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-xxl-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-xxl-start {\n justify-content: flex-start !important;\n }\n .justify-content-xxl-end {\n justify-content: flex-end !important;\n }\n .justify-content-xxl-center {\n justify-content: center !important;\n }\n .justify-content-xxl-between {\n justify-content: space-between !important;\n }\n .justify-content-xxl-around {\n justify-content: space-around !important;\n }\n .justify-content-xxl-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-xxl-start {\n align-items: flex-start !important;\n }\n .align-items-xxl-end {\n align-items: flex-end !important;\n }\n .align-items-xxl-center {\n align-items: center !important;\n }\n .align-items-xxl-baseline {\n align-items: baseline !important;\n }\n .align-items-xxl-stretch {\n align-items: stretch !important;\n }\n .align-content-xxl-start {\n align-content: flex-start !important;\n }\n .align-content-xxl-end {\n align-content: flex-end !important;\n }\n .align-content-xxl-center {\n align-content: center !important;\n }\n .align-content-xxl-between {\n align-content: space-between !important;\n }\n .align-content-xxl-around {\n align-content: space-around !important;\n }\n .align-content-xxl-stretch {\n align-content: stretch !important;\n }\n .align-self-xxl-auto {\n align-self: auto !important;\n }\n .align-self-xxl-start {\n align-self: flex-start !important;\n }\n .align-self-xxl-end {\n align-self: flex-end !important;\n }\n .align-self-xxl-center {\n align-self: center !important;\n }\n .align-self-xxl-baseline {\n align-self: baseline !important;\n }\n .align-self-xxl-stretch {\n align-self: stretch !important;\n }\n .order-xxl-first {\n order: -1 !important;\n }\n .order-xxl-0 {\n order: 0 !important;\n }\n .order-xxl-1 {\n order: 1 !important;\n }\n .order-xxl-2 {\n order: 2 !important;\n }\n .order-xxl-3 {\n order: 3 !important;\n }\n .order-xxl-4 {\n order: 4 !important;\n }\n .order-xxl-5 {\n order: 5 !important;\n }\n .order-xxl-last {\n order: 6 !important;\n }\n .m-xxl-0 {\n margin: 0 !important;\n }\n .m-xxl-1 {\n margin: 0.25rem !important;\n }\n .m-xxl-2 {\n margin: 0.5rem !important;\n }\n .m-xxl-3 {\n margin: 1rem !important;\n }\n .m-xxl-4 {\n margin: 1.5rem !important;\n }\n .m-xxl-5 {\n margin: 3rem !important;\n }\n .m-xxl-auto {\n margin: auto !important;\n }\n .mx-xxl-0 {\n margin-left: 0 !important;\n margin-right: 0 !important;\n }\n .mx-xxl-1 {\n margin-left: 0.25rem !important;\n margin-right: 0.25rem !important;\n }\n .mx-xxl-2 {\n margin-left: 0.5rem !important;\n margin-right: 0.5rem !important;\n }\n .mx-xxl-3 {\n margin-left: 1rem !important;\n margin-right: 1rem !important;\n }\n .mx-xxl-4 {\n margin-left: 1.5rem !important;\n margin-right: 1.5rem !important;\n }\n .mx-xxl-5 {\n margin-left: 3rem !important;\n margin-right: 3rem !important;\n }\n .mx-xxl-auto {\n margin-left: auto !important;\n margin-right: auto !important;\n }\n .my-xxl-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-xxl-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-xxl-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-xxl-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-xxl-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-xxl-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-xxl-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-xxl-0 {\n margin-top: 0 !important;\n }\n .mt-xxl-1 {\n margin-top: 0.25rem !important;\n }\n .mt-xxl-2 {\n margin-top: 0.5rem !important;\n }\n .mt-xxl-3 {\n margin-top: 1rem !important;\n }\n .mt-xxl-4 {\n margin-top: 1.5rem !important;\n }\n .mt-xxl-5 {\n margin-top: 3rem !important;\n }\n .mt-xxl-auto {\n margin-top: auto !important;\n }\n .me-xxl-0 {\n margin-left: 0 !important;\n }\n .me-xxl-1 {\n margin-left: 0.25rem !important;\n }\n .me-xxl-2 {\n margin-left: 0.5rem !important;\n }\n .me-xxl-3 {\n margin-left: 1rem !important;\n }\n .me-xxl-4 {\n margin-left: 1.5rem !important;\n }\n .me-xxl-5 {\n margin-left: 3rem !important;\n }\n .me-xxl-auto {\n margin-left: auto !important;\n }\n .mb-xxl-0 {\n margin-bottom: 0 !important;\n }\n .mb-xxl-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-xxl-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-xxl-3 {\n margin-bottom: 1rem !important;\n }\n .mb-xxl-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-xxl-5 {\n margin-bottom: 3rem !important;\n }\n .mb-xxl-auto {\n margin-bottom: auto !important;\n }\n .ms-xxl-0 {\n margin-right: 0 !important;\n }\n .ms-xxl-1 {\n margin-right: 0.25rem !important;\n }\n .ms-xxl-2 {\n margin-right: 0.5rem !important;\n }\n .ms-xxl-3 {\n margin-right: 1rem !important;\n }\n .ms-xxl-4 {\n margin-right: 1.5rem !important;\n }\n .ms-xxl-5 {\n margin-right: 3rem !important;\n }\n .ms-xxl-auto {\n margin-right: auto !important;\n }\n .p-xxl-0 {\n padding: 0 !important;\n }\n .p-xxl-1 {\n padding: 0.25rem !important;\n }\n .p-xxl-2 {\n padding: 0.5rem !important;\n }\n .p-xxl-3 {\n padding: 1rem !important;\n }\n .p-xxl-4 {\n padding: 1.5rem !important;\n }\n .p-xxl-5 {\n padding: 3rem !important;\n }\n .px-xxl-0 {\n padding-left: 0 !important;\n padding-right: 0 !important;\n }\n .px-xxl-1 {\n padding-left: 0.25rem !important;\n padding-right: 0.25rem !important;\n }\n .px-xxl-2 {\n padding-left: 0.5rem !important;\n padding-right: 0.5rem !important;\n }\n .px-xxl-3 {\n padding-left: 1rem !important;\n padding-right: 1rem !important;\n }\n .px-xxl-4 {\n padding-left: 1.5rem !important;\n padding-right: 1.5rem !important;\n }\n .px-xxl-5 {\n padding-left: 3rem !important;\n padding-right: 3rem !important;\n }\n .py-xxl-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-xxl-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-xxl-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-xxl-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-xxl-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-xxl-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-xxl-0 {\n padding-top: 0 !important;\n }\n .pt-xxl-1 {\n padding-top: 0.25rem !important;\n }\n .pt-xxl-2 {\n padding-top: 0.5rem !important;\n }\n .pt-xxl-3 {\n padding-top: 1rem !important;\n }\n .pt-xxl-4 {\n padding-top: 1.5rem !important;\n }\n .pt-xxl-5 {\n padding-top: 3rem !important;\n }\n .pe-xxl-0 {\n padding-left: 0 !important;\n }\n .pe-xxl-1 {\n padding-left: 0.25rem !important;\n }\n .pe-xxl-2 {\n padding-left: 0.5rem !important;\n }\n .pe-xxl-3 {\n padding-left: 1rem !important;\n }\n .pe-xxl-4 {\n padding-left: 1.5rem !important;\n }\n .pe-xxl-5 {\n padding-left: 3rem !important;\n }\n .pb-xxl-0 {\n padding-bottom: 0 !important;\n }\n .pb-xxl-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-xxl-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-xxl-3 {\n padding-bottom: 1rem !important;\n }\n .pb-xxl-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-xxl-5 {\n padding-bottom: 3rem !important;\n }\n .ps-xxl-0 {\n padding-right: 0 !important;\n }\n .ps-xxl-1 {\n padding-right: 0.25rem !important;\n }\n .ps-xxl-2 {\n padding-right: 0.5rem !important;\n }\n .ps-xxl-3 {\n padding-right: 1rem !important;\n }\n .ps-xxl-4 {\n padding-right: 1.5rem !important;\n }\n .ps-xxl-5 {\n padding-right: 3rem !important;\n }\n}\n@media print {\n .d-print-inline {\n display: inline !important;\n }\n .d-print-inline-block {\n display: inline-block !important;\n }\n .d-print-block {\n display: block !important;\n }\n .d-print-grid {\n display: grid !important;\n }\n .d-print-inline-grid {\n display: inline-grid !important;\n }\n .d-print-table {\n display: table !important;\n }\n .d-print-table-row {\n display: table-row !important;\n }\n .d-print-table-cell {\n display: table-cell !important;\n }\n .d-print-flex {\n display: flex !important;\n }\n .d-print-inline-flex {\n display: inline-flex !important;\n }\n .d-print-none {\n display: none !important;\n }\n}\n/*# sourceMappingURL=bootstrap-grid.rtl.css.map */","// Container mixins\n\n@mixin make-container($gutter: $container-padding-x) {\n --#{$prefix}gutter-x: #{$gutter};\n --#{$prefix}gutter-y: 0;\n width: 100%;\n padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n margin-right: auto;\n margin-left: auto;\n}\n","// Breakpoint viewport sizes and media queries.\n//\n// Breakpoints are defined as a map of (name: minimum width), order from small to large:\n//\n// (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)\n//\n// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default.\n\n// Name of the next breakpoint, or null for the last breakpoint.\n//\n// >> breakpoint-next(sm)\n// md\n// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// md\n// >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl xxl))\n// md\n@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) {\n $n: index($breakpoint-names, $name);\n @if not $n {\n @error \"breakpoint `#{$name}` not found in `#{$breakpoints}`\";\n }\n @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null);\n}\n\n// Minimum breakpoint width. Null for the smallest (first) breakpoint.\n//\n// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// 576px\n@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {\n $min: map-get($breakpoints, $name);\n @return if($min != 0, $min, null);\n}\n\n// Maximum breakpoint width.\n// The maximum value is reduced by 0.02px to work around the limitations of\n// `min-` and `max-` prefixes and viewports with fractional widths.\n// See https://www.w3.org/TR/mediaqueries-4/#mq-min-max\n// Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari.\n// See https://bugs.webkit.org/show_bug.cgi?id=178261\n//\n// >> breakpoint-max(md, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// 767.98px\n@function breakpoint-max($name, $breakpoints: $grid-breakpoints) {\n $max: map-get($breakpoints, $name);\n @return if($max and $max > 0, $max - .02, null);\n}\n\n// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front.\n// Useful for making responsive utilities.\n//\n// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// \"\" (Returns a blank string)\n// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\n// \"-sm\"\n@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) {\n @return if(breakpoint-min($name, $breakpoints) == null, \"\", \"-#{$name}\");\n}\n\n// Media of at least the minimum breakpoint width. No query for the smallest breakpoint.\n// Makes the @content apply to the given breakpoint and wider.\n@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($name, $breakpoints);\n @if $min {\n @media (min-width: $min) {\n @content;\n }\n } @else {\n @content;\n }\n}\n\n// Media of at most the maximum breakpoint width. No query for the largest breakpoint.\n// Makes the @content apply to the given breakpoint and narrower.\n@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) {\n $max: breakpoint-max($name, $breakpoints);\n @if $max {\n @media (max-width: $max) {\n @content;\n }\n } @else {\n @content;\n }\n}\n\n// Media that spans multiple breakpoint widths.\n// Makes the @content apply between the min and max breakpoints\n@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($lower, $breakpoints);\n $max: breakpoint-max($upper, $breakpoints);\n\n @if $min != null and $max != null {\n @media (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else if $max == null {\n @include media-breakpoint-up($lower, $breakpoints) {\n @content;\n }\n } @else if $min == null {\n @include media-breakpoint-down($upper, $breakpoints) {\n @content;\n }\n }\n}\n\n// Media between the breakpoint's minimum and maximum widths.\n// No minimum for the smallest breakpoint, and no maximum for the largest one.\n// Makes the @content apply only to the given breakpoint, not viewports any wider or narrower.\n@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($name, $breakpoints);\n $next: breakpoint-next($name, $breakpoints);\n $max: breakpoint-max($next, $breakpoints);\n\n @if $min != null and $max != null {\n @media (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else if $max == null {\n @include media-breakpoint-up($name, $breakpoints) {\n @content;\n }\n } @else if $min == null {\n @include media-breakpoint-down($next, $breakpoints) {\n @content;\n }\n }\n}\n","// Row\n//\n// Rows contain your columns.\n\n:root {\n @each $name, $value in $grid-breakpoints {\n --#{$prefix}breakpoint-#{$name}: #{$value};\n }\n}\n\n@if $enable-grid-classes {\n .row {\n @include make-row();\n\n > * {\n @include make-col-ready();\n }\n }\n}\n\n@if $enable-cssgrid {\n .grid {\n display: grid;\n grid-template-rows: repeat(var(--#{$prefix}rows, 1), 1fr);\n grid-template-columns: repeat(var(--#{$prefix}columns, #{$grid-columns}), 1fr);\n gap: var(--#{$prefix}gap, #{$grid-gutter-width});\n\n @include make-cssgrid();\n }\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n@if $enable-grid-classes {\n @include make-grid-columns();\n}\n","// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n@mixin make-row($gutter: $grid-gutter-width) {\n --#{$prefix}gutter-x: #{$gutter};\n --#{$prefix}gutter-y: 0;\n display: flex;\n flex-wrap: wrap;\n // TODO: Revisit calc order after https://github.com/react-bootstrap/react-bootstrap/issues/6039 is fixed\n margin-top: calc(-1 * var(--#{$prefix}gutter-y)); // stylelint-disable-line function-disallowed-list\n margin-right: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list\n margin-left: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list\n}\n\n@mixin make-col-ready() {\n // Add box sizing if only the grid is loaded\n box-sizing: if(variable-exists(include-column-box-sizing) and $include-column-box-sizing, border-box, null);\n // Prevent columns from becoming too narrow when at smaller grid tiers by\n // always setting `width: 100%;`. This works because we set the width\n // later on to override this initial width.\n flex-shrink: 0;\n width: 100%;\n max-width: 100%; // Prevent `.col-auto`, `.col` (& responsive variants) from breaking out the grid\n padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n margin-top: var(--#{$prefix}gutter-y);\n}\n\n@mixin make-col($size: false, $columns: $grid-columns) {\n @if $size {\n flex: 0 0 auto;\n width: percentage(divide($size, $columns));\n\n } @else {\n flex: 1 1 0;\n max-width: 100%;\n }\n}\n\n@mixin make-col-auto() {\n flex: 0 0 auto;\n width: auto;\n}\n\n@mixin make-col-offset($size, $columns: $grid-columns) {\n $num: divide($size, $columns);\n margin-left: if($num == 0, 0, percentage($num));\n}\n\n// Row columns\n//\n// Specify on a parent element(e.g., .row) to force immediate children into NN\n// number of columns. Supports wrapping to new lines, but does not do a Masonry\n// style grid.\n@mixin row-cols($count) {\n > * {\n flex: 0 0 auto;\n width: percentage(divide(1, $count));\n }\n}\n\n// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `$grid-columns`.\n\n@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) {\n @each $breakpoint in map-keys($breakpoints) {\n $infix: breakpoint-infix($breakpoint, $breakpoints);\n\n @include media-breakpoint-up($breakpoint, $breakpoints) {\n // Provide basic `.col-{bp}` classes for equal-width flexbox columns\n .col#{$infix} {\n flex: 1 0 0%; // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4\n }\n\n .row-cols#{$infix}-auto > * {\n @include make-col-auto();\n }\n\n @if $grid-row-columns > 0 {\n @for $i from 1 through $grid-row-columns {\n .row-cols#{$infix}-#{$i} {\n @include row-cols($i);\n }\n }\n }\n\n .col#{$infix}-auto {\n @include make-col-auto();\n }\n\n @if $columns > 0 {\n @for $i from 1 through $columns {\n .col#{$infix}-#{$i} {\n @include make-col($i, $columns);\n }\n }\n\n // `$columns - 1` because offsetting by the width of an entire row isn't possible\n @for $i from 0 through ($columns - 1) {\n @if not ($infix == \"\" and $i == 0) { // Avoid emitting useless .offset-0\n .offset#{$infix}-#{$i} {\n @include make-col-offset($i, $columns);\n }\n }\n }\n }\n\n // Gutters\n //\n // Make use of `.g-*`, `.gx-*` or `.gy-*` utilities to change spacing between the columns.\n @each $key, $value in $gutters {\n .g#{$infix}-#{$key},\n .gx#{$infix}-#{$key} {\n --#{$prefix}gutter-x: #{$value};\n }\n\n .g#{$infix}-#{$key},\n .gy#{$infix}-#{$key} {\n --#{$prefix}gutter-y: #{$value};\n }\n }\n }\n }\n}\n\n@mixin make-cssgrid($columns: $grid-columns, $breakpoints: $grid-breakpoints) {\n @each $breakpoint in map-keys($breakpoints) {\n $infix: breakpoint-infix($breakpoint, $breakpoints);\n\n @include media-breakpoint-up($breakpoint, $breakpoints) {\n @if $columns > 0 {\n @for $i from 1 through $columns {\n .g-col#{$infix}-#{$i} {\n grid-column: auto / span $i;\n }\n }\n\n // Start with `1` because `0` is an invalid value.\n // Ends with `$columns - 1` because offsetting by the width of an entire row isn't possible.\n @for $i from 1 through ($columns - 1) {\n .g-start#{$infix}-#{$i} {\n grid-column-start: $i;\n }\n }\n }\n }\n }\n}\n","// Utility generator\n// Used to generate utilities & print utilities\n@mixin generate-utility($utility, $infix: \"\", $is-rfs-media-query: false) {\n $values: map-get($utility, values);\n\n // If the values are a list or string, convert it into a map\n @if type-of($values) == \"string\" or type-of(nth($values, 1)) != \"list\" {\n $values: zip($values, $values);\n }\n\n @each $key, $value in $values {\n $properties: map-get($utility, property);\n\n // Multiple properties are possible, for example with vertical or horizontal margins or paddings\n @if type-of($properties) == \"string\" {\n $properties: append((), $properties);\n }\n\n // Use custom class if present\n $property-class: if(map-has-key($utility, class), map-get($utility, class), nth($properties, 1));\n $property-class: if($property-class == null, \"\", $property-class);\n\n // Use custom CSS variable name if present, otherwise default to `class`\n $css-variable-name: if(map-has-key($utility, css-variable-name), map-get($utility, css-variable-name), map-get($utility, class));\n\n // State params to generate pseudo-classes\n $state: if(map-has-key($utility, state), map-get($utility, state), ());\n\n $infix: if($property-class == \"\" and str-slice($infix, 1, 1) == \"-\", str-slice($infix, 2), $infix);\n\n // Don't prefix if value key is null (e.g. with shadow class)\n $property-class-modifier: if($key, if($property-class == \"\" and $infix == \"\", \"\", \"-\") + $key, \"\");\n\n @if map-get($utility, rfs) {\n // Inside the media query\n @if $is-rfs-media-query {\n $val: rfs-value($value);\n\n // Do not render anything if fluid and non fluid values are the same\n $value: if($val == rfs-fluid-value($value), null, $val);\n }\n @else {\n $value: rfs-fluid-value($value);\n }\n }\n\n $is-css-var: map-get($utility, css-var);\n $is-local-vars: map-get($utility, local-vars);\n $is-rtl: map-get($utility, rtl);\n\n @if $value != null {\n @if $is-rtl == false {\n /* rtl:begin:remove */\n }\n\n @if $is-css-var {\n .#{$property-class + $infix + $property-class-modifier} {\n --#{$prefix}#{$css-variable-name}: #{$value};\n }\n\n @each $pseudo in $state {\n .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {\n --#{$prefix}#{$css-variable-name}: #{$value};\n }\n }\n } @else {\n .#{$property-class + $infix + $property-class-modifier} {\n @each $property in $properties {\n @if $is-local-vars {\n @each $local-var, $variable in $is-local-vars {\n --#{$prefix}#{$local-var}: #{$variable};\n }\n }\n #{$property}: $value if($enable-important-utilities, !important, null);\n }\n }\n\n @each $pseudo in $state {\n .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {\n @each $property in $properties {\n @if $is-local-vars {\n @each $local-var, $variable in $is-local-vars {\n --#{$prefix}#{$local-var}: #{$variable};\n }\n }\n #{$property}: $value if($enable-important-utilities, !important, null);\n }\n }\n }\n }\n\n @if $is-rtl == false {\n /* rtl:end:remove */\n }\n }\n }\n}\n","// Loop over each breakpoint\n@each $breakpoint in map-keys($grid-breakpoints) {\n\n // Generate media query if needed\n @include media-breakpoint-up($breakpoint) {\n $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\n\n // Loop over each utility property\n @each $key, $utility in $utilities {\n // The utility can be disabled with `false`, thus check if the utility is a map first\n // Only proceed if responsive media queries are enabled or if it's the base media query\n @if type-of($utility) == \"map\" and (map-get($utility, responsive) or $infix == \"\") {\n @include generate-utility($utility, $infix);\n }\n }\n }\n}\n\n// RFS rescaling\n@media (min-width: $rfs-mq-value) {\n @each $breakpoint in map-keys($grid-breakpoints) {\n $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\n\n @if (map-get($grid-breakpoints, $breakpoint) < $rfs-breakpoint) {\n // Loop over each utility property\n @each $key, $utility in $utilities {\n // The utility can be disabled with `false`, thus check if the utility is a map first\n // Only proceed if responsive media queries are enabled or if it's the base media query\n @if type-of($utility) == \"map\" and map-get($utility, rfs) and (map-get($utility, responsive) or $infix == \"\") {\n @include generate-utility($utility, $infix, true);\n }\n }\n }\n }\n}\n\n\n// Print utilities\n@media print {\n @each $key, $utility in $utilities {\n // The utility can be disabled with `false`, thus check if the utility is a map first\n // Then check if the utility needs print styles\n @if type-of($utility) == \"map\" and map-get($utility, print) == true {\n @include generate-utility($utility, \"-print\");\n }\n }\n}\n"]} \ No newline at end of file diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css new file mode 100644 index 0000000..6305410 --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css @@ -0,0 +1,597 @@ +/*! + * Bootstrap Reboot v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +:root, +[data-bs-theme=light] { + --bs-blue: #0d6efd; + --bs-indigo: #6610f2; + --bs-purple: #6f42c1; + --bs-pink: #d63384; + --bs-red: #dc3545; + --bs-orange: #fd7e14; + --bs-yellow: #ffc107; + --bs-green: #198754; + --bs-teal: #20c997; + --bs-cyan: #0dcaf0; + --bs-black: #000; + --bs-white: #fff; + --bs-gray: #6c757d; + --bs-gray-dark: #343a40; + --bs-gray-100: #f8f9fa; + --bs-gray-200: #e9ecef; + --bs-gray-300: #dee2e6; + --bs-gray-400: #ced4da; + --bs-gray-500: #adb5bd; + --bs-gray-600: #6c757d; + --bs-gray-700: #495057; + --bs-gray-800: #343a40; + --bs-gray-900: #212529; + --bs-primary: #0d6efd; + --bs-secondary: #6c757d; + --bs-success: #198754; + --bs-info: #0dcaf0; + --bs-warning: #ffc107; + --bs-danger: #dc3545; + --bs-light: #f8f9fa; + --bs-dark: #212529; + --bs-primary-rgb: 13, 110, 253; + --bs-secondary-rgb: 108, 117, 125; + --bs-success-rgb: 25, 135, 84; + --bs-info-rgb: 13, 202, 240; + --bs-warning-rgb: 255, 193, 7; + --bs-danger-rgb: 220, 53, 69; + --bs-light-rgb: 248, 249, 250; + --bs-dark-rgb: 33, 37, 41; + --bs-primary-text-emphasis: #052c65; + --bs-secondary-text-emphasis: #2b2f32; + --bs-success-text-emphasis: #0a3622; + --bs-info-text-emphasis: #055160; + --bs-warning-text-emphasis: #664d03; + --bs-danger-text-emphasis: #58151c; + --bs-light-text-emphasis: #495057; + --bs-dark-text-emphasis: #495057; + --bs-primary-bg-subtle: #cfe2ff; + --bs-secondary-bg-subtle: #e2e3e5; + --bs-success-bg-subtle: #d1e7dd; + --bs-info-bg-subtle: #cff4fc; + --bs-warning-bg-subtle: #fff3cd; + --bs-danger-bg-subtle: #f8d7da; + --bs-light-bg-subtle: #fcfcfd; + --bs-dark-bg-subtle: #ced4da; + --bs-primary-border-subtle: #9ec5fe; + --bs-secondary-border-subtle: #c4c8cb; + --bs-success-border-subtle: #a3cfbb; + --bs-info-border-subtle: #9eeaf9; + --bs-warning-border-subtle: #ffe69c; + --bs-danger-border-subtle: #f1aeb5; + --bs-light-border-subtle: #e9ecef; + --bs-dark-border-subtle: #adb5bd; + --bs-white-rgb: 255, 255, 255; + --bs-black-rgb: 0, 0, 0; + --bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0)); + --bs-body-font-family: var(--bs-font-sans-serif); + --bs-body-font-size: 1rem; + --bs-body-font-weight: 400; + --bs-body-line-height: 1.5; + --bs-body-color: #212529; + --bs-body-color-rgb: 33, 37, 41; + --bs-body-bg: #fff; + --bs-body-bg-rgb: 255, 255, 255; + --bs-emphasis-color: #000; + --bs-emphasis-color-rgb: 0, 0, 0; + --bs-secondary-color: rgba(33, 37, 41, 0.75); + --bs-secondary-color-rgb: 33, 37, 41; + --bs-secondary-bg: #e9ecef; + --bs-secondary-bg-rgb: 233, 236, 239; + --bs-tertiary-color: rgba(33, 37, 41, 0.5); + --bs-tertiary-color-rgb: 33, 37, 41; + --bs-tertiary-bg: #f8f9fa; + --bs-tertiary-bg-rgb: 248, 249, 250; + --bs-heading-color: inherit; + --bs-link-color: #0d6efd; + --bs-link-color-rgb: 13, 110, 253; + --bs-link-decoration: underline; + --bs-link-hover-color: #0a58ca; + --bs-link-hover-color-rgb: 10, 88, 202; + --bs-code-color: #d63384; + --bs-highlight-color: #212529; + --bs-highlight-bg: #fff3cd; + --bs-border-width: 1px; + --bs-border-style: solid; + --bs-border-color: #dee2e6; + --bs-border-color-translucent: rgba(0, 0, 0, 0.175); + --bs-border-radius: 0.375rem; + --bs-border-radius-sm: 0.25rem; + --bs-border-radius-lg: 0.5rem; + --bs-border-radius-xl: 1rem; + --bs-border-radius-xxl: 2rem; + --bs-border-radius-2xl: var(--bs-border-radius-xxl); + --bs-border-radius-pill: 50rem; + --bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); + --bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); + --bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175); + --bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075); + --bs-focus-ring-width: 0.25rem; + --bs-focus-ring-opacity: 0.25; + --bs-focus-ring-color: rgba(13, 110, 253, 0.25); + --bs-form-valid-color: #198754; + --bs-form-valid-border-color: #198754; + --bs-form-invalid-color: #dc3545; + --bs-form-invalid-border-color: #dc3545; +} + +[data-bs-theme=dark] { + color-scheme: dark; + --bs-body-color: #dee2e6; + --bs-body-color-rgb: 222, 226, 230; + --bs-body-bg: #212529; + --bs-body-bg-rgb: 33, 37, 41; + --bs-emphasis-color: #fff; + --bs-emphasis-color-rgb: 255, 255, 255; + --bs-secondary-color: rgba(222, 226, 230, 0.75); + --bs-secondary-color-rgb: 222, 226, 230; + --bs-secondary-bg: #343a40; + --bs-secondary-bg-rgb: 52, 58, 64; + --bs-tertiary-color: rgba(222, 226, 230, 0.5); + --bs-tertiary-color-rgb: 222, 226, 230; + --bs-tertiary-bg: #2b3035; + --bs-tertiary-bg-rgb: 43, 48, 53; + --bs-primary-text-emphasis: #6ea8fe; + --bs-secondary-text-emphasis: #a7acb1; + --bs-success-text-emphasis: #75b798; + --bs-info-text-emphasis: #6edff6; + --bs-warning-text-emphasis: #ffda6a; + --bs-danger-text-emphasis: #ea868f; + --bs-light-text-emphasis: #f8f9fa; + --bs-dark-text-emphasis: #dee2e6; + --bs-primary-bg-subtle: #031633; + --bs-secondary-bg-subtle: #161719; + --bs-success-bg-subtle: #051b11; + --bs-info-bg-subtle: #032830; + --bs-warning-bg-subtle: #332701; + --bs-danger-bg-subtle: #2c0b0e; + --bs-light-bg-subtle: #343a40; + --bs-dark-bg-subtle: #1a1d20; + --bs-primary-border-subtle: #084298; + --bs-secondary-border-subtle: #41464b; + --bs-success-border-subtle: #0f5132; + --bs-info-border-subtle: #087990; + --bs-warning-border-subtle: #997404; + --bs-danger-border-subtle: #842029; + --bs-light-border-subtle: #495057; + --bs-dark-border-subtle: #343a40; + --bs-heading-color: inherit; + --bs-link-color: #6ea8fe; + --bs-link-hover-color: #8bb9fe; + --bs-link-color-rgb: 110, 168, 254; + --bs-link-hover-color-rgb: 139, 185, 254; + --bs-code-color: #e685b5; + --bs-highlight-color: #dee2e6; + --bs-highlight-bg: #664d03; + --bs-border-color: #495057; + --bs-border-color-translucent: rgba(255, 255, 255, 0.15); + --bs-form-valid-color: #75b798; + --bs-form-valid-border-color: #75b798; + --bs-form-invalid-color: #ea868f; + --bs-form-invalid-border-color: #ea868f; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +@media (prefers-reduced-motion: no-preference) { + :root { + scroll-behavior: smooth; + } +} + +body { + margin: 0; + font-family: var(--bs-body-font-family); + font-size: var(--bs-body-font-size); + font-weight: var(--bs-body-font-weight); + line-height: var(--bs-body-line-height); + color: var(--bs-body-color); + text-align: var(--bs-body-text-align); + background-color: var(--bs-body-bg); + -webkit-text-size-adjust: 100%; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +hr { + margin: 1rem 0; + color: inherit; + border: 0; + border-top: var(--bs-border-width) solid; + opacity: 0.25; +} + +h6, h5, h4, h3, h2, h1 { + margin-top: 0; + margin-bottom: 0.5rem; + font-weight: 500; + line-height: 1.2; + color: var(--bs-heading-color); +} + +h1 { + font-size: calc(1.375rem + 1.5vw); +} +@media (min-width: 1200px) { + h1 { + font-size: 2.5rem; + } +} + +h2 { + font-size: calc(1.325rem + 0.9vw); +} +@media (min-width: 1200px) { + h2 { + font-size: 2rem; + } +} + +h3 { + font-size: calc(1.3rem + 0.6vw); +} +@media (min-width: 1200px) { + h3 { + font-size: 1.75rem; + } +} + +h4 { + font-size: calc(1.275rem + 0.3vw); +} +@media (min-width: 1200px) { + h4 { + font-size: 1.5rem; + } +} + +h5 { + font-size: 1.25rem; +} + +h6 { + font-size: 1rem; +} + +p { + margin-top: 0; + margin-bottom: 1rem; +} + +abbr[title] { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; + cursor: help; + -webkit-text-decoration-skip-ink: none; + text-decoration-skip-ink: none; +} + +address { + margin-bottom: 1rem; + font-style: normal; + line-height: inherit; +} + +ol, +ul { + padding-left: 2rem; +} + +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: 0.5rem; + margin-left: 0; +} + +blockquote { + margin: 0 0 1rem; +} + +b, +strong { + font-weight: bolder; +} + +small { + font-size: 0.875em; +} + +mark { + padding: 0.1875em; + color: var(--bs-highlight-color); + background-color: var(--bs-highlight-bg); +} + +sub, +sup { + position: relative; + font-size: 0.75em; + line-height: 0; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +a { + color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1)); + text-decoration: underline; +} +a:hover { + --bs-link-color-rgb: var(--bs-link-hover-color-rgb); +} + +a:not([href]):not([class]), a:not([href]):not([class]):hover { + color: inherit; + text-decoration: none; +} + +pre, +code, +kbd, +samp { + font-family: var(--bs-font-monospace); + font-size: 1em; +} + +pre { + display: block; + margin-top: 0; + margin-bottom: 1rem; + overflow: auto; + font-size: 0.875em; +} +pre code { + font-size: inherit; + color: inherit; + word-break: normal; +} + +code { + font-size: 0.875em; + color: var(--bs-code-color); + word-wrap: break-word; +} +a > code { + color: inherit; +} + +kbd { + padding: 0.1875rem 0.375rem; + font-size: 0.875em; + color: var(--bs-body-bg); + background-color: var(--bs-body-color); + border-radius: 0.25rem; +} +kbd kbd { + padding: 0; + font-size: 1em; +} + +figure { + margin: 0 0 1rem; +} + +img, +svg { + vertical-align: middle; +} + +table { + caption-side: bottom; + border-collapse: collapse; +} + +caption { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + color: var(--bs-secondary-color); + text-align: left; +} + +th { + text-align: inherit; + text-align: -webkit-match-parent; +} + +thead, +tbody, +tfoot, +tr, +td, +th { + border-color: inherit; + border-style: solid; + border-width: 0; +} + +label { + display: inline-block; +} + +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, +select { + text-transform: none; +} + +[role=button] { + cursor: pointer; +} + +select { + word-wrap: normal; +} +select:disabled { + opacity: 1; +} + +[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator { + display: none !important; +} + +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; +} + +::-moz-focus-inner { + padding: 0; + border-style: none; +} + +textarea { + resize: vertical; +} + +fieldset { + min-width: 0; + padding: 0; + margin: 0; + border: 0; +} + +legend { + float: left; + width: 100%; + padding: 0; + margin-bottom: 0.5rem; + font-size: calc(1.275rem + 0.3vw); + line-height: inherit; +} +@media (min-width: 1200px) { + legend { + font-size: 1.5rem; + } +} +legend + * { + clear: left; +} + +::-webkit-datetime-edit-fields-wrapper, +::-webkit-datetime-edit-text, +::-webkit-datetime-edit-minute, +::-webkit-datetime-edit-hour-field, +::-webkit-datetime-edit-day-field, +::-webkit-datetime-edit-month-field, +::-webkit-datetime-edit-year-field { + padding: 0; +} + +::-webkit-inner-spin-button { + height: auto; +} + +[type=search] { + -webkit-appearance: textfield; + outline-offset: -2px; +} + +/* rtl:raw: +[type="tel"], +[type="url"], +[type="email"], +[type="number"] { + direction: ltr; +} +*/ +::-webkit-search-decoration { + -webkit-appearance: none; +} + +::-webkit-color-swatch-wrapper { + padding: 0; +} + +::-webkit-file-upload-button { + font: inherit; + -webkit-appearance: button; +} + +::file-selector-button { + font: inherit; + -webkit-appearance: button; +} + +output { + display: inline-block; +} + +iframe { + border: 0; +} + +summary { + display: list-item; + cursor: pointer; +} + +progress { + vertical-align: baseline; +} + +[hidden] { + display: none !important; +} + +/*# sourceMappingURL=bootstrap-reboot.css.map */ \ No newline at end of file diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map new file mode 100644 index 0000000..5fe522b --- /dev/null +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../scss/mixins/_banner.scss","../../scss/_root.scss","../../scss/vendor/_rfs.scss","bootstrap-reboot.css","../../scss/mixins/_color-mode.scss","../../scss/_reboot.scss","../../scss/_variables.scss","../../scss/mixins/_border-radius.scss"],"names":[],"mappings":"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","file":"bootstrap-reboot.css","sourcesContent":["@mixin bsBanner($file) {\n /*!\n * Bootstrap #{$file} v5.3.3 (https://getbootstrap.com/)\n * Copyright 2011-2024 The Bootstrap Authors\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n}\n",":root,\n[data-bs-theme=\"light\"] {\n // Note: Custom variable values only support SassScript inside `#{}`.\n\n // Colors\n //\n // Generate palettes for full colors, grays, and theme colors.\n\n @each $color, $value in $colors {\n --#{$prefix}#{$color}: #{$value};\n }\n\n @each $color, $value in $grays {\n --#{$prefix}gray-#{$color}: #{$value};\n }\n\n @each $color, $value in $theme-colors {\n --#{$prefix}#{$color}: #{$value};\n }\n\n @each $color, $value in $theme-colors-rgb {\n --#{$prefix}#{$color}-rgb: #{$value};\n }\n\n @each $color, $value in $theme-colors-text {\n --#{$prefix}#{$color}-text-emphasis: #{$value};\n }\n\n @each $color, $value in $theme-colors-bg-subtle {\n --#{$prefix}#{$color}-bg-subtle: #{$value};\n }\n\n @each $color, $value in $theme-colors-border-subtle {\n --#{$prefix}#{$color}-border-subtle: #{$value};\n }\n\n --#{$prefix}white-rgb: #{to-rgb($white)};\n --#{$prefix}black-rgb: #{to-rgb($black)};\n\n // Fonts\n\n // Note: Use `inspect` for lists so that quoted items keep the quotes.\n // See https://github.com/sass/sass/issues/2383#issuecomment-336349172\n --#{$prefix}font-sans-serif: #{inspect($font-family-sans-serif)};\n --#{$prefix}font-monospace: #{inspect($font-family-monospace)};\n --#{$prefix}gradient: #{$gradient};\n\n // Root and body\n // scss-docs-start root-body-variables\n @if $font-size-root != null {\n --#{$prefix}root-font-size: #{$font-size-root};\n }\n --#{$prefix}body-font-family: #{inspect($font-family-base)};\n @include rfs($font-size-base, --#{$prefix}body-font-size);\n --#{$prefix}body-font-weight: #{$font-weight-base};\n --#{$prefix}body-line-height: #{$line-height-base};\n @if $body-text-align != null {\n --#{$prefix}body-text-align: #{$body-text-align};\n }\n\n --#{$prefix}body-color: #{$body-color};\n --#{$prefix}body-color-rgb: #{to-rgb($body-color)};\n --#{$prefix}body-bg: #{$body-bg};\n --#{$prefix}body-bg-rgb: #{to-rgb($body-bg)};\n\n --#{$prefix}emphasis-color: #{$body-emphasis-color};\n --#{$prefix}emphasis-color-rgb: #{to-rgb($body-emphasis-color)};\n\n --#{$prefix}secondary-color: #{$body-secondary-color};\n --#{$prefix}secondary-color-rgb: #{to-rgb($body-secondary-color)};\n --#{$prefix}secondary-bg: #{$body-secondary-bg};\n --#{$prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg)};\n\n --#{$prefix}tertiary-color: #{$body-tertiary-color};\n --#{$prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color)};\n --#{$prefix}tertiary-bg: #{$body-tertiary-bg};\n --#{$prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg)};\n // scss-docs-end root-body-variables\n\n --#{$prefix}heading-color: #{$headings-color};\n\n --#{$prefix}link-color: #{$link-color};\n --#{$prefix}link-color-rgb: #{to-rgb($link-color)};\n --#{$prefix}link-decoration: #{$link-decoration};\n\n --#{$prefix}link-hover-color: #{$link-hover-color};\n --#{$prefix}link-hover-color-rgb: #{to-rgb($link-hover-color)};\n\n @if $link-hover-decoration != null {\n --#{$prefix}link-hover-decoration: #{$link-hover-decoration};\n }\n\n --#{$prefix}code-color: #{$code-color};\n --#{$prefix}highlight-color: #{$mark-color};\n --#{$prefix}highlight-bg: #{$mark-bg};\n\n // scss-docs-start root-border-var\n --#{$prefix}border-width: #{$border-width};\n --#{$prefix}border-style: #{$border-style};\n --#{$prefix}border-color: #{$border-color};\n --#{$prefix}border-color-translucent: #{$border-color-translucent};\n\n --#{$prefix}border-radius: #{$border-radius};\n --#{$prefix}border-radius-sm: #{$border-radius-sm};\n --#{$prefix}border-radius-lg: #{$border-radius-lg};\n --#{$prefix}border-radius-xl: #{$border-radius-xl};\n --#{$prefix}border-radius-xxl: #{$border-radius-xxl};\n --#{$prefix}border-radius-2xl: var(--#{$prefix}border-radius-xxl); // Deprecated in v5.3.0 for consistency\n --#{$prefix}border-radius-pill: #{$border-radius-pill};\n // scss-docs-end root-border-var\n\n --#{$prefix}box-shadow: #{$box-shadow};\n --#{$prefix}box-shadow-sm: #{$box-shadow-sm};\n --#{$prefix}box-shadow-lg: #{$box-shadow-lg};\n --#{$prefix}box-shadow-inset: #{$box-shadow-inset};\n\n // Focus styles\n // scss-docs-start root-focus-variables\n --#{$prefix}focus-ring-width: #{$focus-ring-width};\n --#{$prefix}focus-ring-opacity: #{$focus-ring-opacity};\n --#{$prefix}focus-ring-color: #{$focus-ring-color};\n // scss-docs-end root-focus-variables\n\n // scss-docs-start root-form-validation-variables\n --#{$prefix}form-valid-color: #{$form-valid-color};\n --#{$prefix}form-valid-border-color: #{$form-valid-border-color};\n --#{$prefix}form-invalid-color: #{$form-invalid-color};\n --#{$prefix}form-invalid-border-color: #{$form-invalid-border-color};\n // scss-docs-end root-form-validation-variables\n}\n\n@if $enable-dark-mode {\n @include color-mode(dark, true) {\n color-scheme: dark;\n\n // scss-docs-start root-dark-mode-vars\n --#{$prefix}body-color: #{$body-color-dark};\n --#{$prefix}body-color-rgb: #{to-rgb($body-color-dark)};\n --#{$prefix}body-bg: #{$body-bg-dark};\n --#{$prefix}body-bg-rgb: #{to-rgb($body-bg-dark)};\n\n --#{$prefix}emphasis-color: #{$body-emphasis-color-dark};\n --#{$prefix}emphasis-color-rgb: #{to-rgb($body-emphasis-color-dark)};\n\n --#{$prefix}secondary-color: #{$body-secondary-color-dark};\n --#{$prefix}secondary-color-rgb: #{to-rgb($body-secondary-color-dark)};\n --#{$prefix}secondary-bg: #{$body-secondary-bg-dark};\n --#{$prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg-dark)};\n\n --#{$prefix}tertiary-color: #{$body-tertiary-color-dark};\n --#{$prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color-dark)};\n --#{$prefix}tertiary-bg: #{$body-tertiary-bg-dark};\n --#{$prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg-dark)};\n\n @each $color, $value in $theme-colors-text-dark {\n --#{$prefix}#{$color}-text-emphasis: #{$value};\n }\n\n @each $color, $value in $theme-colors-bg-subtle-dark {\n --#{$prefix}#{$color}-bg-subtle: #{$value};\n }\n\n @each $color, $value in $theme-colors-border-subtle-dark {\n --#{$prefix}#{$color}-border-subtle: #{$value};\n }\n\n --#{$prefix}heading-color: #{$headings-color-dark};\n\n --#{$prefix}link-color: #{$link-color-dark};\n --#{$prefix}link-hover-color: #{$link-hover-color-dark};\n --#{$prefix}link-color-rgb: #{to-rgb($link-color-dark)};\n --#{$prefix}link-hover-color-rgb: #{to-rgb($link-hover-color-dark)};\n\n --#{$prefix}code-color: #{$code-color-dark};\n --#{$prefix}highlight-color: #{$mark-color-dark};\n --#{$prefix}highlight-bg: #{$mark-bg-dark};\n\n --#{$prefix}border-color: #{$border-color-dark};\n --#{$prefix}border-color-translucent: #{$border-color-translucent-dark};\n\n --#{$prefix}form-valid-color: #{$form-valid-color-dark};\n --#{$prefix}form-valid-border-color: #{$form-valid-border-color-dark};\n --#{$prefix}form-invalid-color: #{$form-invalid-color-dark};\n --#{$prefix}form-invalid-border-color: #{$form-invalid-border-color-dark};\n // scss-docs-end root-dark-mode-vars\n }\n}\n","// stylelint-disable scss/dimension-no-non-numeric-values\n\n// SCSS RFS mixin\n//\n// Automated responsive values for font sizes, paddings, margins and much more\n//\n// Licensed under MIT (https://github.com/twbs/rfs/blob/main/LICENSE)\n\n// Configuration\n\n// Base value\n$rfs-base-value: 1.25rem !default;\n$rfs-unit: rem !default;\n\n@if $rfs-unit != rem and $rfs-unit != px {\n @error \"`#{$rfs-unit}` is not a valid unit for $rfs-unit. Use `px` or `rem`.\";\n}\n\n// Breakpoint at where values start decreasing if screen width is smaller\n$rfs-breakpoint: 1200px !default;\n$rfs-breakpoint-unit: px !default;\n\n@if $rfs-breakpoint-unit != px and $rfs-breakpoint-unit != em and $rfs-breakpoint-unit != rem {\n @error \"`#{$rfs-breakpoint-unit}` is not a valid unit for $rfs-breakpoint-unit. Use `px`, `em` or `rem`.\";\n}\n\n// Resize values based on screen height and width\n$rfs-two-dimensional: false !default;\n\n// Factor of decrease\n$rfs-factor: 10 !default;\n\n@if type-of($rfs-factor) != number or $rfs-factor <= 1 {\n @error \"`#{$rfs-factor}` is not a valid $rfs-factor, it must be greater than 1.\";\n}\n\n// Mode. Possibilities: \"min-media-query\", \"max-media-query\"\n$rfs-mode: min-media-query !default;\n\n// Generate enable or disable classes. Possibilities: false, \"enable\" or \"disable\"\n$rfs-class: false !default;\n\n// 1 rem = $rfs-rem-value px\n$rfs-rem-value: 16 !default;\n\n// Safari iframe resize bug: https://github.com/twbs/rfs/issues/14\n$rfs-safari-iframe-resize-bug-fix: false !default;\n\n// Disable RFS by setting $enable-rfs to false\n$enable-rfs: true !default;\n\n// Cache $rfs-base-value unit\n$rfs-base-value-unit: unit($rfs-base-value);\n\n@function divide($dividend, $divisor, $precision: 10) {\n $sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1);\n $dividend: abs($dividend);\n $divisor: abs($divisor);\n @if $dividend == 0 {\n @return 0;\n }\n @if $divisor == 0 {\n @error \"Cannot divide by 0\";\n }\n $remainder: $dividend;\n $result: 0;\n $factor: 10;\n @while ($remainder > 0 and $precision >= 0) {\n $quotient: 0;\n @while ($remainder >= $divisor) {\n $remainder: $remainder - $divisor;\n $quotient: $quotient + 1;\n }\n $result: $result * 10 + $quotient;\n $factor: $factor * .1;\n $remainder: $remainder * 10;\n $precision: $precision - 1;\n @if ($precision < 0 and $remainder >= $divisor * 5) {\n $result: $result + 1;\n }\n }\n $result: $result * $factor * $sign;\n $dividend-unit: unit($dividend);\n $divisor-unit: unit($divisor);\n $unit-map: (\n \"px\": 1px,\n \"rem\": 1rem,\n \"em\": 1em,\n \"%\": 1%\n );\n @if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) {\n $result: $result * map-get($unit-map, $dividend-unit);\n }\n @return $result;\n}\n\n// Remove px-unit from $rfs-base-value for calculations\n@if $rfs-base-value-unit == px {\n $rfs-base-value: divide($rfs-base-value, $rfs-base-value * 0 + 1);\n}\n@else if $rfs-base-value-unit == rem {\n $rfs-base-value: divide($rfs-base-value, divide($rfs-base-value * 0 + 1, $rfs-rem-value));\n}\n\n// Cache $rfs-breakpoint unit to prevent multiple calls\n$rfs-breakpoint-unit-cache: unit($rfs-breakpoint);\n\n// Remove unit from $rfs-breakpoint for calculations\n@if $rfs-breakpoint-unit-cache == px {\n $rfs-breakpoint: divide($rfs-breakpoint, $rfs-breakpoint * 0 + 1);\n}\n@else if $rfs-breakpoint-unit-cache == rem or $rfs-breakpoint-unit-cache == \"em\" {\n $rfs-breakpoint: divide($rfs-breakpoint, divide($rfs-breakpoint * 0 + 1, $rfs-rem-value));\n}\n\n// Calculate the media query value\n$rfs-mq-value: if($rfs-breakpoint-unit == px, #{$rfs-breakpoint}px, #{divide($rfs-breakpoint, $rfs-rem-value)}#{$rfs-breakpoint-unit});\n$rfs-mq-property-width: if($rfs-mode == max-media-query, max-width, min-width);\n$rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height);\n\n// Internal mixin used to determine which media query needs to be used\n@mixin _rfs-media-query {\n @if $rfs-two-dimensional {\n @if $rfs-mode == max-media-query {\n @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}), (#{$rfs-mq-property-height}: #{$rfs-mq-value}) {\n @content;\n }\n }\n @else {\n @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) and (#{$rfs-mq-property-height}: #{$rfs-mq-value}) {\n @content;\n }\n }\n }\n @else {\n @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) {\n @content;\n }\n }\n}\n\n// Internal mixin that adds disable classes to the selector if needed.\n@mixin _rfs-rule {\n @if $rfs-class == disable and $rfs-mode == max-media-query {\n // Adding an extra class increases specificity, which prevents the media query to override the property\n &,\n .disable-rfs &,\n &.disable-rfs {\n @content;\n }\n }\n @else if $rfs-class == enable and $rfs-mode == min-media-query {\n .enable-rfs &,\n &.enable-rfs {\n @content;\n }\n } @else {\n @content;\n }\n}\n\n// Internal mixin that adds enable classes to the selector if needed.\n@mixin _rfs-media-query-rule {\n\n @if $rfs-class == enable {\n @if $rfs-mode == min-media-query {\n @content;\n }\n\n @include _rfs-media-query () {\n .enable-rfs &,\n &.enable-rfs {\n @content;\n }\n }\n }\n @else {\n @if $rfs-class == disable and $rfs-mode == min-media-query {\n .disable-rfs &,\n &.disable-rfs {\n @content;\n }\n }\n @include _rfs-media-query () {\n @content;\n }\n }\n}\n\n// Helper function to get the formatted non-responsive value\n@function rfs-value($values) {\n // Convert to list\n $values: if(type-of($values) != list, ($values,), $values);\n\n $val: \"\";\n\n // Loop over each value and calculate value\n @each $value in $values {\n @if $value == 0 {\n $val: $val + \" 0\";\n }\n @else {\n // Cache $value unit\n $unit: if(type-of($value) == \"number\", unit($value), false);\n\n @if $unit == px {\n // Convert to rem if needed\n $val: $val + \" \" + if($rfs-unit == rem, #{divide($value, $value * 0 + $rfs-rem-value)}rem, $value);\n }\n @else if $unit == rem {\n // Convert to px if needed\n $val: $val + \" \" + if($rfs-unit == px, #{divide($value, $value * 0 + 1) * $rfs-rem-value}px, $value);\n } @else {\n // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value\n $val: $val + \" \" + $value;\n }\n }\n }\n\n // Remove first space\n @return unquote(str-slice($val, 2));\n}\n\n// Helper function to get the responsive value calculated by RFS\n@function rfs-fluid-value($values) {\n // Convert to list\n $values: if(type-of($values) != list, ($values,), $values);\n\n $val: \"\";\n\n // Loop over each value and calculate value\n @each $value in $values {\n @if $value == 0 {\n $val: $val + \" 0\";\n } @else {\n // Cache $value unit\n $unit: if(type-of($value) == \"number\", unit($value), false);\n\n // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value\n @if not $unit or $unit != px and $unit != rem {\n $val: $val + \" \" + $value;\n } @else {\n // Remove unit from $value for calculations\n $value: divide($value, $value * 0 + if($unit == px, 1, divide(1, $rfs-rem-value)));\n\n // Only add the media query if the value is greater than the minimum value\n @if abs($value) <= $rfs-base-value or not $enable-rfs {\n $val: $val + \" \" + if($rfs-unit == rem, #{divide($value, $rfs-rem-value)}rem, #{$value}px);\n }\n @else {\n // Calculate the minimum value\n $value-min: $rfs-base-value + divide(abs($value) - $rfs-base-value, $rfs-factor);\n\n // Calculate difference between $value and the minimum value\n $value-diff: abs($value) - $value-min;\n\n // Base value formatting\n $min-width: if($rfs-unit == rem, #{divide($value-min, $rfs-rem-value)}rem, #{$value-min}px);\n\n // Use negative value if needed\n $min-width: if($value < 0, -$min-width, $min-width);\n\n // Use `vmin` if two-dimensional is enabled\n $variable-unit: if($rfs-two-dimensional, vmin, vw);\n\n // Calculate the variable width between 0 and $rfs-breakpoint\n $variable-width: #{divide($value-diff * 100, $rfs-breakpoint)}#{$variable-unit};\n\n // Return the calculated value\n $val: $val + \" calc(\" + $min-width + if($value < 0, \" - \", \" + \") + $variable-width + \")\";\n }\n }\n }\n }\n\n // Remove first space\n @return unquote(str-slice($val, 2));\n}\n\n// RFS mixin\n@mixin rfs($values, $property: font-size) {\n @if $values != null {\n $val: rfs-value($values);\n $fluid-val: rfs-fluid-value($values);\n\n // Do not print the media query if responsive & non-responsive values are the same\n @if $val == $fluid-val {\n #{$property}: $val;\n }\n @else {\n @include _rfs-rule () {\n #{$property}: if($rfs-mode == max-media-query, $val, $fluid-val);\n\n // Include safari iframe resize fix if needed\n min-width: if($rfs-safari-iframe-resize-bug-fix, (0 * 1vw), null);\n }\n\n @include _rfs-media-query-rule () {\n #{$property}: if($rfs-mode == max-media-query, $fluid-val, $val);\n }\n }\n }\n}\n\n// Shorthand helper mixins\n@mixin font-size($value) {\n @include rfs($value);\n}\n\n@mixin padding($value) {\n @include rfs($value, padding);\n}\n\n@mixin padding-top($value) {\n @include rfs($value, padding-top);\n}\n\n@mixin padding-right($value) {\n @include rfs($value, padding-right);\n}\n\n@mixin padding-bottom($value) {\n @include rfs($value, padding-bottom);\n}\n\n@mixin padding-left($value) {\n @include rfs($value, padding-left);\n}\n\n@mixin margin($value) {\n @include rfs($value, margin);\n}\n\n@mixin margin-top($value) {\n @include rfs($value, margin-top);\n}\n\n@mixin margin-right($value) {\n @include rfs($value, margin-right);\n}\n\n@mixin margin-bottom($value) {\n @include rfs($value, margin-bottom);\n}\n\n@mixin margin-left($value) {\n @include rfs($value, margin-left);\n}\n","/*!\n * Bootstrap Reboot v5.3.3 (https://getbootstrap.com/)\n * Copyright 2011-2024 The Bootstrap Authors\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n:root,\n[data-bs-theme=light] {\n --bs-blue: #0d6efd;\n --bs-indigo: #6610f2;\n --bs-purple: #6f42c1;\n --bs-pink: #d63384;\n --bs-red: #dc3545;\n --bs-orange: #fd7e14;\n --bs-yellow: #ffc107;\n --bs-green: #198754;\n --bs-teal: #20c997;\n --bs-cyan: #0dcaf0;\n --bs-black: #000;\n --bs-white: #fff;\n --bs-gray: #6c757d;\n --bs-gray-dark: #343a40;\n --bs-gray-100: #f8f9fa;\n --bs-gray-200: #e9ecef;\n --bs-gray-300: #dee2e6;\n --bs-gray-400: #ced4da;\n --bs-gray-500: #adb5bd;\n --bs-gray-600: #6c757d;\n --bs-gray-700: #495057;\n --bs-gray-800: #343a40;\n --bs-gray-900: #212529;\n --bs-primary: #0d6efd;\n --bs-secondary: #6c757d;\n --bs-success: #198754;\n --bs-info: #0dcaf0;\n --bs-warning: #ffc107;\n --bs-danger: #dc3545;\n --bs-light: #f8f9fa;\n --bs-dark: #212529;\n --bs-primary-rgb: 13, 110, 253;\n --bs-secondary-rgb: 108, 117, 125;\n --bs-success-rgb: 25, 135, 84;\n --bs-info-rgb: 13, 202, 240;\n --bs-warning-rgb: 255, 193, 7;\n --bs-danger-rgb: 220, 53, 69;\n --bs-light-rgb: 248, 249, 250;\n --bs-dark-rgb: 33, 37, 41;\n --bs-primary-text-emphasis: #052c65;\n --bs-secondary-text-emphasis: #2b2f32;\n --bs-success-text-emphasis: #0a3622;\n --bs-info-text-emphasis: #055160;\n --bs-warning-text-emphasis: #664d03;\n --bs-danger-text-emphasis: #58151c;\n --bs-light-text-emphasis: #495057;\n --bs-dark-text-emphasis: #495057;\n --bs-primary-bg-subtle: #cfe2ff;\n --bs-secondary-bg-subtle: #e2e3e5;\n --bs-success-bg-subtle: #d1e7dd;\n --bs-info-bg-subtle: #cff4fc;\n --bs-warning-bg-subtle: #fff3cd;\n --bs-danger-bg-subtle: #f8d7da;\n --bs-light-bg-subtle: #fcfcfd;\n --bs-dark-bg-subtle: #ced4da;\n --bs-primary-border-subtle: #9ec5fe;\n --bs-secondary-border-subtle: #c4c8cb;\n --bs-success-border-subtle: #a3cfbb;\n --bs-info-border-subtle: #9eeaf9;\n --bs-warning-border-subtle: #ffe69c;\n --bs-danger-border-subtle: #f1aeb5;\n --bs-light-border-subtle: #e9ecef;\n --bs-dark-border-subtle: #adb5bd;\n --bs-white-rgb: 255, 255, 255;\n --bs-black-rgb: 0, 0, 0;\n --bs-font-sans-serif: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", \"Liberation Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));\n --bs-body-font-family: var(--bs-font-sans-serif);\n --bs-body-font-size: 1rem;\n --bs-body-font-weight: 400;\n --bs-body-line-height: 1.5;\n --bs-body-color: #212529;\n --bs-body-color-rgb: 33, 37, 41;\n --bs-body-bg: #fff;\n --bs-body-bg-rgb: 255, 255, 255;\n --bs-emphasis-color: #000;\n --bs-emphasis-color-rgb: 0, 0, 0;\n --bs-secondary-color: rgba(33, 37, 41, 0.75);\n --bs-secondary-color-rgb: 33, 37, 41;\n --bs-secondary-bg: #e9ecef;\n --bs-secondary-bg-rgb: 233, 236, 239;\n --bs-tertiary-color: rgba(33, 37, 41, 0.5);\n --bs-tertiary-color-rgb: 33, 37, 41;\n --bs-tertiary-bg: #f8f9fa;\n --bs-tertiary-bg-rgb: 248, 249, 250;\n --bs-heading-color: inherit;\n --bs-link-color: #0d6efd;\n --bs-link-color-rgb: 13, 110, 253;\n --bs-link-decoration: underline;\n --bs-link-hover-color: #0a58ca;\n --bs-link-hover-color-rgb: 10, 88, 202;\n --bs-code-color: #d63384;\n --bs-highlight-color: #212529;\n --bs-highlight-bg: #fff3cd;\n --bs-border-width: 1px;\n --bs-border-style: solid;\n --bs-border-color: #dee2e6;\n --bs-border-color-translucent: rgba(0, 0, 0, 0.175);\n --bs-border-radius: 0.375rem;\n --bs-border-radius-sm: 0.25rem;\n --bs-border-radius-lg: 0.5rem;\n --bs-border-radius-xl: 1rem;\n --bs-border-radius-xxl: 2rem;\n --bs-border-radius-2xl: var(--bs-border-radius-xxl);\n --bs-border-radius-pill: 50rem;\n --bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);\n --bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);\n --bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);\n --bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);\n --bs-focus-ring-width: 0.25rem;\n --bs-focus-ring-opacity: 0.25;\n --bs-focus-ring-color: rgba(13, 110, 253, 0.25);\n --bs-form-valid-color: #198754;\n --bs-form-valid-border-color: #198754;\n --bs-form-invalid-color: #dc3545;\n --bs-form-invalid-border-color: #dc3545;\n}\n\n[data-bs-theme=dark] {\n color-scheme: dark;\n --bs-body-color: #dee2e6;\n --bs-body-color-rgb: 222, 226, 230;\n --bs-body-bg: #212529;\n --bs-body-bg-rgb: 33, 37, 41;\n --bs-emphasis-color: #fff;\n --bs-emphasis-color-rgb: 255, 255, 255;\n --bs-secondary-color: rgba(222, 226, 230, 0.75);\n --bs-secondary-color-rgb: 222, 226, 230;\n --bs-secondary-bg: #343a40;\n --bs-secondary-bg-rgb: 52, 58, 64;\n --bs-tertiary-color: rgba(222, 226, 230, 0.5);\n --bs-tertiary-color-rgb: 222, 226, 230;\n --bs-tertiary-bg: #2b3035;\n --bs-tertiary-bg-rgb: 43, 48, 53;\n --bs-primary-text-emphasis: #6ea8fe;\n --bs-secondary-text-emphasis: #a7acb1;\n --bs-success-text-emphasis: #75b798;\n --bs-info-text-emphasis: #6edff6;\n --bs-warning-text-emphasis: #ffda6a;\n --bs-danger-text-emphasis: #ea868f;\n --bs-light-text-emphasis: #f8f9fa;\n --bs-dark-text-emphasis: #dee2e6;\n --bs-primary-bg-subtle: #031633;\n --bs-secondary-bg-subtle: #161719;\n --bs-success-bg-subtle: #051b11;\n --bs-info-bg-subtle: #032830;\n --bs-warning-bg-subtle: #332701;\n --bs-danger-bg-subtle: #2c0b0e;\n --bs-light-bg-subtle: #343a40;\n --bs-dark-bg-subtle: #1a1d20;\n --bs-primary-border-subtle: #084298;\n --bs-secondary-border-subtle: #41464b;\n --bs-success-border-subtle: #0f5132;\n --bs-info-border-subtle: #087990;\n --bs-warning-border-subtle: #997404;\n --bs-danger-border-subtle: #842029;\n --bs-light-border-subtle: #495057;\n --bs-dark-border-subtle: #343a40;\n --bs-heading-color: inherit;\n --bs-link-color: #6ea8fe;\n --bs-link-hover-color: #8bb9fe;\n --bs-link-color-rgb: 110, 168, 254;\n --bs-link-hover-color-rgb: 139, 185, 254;\n --bs-code-color: #e685b5;\n --bs-highlight-color: #dee2e6;\n --bs-highlight-bg: #664d03;\n --bs-border-color: #495057;\n --bs-border-color-translucent: rgba(255, 255, 255, 0.15);\n --bs-form-valid-color: #75b798;\n --bs-form-valid-border-color: #75b798;\n --bs-form-invalid-color: #ea868f;\n --bs-form-invalid-border-color: #ea868f;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n :root {\n scroll-behavior: smooth;\n }\n}\n\nbody {\n margin: 0;\n font-family: var(--bs-body-font-family);\n font-size: var(--bs-body-font-size);\n font-weight: var(--bs-body-font-weight);\n line-height: var(--bs-body-line-height);\n color: var(--bs-body-color);\n text-align: var(--bs-body-text-align);\n background-color: var(--bs-body-bg);\n -webkit-text-size-adjust: 100%;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n\nhr {\n margin: 1rem 0;\n color: inherit;\n border: 0;\n border-top: var(--bs-border-width) solid;\n opacity: 0.25;\n}\n\nh6, h5, h4, h3, h2, h1 {\n margin-top: 0;\n margin-bottom: 0.5rem;\n font-weight: 500;\n line-height: 1.2;\n color: var(--bs-heading-color);\n}\n\nh1 {\n font-size: calc(1.375rem + 1.5vw);\n}\n@media (min-width: 1200px) {\n h1 {\n font-size: 2.5rem;\n }\n}\n\nh2 {\n font-size: calc(1.325rem + 0.9vw);\n}\n@media (min-width: 1200px) {\n h2 {\n font-size: 2rem;\n }\n}\n\nh3 {\n font-size: calc(1.3rem + 0.6vw);\n}\n@media (min-width: 1200px) {\n h3 {\n font-size: 1.75rem;\n }\n}\n\nh4 {\n font-size: calc(1.275rem + 0.3vw);\n}\n@media (min-width: 1200px) {\n h4 {\n font-size: 1.5rem;\n }\n}\n\nh5 {\n font-size: 1.25rem;\n}\n\nh6 {\n font-size: 1rem;\n}\n\np {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nabbr[title] {\n text-decoration: underline dotted;\n cursor: help;\n text-decoration-skip-ink: none;\n}\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\nol,\nul {\n padding-left: 2rem;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: 700;\n}\n\ndd {\n margin-bottom: 0.5rem;\n margin-left: 0;\n}\n\nblockquote {\n margin: 0 0 1rem;\n}\n\nb,\nstrong {\n font-weight: bolder;\n}\n\nsmall {\n font-size: 0.875em;\n}\n\nmark {\n padding: 0.1875em;\n color: var(--bs-highlight-color);\n background-color: var(--bs-highlight-bg);\n}\n\nsub,\nsup {\n position: relative;\n font-size: 0.75em;\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\na {\n color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));\n text-decoration: underline;\n}\na:hover {\n --bs-link-color-rgb: var(--bs-link-hover-color-rgb);\n}\n\na:not([href]):not([class]), a:not([href]):not([class]):hover {\n color: inherit;\n text-decoration: none;\n}\n\npre,\ncode,\nkbd,\nsamp {\n font-family: var(--bs-font-monospace);\n font-size: 1em;\n}\n\npre {\n display: block;\n margin-top: 0;\n margin-bottom: 1rem;\n overflow: auto;\n font-size: 0.875em;\n}\npre code {\n font-size: inherit;\n color: inherit;\n word-break: normal;\n}\n\ncode {\n font-size: 0.875em;\n color: var(--bs-code-color);\n word-wrap: break-word;\n}\na > code {\n color: inherit;\n}\n\nkbd {\n padding: 0.1875rem 0.375rem;\n font-size: 0.875em;\n color: var(--bs-body-bg);\n background-color: var(--bs-body-color);\n border-radius: 0.25rem;\n}\nkbd kbd {\n padding: 0;\n font-size: 1em;\n}\n\nfigure {\n margin: 0 0 1rem;\n}\n\nimg,\nsvg {\n vertical-align: middle;\n}\n\ntable {\n caption-side: bottom;\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n color: var(--bs-secondary-color);\n text-align: left;\n}\n\nth {\n text-align: inherit;\n text-align: -webkit-match-parent;\n}\n\nthead,\ntbody,\ntfoot,\ntr,\ntd,\nth {\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n}\n\nlabel {\n display: inline-block;\n}\n\nbutton {\n border-radius: 0;\n}\n\nbutton:focus:not(:focus-visible) {\n outline: 0;\n}\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\nbutton,\nselect {\n text-transform: none;\n}\n\n[role=button] {\n cursor: pointer;\n}\n\nselect {\n word-wrap: normal;\n}\nselect:disabled {\n opacity: 1;\n}\n\n[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {\n display: none !important;\n}\n\nbutton,\n[type=button],\n[type=reset],\n[type=submit] {\n -webkit-appearance: button;\n}\nbutton:not(:disabled),\n[type=button]:not(:disabled),\n[type=reset]:not(:disabled),\n[type=submit]:not(:disabled) {\n cursor: pointer;\n}\n\n::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\n\ntextarea {\n resize: vertical;\n}\n\nfieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\n\nlegend {\n float: left;\n width: 100%;\n padding: 0;\n margin-bottom: 0.5rem;\n font-size: calc(1.275rem + 0.3vw);\n line-height: inherit;\n}\n@media (min-width: 1200px) {\n legend {\n font-size: 1.5rem;\n }\n}\nlegend + * {\n clear: left;\n}\n\n::-webkit-datetime-edit-fields-wrapper,\n::-webkit-datetime-edit-text,\n::-webkit-datetime-edit-minute,\n::-webkit-datetime-edit-hour-field,\n::-webkit-datetime-edit-day-field,\n::-webkit-datetime-edit-month-field,\n::-webkit-datetime-edit-year-field {\n padding: 0;\n}\n\n::-webkit-inner-spin-button {\n height: auto;\n}\n\n[type=search] {\n -webkit-appearance: textfield;\n outline-offset: -2px;\n}\n\n/* rtl:raw:\n[type=\"tel\"],\n[type=\"url\"],\n[type=\"email\"],\n[type=\"number\"] {\n direction: ltr;\n}\n*/\n::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n::-webkit-color-swatch-wrapper {\n padding: 0;\n}\n\n::file-selector-button {\n font: inherit;\n -webkit-appearance: button;\n}\n\noutput {\n display: inline-block;\n}\n\niframe {\n border: 0;\n}\n\nsummary {\n display: list-item;\n cursor: pointer;\n}\n\nprogress {\n vertical-align: baseline;\n}\n\n[hidden] {\n display: none !important;\n}\n\n/*# sourceMappingURL=bootstrap-reboot.css.map */\n","// scss-docs-start color-mode-mixin\n@mixin color-mode($mode: light, $root: false) {\n @if $color-mode-type == \"media-query\" {\n @if $root == true {\n @media (prefers-color-scheme: $mode) {\n :root {\n @content;\n }\n }\n } @else {\n @media (prefers-color-scheme: $mode) {\n @content;\n }\n }\n } @else {\n [data-bs-theme=\"#{$mode}\"] {\n @content;\n }\n }\n}\n// scss-docs-end color-mode-mixin\n","// stylelint-disable declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix\n\n\n// Reboot\n//\n// Normalization of HTML elements, manually forked from Normalize.css to remove\n// styles targeting irrelevant browsers while applying new styles.\n//\n// Normalize is licensed MIT. https://github.com/necolas/normalize.css\n\n\n// Document\n//\n// Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n\n// Root\n//\n// Ability to the value of the root font sizes, affecting the value of `rem`.\n// null by default, thus nothing is generated.\n\n:root {\n @if $font-size-root != null {\n @include font-size(var(--#{$prefix}root-font-size));\n }\n\n @if $enable-smooth-scroll {\n @media (prefers-reduced-motion: no-preference) {\n scroll-behavior: smooth;\n }\n }\n}\n\n\n// Body\n//\n// 1. Remove the margin in all browsers.\n// 2. As a best practice, apply a default `background-color`.\n// 3. Prevent adjustments of font size after orientation changes in iOS.\n// 4. Change the default tap highlight to be completely transparent in iOS.\n\n// scss-docs-start reboot-body-rules\nbody {\n margin: 0; // 1\n font-family: var(--#{$prefix}body-font-family);\n @include font-size(var(--#{$prefix}body-font-size));\n font-weight: var(--#{$prefix}body-font-weight);\n line-height: var(--#{$prefix}body-line-height);\n color: var(--#{$prefix}body-color);\n text-align: var(--#{$prefix}body-text-align);\n background-color: var(--#{$prefix}body-bg); // 2\n -webkit-text-size-adjust: 100%; // 3\n -webkit-tap-highlight-color: rgba($black, 0); // 4\n}\n// scss-docs-end reboot-body-rules\n\n\n// Content grouping\n//\n// 1. Reset Firefox's gray color\n\nhr {\n margin: $hr-margin-y 0;\n color: $hr-color; // 1\n border: 0;\n border-top: $hr-border-width solid $hr-border-color;\n opacity: $hr-opacity;\n}\n\n\n// Typography\n//\n// 1. Remove top margins from headings\n// By default, `

    `-`

    ` all receive top and bottom margins. We nuke the top\n// margin for easier control within type scales as it avoids margin collapsing.\n\n%heading {\n margin-top: 0; // 1\n margin-bottom: $headings-margin-bottom;\n font-family: $headings-font-family;\n font-style: $headings-font-style;\n font-weight: $headings-font-weight;\n line-height: $headings-line-height;\n color: var(--#{$prefix}heading-color);\n}\n\nh1 {\n @extend %heading;\n @include font-size($h1-font-size);\n}\n\nh2 {\n @extend %heading;\n @include font-size($h2-font-size);\n}\n\nh3 {\n @extend %heading;\n @include font-size($h3-font-size);\n}\n\nh4 {\n @extend %heading;\n @include font-size($h4-font-size);\n}\n\nh5 {\n @extend %heading;\n @include font-size($h5-font-size);\n}\n\nh6 {\n @extend %heading;\n @include font-size($h6-font-size);\n}\n\n\n// Reset margins on paragraphs\n//\n// Similarly, the top margin on `

    `s get reset. However, we also reset the\n// bottom margin to use `rem` units instead of `em`.\n\np {\n margin-top: 0;\n margin-bottom: $paragraph-margin-bottom;\n}\n\n\n// Abbreviations\n//\n// 1. Add the correct text decoration in Chrome, Edge, Opera, and Safari.\n// 2. Add explicit cursor to indicate changed behavior.\n// 3. Prevent the text-decoration to be skipped.\n\nabbr[title] {\n text-decoration: underline dotted; // 1\n cursor: help; // 2\n text-decoration-skip-ink: none; // 3\n}\n\n\n// Address\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\n\n// Lists\n\nol,\nul {\n padding-left: 2rem;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: $dt-font-weight;\n}\n\n// 1. Undo browser default\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0; // 1\n}\n\n\n// Blockquote\n\nblockquote {\n margin: 0 0 1rem;\n}\n\n\n// Strong\n//\n// Add the correct font weight in Chrome, Edge, and Safari\n\nb,\nstrong {\n font-weight: $font-weight-bolder;\n}\n\n\n// Small\n//\n// Add the correct font size in all browsers\n\nsmall {\n @include font-size($small-font-size);\n}\n\n\n// Mark\n\nmark {\n padding: $mark-padding;\n color: var(--#{$prefix}highlight-color);\n background-color: var(--#{$prefix}highlight-bg);\n}\n\n\n// Sub and Sup\n//\n// Prevent `sub` and `sup` elements from affecting the line height in\n// all browsers.\n\nsub,\nsup {\n position: relative;\n @include font-size($sub-sup-font-size);\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub { bottom: -.25em; }\nsup { top: -.5em; }\n\n\n// Links\n\na {\n color: rgba(var(--#{$prefix}link-color-rgb), var(--#{$prefix}link-opacity, 1));\n text-decoration: $link-decoration;\n\n &:hover {\n --#{$prefix}link-color-rgb: var(--#{$prefix}link-hover-color-rgb);\n text-decoration: $link-hover-decoration;\n }\n}\n\n// And undo these styles for placeholder links/named anchors (without href).\n// It would be more straightforward to just use a[href] in previous block, but that\n// causes specificity issues in many other styles that are too complex to fix.\n// See https://github.com/twbs/bootstrap/issues/19402\n\na:not([href]):not([class]) {\n &,\n &:hover {\n color: inherit;\n text-decoration: none;\n }\n}\n\n\n// Code\n\npre,\ncode,\nkbd,\nsamp {\n font-family: $font-family-code;\n @include font-size(1em); // Correct the odd `em` font sizing in all browsers.\n}\n\n// 1. Remove browser default top margin\n// 2. Reset browser default of `1em` to use `rem`s\n// 3. Don't allow content to break outside\n\npre {\n display: block;\n margin-top: 0; // 1\n margin-bottom: 1rem; // 2\n overflow: auto; // 3\n @include font-size($code-font-size);\n color: $pre-color;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n @include font-size(inherit);\n color: inherit;\n word-break: normal;\n }\n}\n\ncode {\n @include font-size($code-font-size);\n color: var(--#{$prefix}code-color);\n word-wrap: break-word;\n\n // Streamline the style when inside anchors to avoid broken underline and more\n a > & {\n color: inherit;\n }\n}\n\nkbd {\n padding: $kbd-padding-y $kbd-padding-x;\n @include font-size($kbd-font-size);\n color: $kbd-color;\n background-color: $kbd-bg;\n @include border-radius($border-radius-sm);\n\n kbd {\n padding: 0;\n @include font-size(1em);\n font-weight: $nested-kbd-font-weight;\n }\n}\n\n\n// Figures\n//\n// Apply a consistent margin strategy (matches our type styles).\n\nfigure {\n margin: 0 0 1rem;\n}\n\n\n// Images and content\n\nimg,\nsvg {\n vertical-align: middle;\n}\n\n\n// Tables\n//\n// Prevent double borders\n\ntable {\n caption-side: bottom;\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: $table-cell-padding-y;\n padding-bottom: $table-cell-padding-y;\n color: $table-caption-color;\n text-align: left;\n}\n\n// 1. Removes font-weight bold by inheriting\n// 2. Matches default `` alignment by inheriting `text-align`.\n// 3. Fix alignment for Safari\n\nth {\n font-weight: $table-th-font-weight; // 1\n text-align: inherit; // 2\n text-align: -webkit-match-parent; // 3\n}\n\nthead,\ntbody,\ntfoot,\ntr,\ntd,\nth {\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n}\n\n\n// Forms\n//\n// 1. Allow labels to use `margin` for spacing.\n\nlabel {\n display: inline-block; // 1\n}\n\n// Remove the default `border-radius` that macOS Chrome adds.\n// See https://github.com/twbs/bootstrap/issues/24093\n\nbutton {\n // stylelint-disable-next-line property-disallowed-list\n border-radius: 0;\n}\n\n// Explicitly remove focus outline in Chromium when it shouldn't be\n// visible (e.g. as result of mouse click or touch tap). It already\n// should be doing this automatically, but seems to currently be\n// confused and applies its very visible two-tone outline anyway.\n\nbutton:focus:not(:focus-visible) {\n outline: 0;\n}\n\n// 1. Remove the margin in Firefox and Safari\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0; // 1\n font-family: inherit;\n @include font-size(inherit);\n line-height: inherit;\n}\n\n// Remove the inheritance of text transform in Firefox\nbutton,\nselect {\n text-transform: none;\n}\n// Set the cursor for non-` -@*

    Current count: @State.Count

    *@ -@* *@ +

    Current count: @State.Count

    +

    diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pages/Counter.razor.cs b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pages/Counter.razor.cs index 1a7c328..8cf5cd0 100644 --- a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pages/Counter.razor.cs +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pages/Counter.razor.cs @@ -11,20 +11,14 @@ public partial class Counter : ComponentBase [Inject] IDispatcher _dispatcher { get; set; } = default!; [Inject] IPulseGlobalTracker _pulseGlobalTracker { get; set; } = default!; [Inject] IStatePulseRegistry _statePulseRegistry { get; set; } = default!; - [Inject] IStateAccessor _stateAccessor { get; set; } = default!; - + private int Update { get; set; } public CounterSingletonState Shared => _statePulse.StateOf(() => this, OnUpdate); - //public CounterState State => _statePulse.StateOf(() => this, OnUpdate); - private async Task OnUpdate() - { - Debugger.Break(); - StateHasChanged(); - } + public CounterState State => _statePulse.StateOf(() => this, OnUpdate); + private async Task OnUpdate() => await InvokeAsync(StateHasChanged); protected override void OnInitialized() { - //_stateAccessor.OnStateChangedNoDetails += (_, e)=> StateHasChanged(); } private async Task SingletonIncrease() { diff --git a/src/StatePulse.Net.Tests.Blazor/Areas/MyFeature/Pages/Page1.cshtml b/src/StatePulse.Net.Tests.Blazor/Areas/MyFeature/Pages/Page1.cshtml deleted file mode 100644 index 7fe28a6..0000000 --- a/src/StatePulse.Net.Tests.Blazor/Areas/MyFeature/Pages/Page1.cshtml +++ /dev/null @@ -1,13 +0,0 @@ -ο»Ώ@page -@model StatePulse.Net.Tests.Blazor.MyFeature.Pages.Page1Model - - - - - - - Page1 - - - - diff --git a/src/StatePulse.Net.Tests.Blazor/Areas/MyFeature/Pages/Page1.cshtml.cs b/src/StatePulse.Net.Tests.Blazor/Areas/MyFeature/Pages/Page1.cshtml.cs deleted file mode 100644 index e1f873d..0000000 --- a/src/StatePulse.Net.Tests.Blazor/Areas/MyFeature/Pages/Page1.cshtml.cs +++ /dev/null @@ -1,12 +0,0 @@ -ο»Ώusing Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; - -namespace StatePulse.Net.Tests.Blazor.MyFeature.Pages; - -public class Page1Model : PageModel -{ - public void OnGet() - { - - } -} diff --git a/src/StatePulse.Net.Tests.Blazor/StatePulse.Net.Tests.Blazor.csproj b/src/StatePulse.Net.Tests.Blazor/StatePulse.Net.Tests.Blazor.csproj deleted file mode 100644 index d4d84fd..0000000 --- a/src/StatePulse.Net.Tests.Blazor/StatePulse.Net.Tests.Blazor.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - net8.0 - enable - enable - true - - - - - - - - - From 08373cc5181d63a7cfdbd5476d8040c4a675cf63 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Sun, 21 Dec 2025 20:55:29 +0200 Subject: [PATCH 04/27] wip --- doc/docs/0.Versions.md | 8 ++- .../Configuration/ConfigureOptions.cs | 1 - src/StatePulse.NET/ServiceRegisterExt.cs | 52 ++++++++++--------- .../IDispatcherMiddlewareSingleton.cs | 4 ++ .../IEffectMiddlewareSingleton.cs | 11 ++++ .../IEffectSingleton.cs | 12 +++++ .../IEffectValidationSingleton.cs | 13 +++++ .../IReducerMiddlewareSingleton.cs | 11 ++++ .../IReducerSingleton.cs | 13 +++++ 9 files changed, 99 insertions(+), 26 deletions(-) create mode 100644 src/StatePulse.Net.Abstractions/IDispatcherMiddlewareSingleton.cs create mode 100644 src/StatePulse.Net.Abstractions/IEffectMiddlewareSingleton.cs create mode 100644 src/StatePulse.Net.Abstractions/IEffectSingleton.cs create mode 100644 src/StatePulse.Net.Abstractions/IEffectValidationSingleton.cs create mode 100644 src/StatePulse.Net.Abstractions/IReducerMiddlewareSingleton.cs create mode 100644 src/StatePulse.Net.Abstractions/IReducerSingleton.cs diff --git a/doc/docs/0.Versions.md b/doc/docs/0.Versions.md index 2a52abc..4549aad 100644 --- a/doc/docs/0.Versions.md +++ b/doc/docs/0.Versions.md @@ -6,7 +6,6 @@ sidebar_position: 0 ## πŸ“¦ v2.0.0 ### ✨ BREAKING CHANGES -### ✨ BREAKING CHANGES - **Interface signatures have changed.** Core interface updates may break plugin‑based systems if the core updates while plugins do not. @@ -21,6 +20,12 @@ sidebar_position: 0 All effects now run as a batch, followed by a single AfterEffect phase. Middleware can still be awaited before the BeforeEffect phase and after the AfterEffect phase. +- **Actions can never be singleton.** + Action are essentially data contract and should remain at the scope level which in blazor server case is circuit bound. + +- **Effects, Reducers, Middleware, EffectValidators no long transient** + Transient lifetime for those is unecessary as none of them should ever hold state of their own therefore they act like static method filled with logic alone... let's eliminate transient overhead and put scoped as default and singleton with the singleton interfaces. + ### ✨ New Features - **βš™οΈ Enhanced Configuration Options** - New global configuration properties: - `DispatchOrderBehavior` - Set default ordering (EffectsFirst/ReducersFirst) @@ -39,6 +44,7 @@ sidebar_position: 0 - `PulseTrackingModel` - Clear option for the tracking model! Either Thread-Safe (`Default`) or Single Threaded Fast Application... WASM/Blazor Server. - `GlobalTrackerLifetime` - Define clearly lifetime scope for the Global Tracker singleton or scoped. `BlazorServer`, `WASM`, `Scoped` (Default) or `Singleton`. - `IStateFeatureSingleton` - Define a singleton state across your app... not useful in WASM but very useful in Blazor Server... where one can share the state across client each client run their own action but the state update spread across all circuits. +- `IReducerSingleton`, `IEffectSingleton`, `IEffectValidationSingleton`, `IEffectMiddlewareSingleton`, `IReducerMiddlewareSingleton` - Define a singleton for blazor server cross circuit logic. ### 🐞 Fixes - Fixed Various Warnings diff --git a/src/StatePulse.NET/Configuration/ConfigureOptions.cs b/src/StatePulse.NET/Configuration/ConfigureOptions.cs index b416ef5..6c593fb 100644 --- a/src/StatePulse.NET/Configuration/ConfigureOptions.cs +++ b/src/StatePulse.NET/Configuration/ConfigureOptions.cs @@ -6,7 +6,6 @@ public class ConfigureOptions ///

    /// Scoped on WASM = Singleton, Singleton on Blazor Server = Chaos Data Leakage /// - public Lifetime ServiceLifetime { get; set; } = Lifetime.Scoped; public MiddlewareEffectBehavior MiddlewareEffectBehavior { get; set; } = MiddlewareEffectBehavior.PerGroupEffects; public MiddlewareTaskBehavior MiddlewareTaskBehavior { get; set; } = MiddlewareTaskBehavior.DoNotAwait; public DispatchEffectBehavior DispatchEffectBehavior { get; set; } = DispatchEffectBehavior.Parallel; diff --git a/src/StatePulse.NET/ServiceRegisterExt.cs b/src/StatePulse.NET/ServiceRegisterExt.cs index cb8cb24..6351902 100644 --- a/src/StatePulse.NET/ServiceRegisterExt.cs +++ b/src/StatePulse.NET/ServiceRegisterExt.cs @@ -47,8 +47,13 @@ public static IServiceCollection AddStatePulseEffect(this IServ private static IServiceCollection AddStatePulseEffect(this IServiceCollection services, Type iFace, Type implementation) { if (services.IsImplementationRegistered(iFace, implementation)) return services; + bool isSingletonFeature = implementation.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEffectSingleton<>)); + + if(!isSingletonFeature) + services.AddScoped(iFace, implementation); + else + services.AddSingleton(iFace, implementation); - services.AddTransient(iFace, implementation); Registry.RegisterEffect(iFace, implementation); return services; } @@ -67,28 +72,18 @@ private static IServiceCollection AddStatePulseReducer(this IServiceCollection s { if (services.IsReducerRegistered(iFace)) return services; - - services.AddTransient(iFace, implementation); - Registry.RegisterReducer(iFace, implementation); + bool isSingleton = implementation.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IReducerSingleton<,>)); + if (!isSingleton) + services.AddScoped(iFace, implementation); + else + services.AddSingleton(iFace, implementation); + Registry.RegisterReducer(iFace, implementation); return services; } public static IServiceCollection AddStatePulseStateFeature(this IServiceCollection services) where TImplementation : IStateFeature => services.AddStatePulseStateFeature(typeof(TImplementation)); - //private static IServiceCollection AddStatePulseStateFeature(this IServiceCollection services, Type implementation) - //{ - // var accessorType = typeof(IStateAccessor<>).MakeGenericType(implementation); - // var accessorImplementationType = typeof(StateAccessor<>).MakeGenericType(implementation); - - // if (services.IsStateAccessorRegistered(accessorImplementationType)) return services; - // if (ConfigureOptions.ServiceLifetime == Lifetime.Scoped) - // services.AddScoped(accessorType, accessorImplementationType); - // else - // services.AddSingleton(accessorType, accessorImplementationType); - - // Registry.RegisterState(implementation); - // return services; - //} + private static IServiceCollection AddStatePulseStateFeature(this IServiceCollection services, Type implementation) { var accessorType = typeof(IStateAccessor<>).MakeGenericType(implementation); @@ -125,7 +120,11 @@ private static IServiceCollection AddStatePulseEffectValidator(this IServiceColl { if (services.IsEffectValidatorImplementationRegistered(implementation)) return services; - services.AddTransient(iFace, implementation); + bool isSingleton = implementation.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEffectValidator<,>)); + if(isSingleton) + services.AddScoped(iFace, implementation); + else + services.AddSingleton(iFace, implementation); Registry.RegisterEffectValidator(iFace, implementation); return services; } @@ -140,10 +139,8 @@ private static IServiceCollection AddStatePulseAction(this IServiceCollection se var dispatchTracker = typeof(DispatchTracker<>).MakeGenericType(implementation); if (services.IsDispatchTrackerRegistered(dispatchTracker)) return services; Registry.RegisterAction(implementation); - if (ConfigureOptions.ServiceLifetime == Lifetime.Scoped) - services.AddScoped(dispatchTrackerIface, dispatchTracker); - else - services.AddSingleton(dispatchTrackerIface, dispatchTracker); + services.AddScoped(dispatchTrackerIface, dispatchTracker); + return services; } @@ -186,7 +183,14 @@ private static void ScanStatePulseAssemblies(this IServiceCollection services, p (iface == effectMiddlewareType || iface == reducerMiddlewareType || iface == dispatchMiddlewareType)) { if (services.IsImplementationRegistered(type, iface)) continue; - services.AddTransient(iface, type); + bool isSingletonEffectMiddleware= typeof(IEffectMiddlewareSingleton).IsAssignableFrom(type); + bool isSingletonReducerMiddleware= typeof(IReducerMiddleware).IsAssignableFrom(type); + bool isSingletonDispatcherMiddleware= typeof(IDispatcherMiddlewareSingleton).IsAssignableFrom(type); + bool isSingleton = isSingletonEffectMiddleware || isSingletonReducerMiddleware || isSingletonDispatcherMiddleware; + if (!isSingleton) + services.AddScoped(iface, type); + else + services.AddSingleton(iface, type); continue; } diff --git a/src/StatePulse.Net.Abstractions/IDispatcherMiddlewareSingleton.cs b/src/StatePulse.Net.Abstractions/IDispatcherMiddlewareSingleton.cs new file mode 100644 index 0000000..ecb672d --- /dev/null +++ b/src/StatePulse.Net.Abstractions/IDispatcherMiddlewareSingleton.cs @@ -0,0 +1,4 @@ +ο»Ώnamespace StatePulse.Net; +public interface IDispatcherMiddlewareSingleton: IDispatcherMiddleware +{ +} diff --git a/src/StatePulse.Net.Abstractions/IEffectMiddlewareSingleton.cs b/src/StatePulse.Net.Abstractions/IEffectMiddlewareSingleton.cs new file mode 100644 index 0000000..9234b30 --- /dev/null +++ b/src/StatePulse.Net.Abstractions/IEffectMiddlewareSingleton.cs @@ -0,0 +1,11 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StatePulse.Net; + +public interface IEffectMiddlewareSingleton : IEffectMiddleware +{ +} diff --git a/src/StatePulse.Net.Abstractions/IEffectSingleton.cs b/src/StatePulse.Net.Abstractions/IEffectSingleton.cs new file mode 100644 index 0000000..7c19df9 --- /dev/null +++ b/src/StatePulse.Net.Abstractions/IEffectSingleton.cs @@ -0,0 +1,12 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StatePulse.Net; + +public interface IEffectSingleton : IEffect + where TAction : IAction +{ +} diff --git a/src/StatePulse.Net.Abstractions/IEffectValidationSingleton.cs b/src/StatePulse.Net.Abstractions/IEffectValidationSingleton.cs new file mode 100644 index 0000000..726d82f --- /dev/null +++ b/src/StatePulse.Net.Abstractions/IEffectValidationSingleton.cs @@ -0,0 +1,13 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StatePulse.Net; + +internal interface IEffectValidationSingleton : IEffectValidator + where TAction : IAction + where TEffect : IEffect +{ +} diff --git a/src/StatePulse.Net.Abstractions/IReducerMiddlewareSingleton.cs b/src/StatePulse.Net.Abstractions/IReducerMiddlewareSingleton.cs new file mode 100644 index 0000000..1a603b1 --- /dev/null +++ b/src/StatePulse.Net.Abstractions/IReducerMiddlewareSingleton.cs @@ -0,0 +1,11 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StatePulse.Net; + +public interface IReducerMiddlewareSingleton : IReducerMiddleware +{ +} diff --git a/src/StatePulse.Net.Abstractions/IReducerSingleton.cs b/src/StatePulse.Net.Abstractions/IReducerSingleton.cs new file mode 100644 index 0000000..46d85d0 --- /dev/null +++ b/src/StatePulse.Net.Abstractions/IReducerSingleton.cs @@ -0,0 +1,13 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StatePulse.Net; + +public interface IReducerSingleton : IReducer + where TState : IStateFeature + where TAction : IAction +{ +} From 1cde7a450d3c2fd99f9edf21cd7c17e824169366 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Wed, 31 Dec 2025 09:36:39 +0200 Subject: [PATCH 05/27] - ConfigureOptions.ScanAssemblies type is now Assembly[]. --- .../Configuration/ConfigureOptions.cs | 4 ++- src/StatePulse.NET/ServiceRegisterExt.cs | 30 +++++++++---------- src/StatePulse.NET/StatePulse.NET.csproj | 4 +-- .../StatePulse.Net.Abstractions.csproj | 4 +-- .../Program.cs | 10 +++---- 5 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/StatePulse.NET/Configuration/ConfigureOptions.cs b/src/StatePulse.NET/Configuration/ConfigureOptions.cs index 6c593fb..fb73299 100644 --- a/src/StatePulse.NET/Configuration/ConfigureOptions.cs +++ b/src/StatePulse.NET/Configuration/ConfigureOptions.cs @@ -1,6 +1,8 @@ ο»Ώusing StatePulse.Net.Engine.Exceptions; +using System.Reflection; namespace StatePulse.Net.Configuration; + public class ConfigureOptions { /// @@ -12,7 +14,7 @@ public class ConfigureOptions public DispatchEffectExecutionBehavior DispatchEffectExecutionBehavior { get; set; } = DispatchEffectExecutionBehavior.YieldAndFire; public DispatchOrdering DispatchOrderBehavior { get; set; } = DispatchOrdering.ReducersFirst; public PulseTrackingModel PulseTrackingPerformance { get; set; } = PulseTrackingModel.ThreadSafe; - public Type[] ScanAssemblies { get; set; } = new Type[] { }; + public Assembly[] ScanAssemblies { get; set; } = new Assembly[] { }; public void ValidateConfiguration() { diff --git a/src/StatePulse.NET/ServiceRegisterExt.cs b/src/StatePulse.NET/ServiceRegisterExt.cs index 6351902..709c712 100644 --- a/src/StatePulse.NET/ServiceRegisterExt.cs +++ b/src/StatePulse.NET/ServiceRegisterExt.cs @@ -2,6 +2,7 @@ using StatePulse.Net.Configuration; using StatePulse.Net.Engine; using StatePulse.Net.Engine.Implementations; +using System.Reflection; namespace StatePulse.Net; @@ -22,13 +23,12 @@ public static IServiceCollection AddStatePulseServices(this IServiceCollection s bool isSingleThreadModel = ConfigureOptions.PulseTrackingPerformance == PulseTrackingModel.SingleThreadFast || ConfigureOptions.PulseTrackingPerformance == PulseTrackingModel.BlazorWebAssemblyFast; if (isSingleThreadModel) - services.AddTransient(); + services.AddTransient(); else - services.AddTransient(); + services.AddTransient(); services.AddSingleton(Registry); - if (ConfigureOptions.ScanAssemblies.Any()) - services.ScanStatePulseAssemblies(ConfigureOptions.ScanAssemblies); + services.ScanStatePulseAssemblies(ConfigureOptions.ScanAssemblies); return services; } @@ -49,9 +49,9 @@ private static IServiceCollection AddStatePulseEffect(this IServiceCollection se if (services.IsImplementationRegistered(iFace, implementation)) return services; bool isSingletonFeature = implementation.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEffectSingleton<>)); - if(!isSingletonFeature) + if (!isSingletonFeature) services.AddScoped(iFace, implementation); - else + else services.AddSingleton(iFace, implementation); Registry.RegisterEffect(iFace, implementation); @@ -74,10 +74,10 @@ private static IServiceCollection AddStatePulseReducer(this IServiceCollection s if (services.IsReducerRegistered(iFace)) return services; bool isSingleton = implementation.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IReducerSingleton<,>)); if (!isSingleton) - services.AddScoped(iFace, implementation); + services.AddScoped(iFace, implementation); else - services.AddSingleton(iFace, implementation); - Registry.RegisterReducer(iFace, implementation); + services.AddSingleton(iFace, implementation); + Registry.RegisterReducer(iFace, implementation); return services; } public static IServiceCollection AddStatePulseStateFeature(this IServiceCollection services) @@ -121,7 +121,7 @@ private static IServiceCollection AddStatePulseEffectValidator(this IServiceColl { if (services.IsEffectValidatorImplementationRegistered(implementation)) return services; bool isSingleton = implementation.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEffectValidator<,>)); - if(isSingleton) + if (isSingleton) services.AddScoped(iFace, implementation); else services.AddSingleton(iFace, implementation); @@ -150,7 +150,7 @@ private static IServiceCollection AddStatePulseAction(this IServiceCollection se /// /// /// - private static void ScanStatePulseAssemblies(this IServiceCollection services, params Type[] assemblies) + private static void ScanStatePulseAssemblies(this IServiceCollection services, params Assembly[] assemblies) { if (_scanned) return; _scanned = true; @@ -167,7 +167,7 @@ private static void ScanStatePulseAssemblies(this IServiceCollection services, p foreach (var assembly in assemblies) { - var types = assembly.Assembly.GetTypes(); + var types = assembly.GetTypes(); foreach (var type in types) { @@ -183,9 +183,9 @@ private static void ScanStatePulseAssemblies(this IServiceCollection services, p (iface == effectMiddlewareType || iface == reducerMiddlewareType || iface == dispatchMiddlewareType)) { if (services.IsImplementationRegistered(type, iface)) continue; - bool isSingletonEffectMiddleware= typeof(IEffectMiddlewareSingleton).IsAssignableFrom(type); - bool isSingletonReducerMiddleware= typeof(IReducerMiddleware).IsAssignableFrom(type); - bool isSingletonDispatcherMiddleware= typeof(IDispatcherMiddlewareSingleton).IsAssignableFrom(type); + bool isSingletonEffectMiddleware = typeof(IEffectMiddlewareSingleton).IsAssignableFrom(type); + bool isSingletonReducerMiddleware = typeof(IReducerMiddleware).IsAssignableFrom(type); + bool isSingletonDispatcherMiddleware = typeof(IDispatcherMiddlewareSingleton).IsAssignableFrom(type); bool isSingleton = isSingletonEffectMiddleware || isSingletonReducerMiddleware || isSingletonDispatcherMiddleware; if (!isSingleton) services.AddScoped(iface, type); diff --git a/src/StatePulse.NET/StatePulse.NET.csproj b/src/StatePulse.NET/StatePulse.NET.csproj index bb47ad1..dacf838 100644 --- a/src/StatePulse.NET/StatePulse.NET.csproj +++ b/src/StatePulse.NET/StatePulse.NET.csproj @@ -11,11 +11,11 @@ True 0.Versions.md https://github.com/mshimshon/StatePulse.NET - Maksim Shimshon Β© 2025 + Maksim Shimshon Β© 2026 StatePulse.NET Maksim Shimshon - 2.0.0 + 2.0.1 LICENSE True StatePulse.NET enables fast, consistent state/action dispatch with optional tracking and anti-duplicate flow control. It supports ordered chaining when needed, while maintaining high-performance fire-and-forget behavior for general use cases. diff --git a/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj b/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj index b171a89..3544b2e 100644 --- a/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj +++ b/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj @@ -11,11 +11,11 @@ True 0.Versions.md https://github.com/mshimshon/StatePulse.NET - Maksim Shimshon Β© 2025 + Maksim Shimshon Β© 2026 StatePulse.Net.Abstractions Maksim Shimshon - 2.0.0 + 2.0.1 LICENSE True StatePulse.NET enables fast, consistent state/action dispatch with optional tracking and anti-duplicate flow control. It supports ordered chaining when needed, while maintaining high-performance fire-and-forget behavior for general use cases. diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Program.cs b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Program.cs index fcb8996..97ac450 100644 --- a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Program.cs +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Program.cs @@ -1,6 +1,5 @@ -using StatePulse.Net.BlazorServerTest.Client.Pages; -using StatePulse.Net.BlazorServerTest.Components; using StatePulse.Net; +using StatePulse.Net.BlazorServerTest.Components; using StatePulse.Net.Configuration; var builder = WebApplication.CreateBuilder(args); @@ -9,12 +8,13 @@ .AddInteractiveServerComponents() .AddInteractiveWebAssemblyComponents(); -builder.Services.AddStatePulseServices(c => { +builder.Services.AddStatePulseServices(c => +{ c.PulseTrackingPerformance = PulseTrackingModel.BlazorServerSafe; c.DispatchEffectExecutionBehavior = DispatchEffectExecutionBehavior.YieldAndFire; c.DispatchEffectBehavior = DispatchEffectBehavior.Sequential; - - c.ScanAssemblies = [typeof(Program), typeof(StatePulse.Net.BlazorServerTest.Client._Imports)]; + + c.ScanAssemblies = [typeof(Program).Assembly, typeof(StatePulse.Net.BlazorServerTest.Client._Imports).Assembly]; }); var app = builder.Build(); From 6cad8f7555bc0e1c363fad2c118a53d5f4e92fb7 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Wed, 31 Dec 2025 09:39:01 +0200 Subject: [PATCH 06/27] updated version log --- doc/docs/0.Versions.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/docs/0.Versions.md b/doc/docs/0.Versions.md index 4549aad..64b596a 100644 --- a/doc/docs/0.Versions.md +++ b/doc/docs/0.Versions.md @@ -26,6 +26,9 @@ sidebar_position: 0 - **Effects, Reducers, Middleware, EffectValidators no long transient** Transient lifetime for those is unecessary as none of them should ever hold state of their own therefore they act like static method filled with logic alone... let's eliminate transient overhead and put scoped as default and singleton with the singleton interfaces. +- **Configuration Scan Assembly Type Changed** + The property `ConfigureOptions.ScanAssemblies` is now taking a `Assembly[]` instead of `Type[]`. + ### ✨ New Features - **βš™οΈ Enhanced Configuration Options** - New global configuration properties: - `DispatchOrderBehavior` - Set default ordering (EffectsFirst/ReducersFirst) From e6ce5a672ffc821941aabe4e0922a6a82aadfb18 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Sat, 3 Jan 2026 10:55:01 +0200 Subject: [PATCH 07/27] Updated Deploy.yml --- .github/workflows/deploy.yml | 6 ++++++ src/StatePulse.NET.sln | 2 ++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 6119b99..4a0ee50 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -13,6 +13,9 @@ concurrency: jobs: deploy-abstraction: runs-on: ubuntu-latest + permissions: + id-token: write + contents: read if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'workflow_run' && @@ -52,6 +55,9 @@ jobs: deploy-core: needs: deploy-abstraction runs-on: ubuntu-latest + permissions: + id-token: write + contents: read if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'workflow_run' && diff --git a/src/StatePulse.NET.sln b/src/StatePulse.NET.sln index 7cc9d2c..e3f119f 100644 --- a/src/StatePulse.NET.sln +++ b/src/StatePulse.NET.sln @@ -6,6 +6,8 @@ MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig + ..\.github\workflows\ci.yml = ..\.github\workflows\ci.yml + ..\.github\workflows\deploy.yml = ..\.github\workflows\deploy.yml ..\README.md = ..\README.md EndProjectSection EndProject From 12fdff17f52af94ab28ae1a967cd5e76ecfe8289 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Sat, 3 Jan 2026 15:01:38 +0200 Subject: [PATCH 08/27] Removed Analyzer, just cant make it work --- .github/workflows/deploy.yml | 25 +++- src/StatePulse.NET.sln | 6 - src/StatePulse.NET/StatePulse.NET.csproj | 9 -- .../StatePulse.Net.Abstractions.csproj | 9 +- .../Analyzer1Analyzer.cs | 55 ++++++++ .../FactSecondParamAnalyzer.cs | 16 ++- .../Resources.Designer.cs | 105 ++++++++++++++ src/StatePulse.Net.Analyzers/Resources.resx | 132 ++++++++++++++++++ .../StatePulse.Net.Analyzers.csproj | 59 +++----- .../Pages/Counter.razor.cs | 5 +- ...tePulse.Net.BlazorServerTest.Client.csproj | 4 +- 11 files changed, 352 insertions(+), 73 deletions(-) create mode 100644 src/StatePulse.Net.Analyzers/Analyzer1Analyzer.cs create mode 100644 src/StatePulse.Net.Analyzers/Resources.Designer.cs create mode 100644 src/StatePulse.Net.Analyzers/Resources.resx diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 4a0ee50..1f57e63 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -50,8 +50,29 @@ jobs: - name: Push StatePulse.Net.Abstractions run: dotnet nuget push ./artifacts/StatePulse.Net.Abstractions.*.nupkg --api-key ${{steps.login.outputs.NUGET_API_KEY}} --source https://api.nuget.org/v3/index.json --skip-duplicate - - name: Wait for NuGet indexing - run: sleep 120 + + - name: Get package version + id: get_version + run: | + FILE=$(ls ./artifacts/*.nupkg | head -n1) + VERSION=$(basename "$FILE" | sed -E 's/MaksimShimshon.RestCountries\.([0-9]+\.[0-9]+\.[0-9]+)\.nupkg/\1/') + echo "version=$VERSION" >> $GITHUB_OUTPUT + + - name: Wait for NuGet availability + uses: nick-invision/retry@v2 + with: + timeout_minutes: 10 + retry_wait_seconds: 10 + max_attempts: 60 + command: | + body=$(curl -s --compressed \ + -H "Accept: application/json" \ + "https://api.nuget.org/v3/registration5-gz-semver2/statepulse.net.abstractions/${{ steps.get_version.outputs.version }}.json" \ + | tr -d '\000') + + echo "$body" | head -c 5 | grep -q " - - - - - + + - - False - - + diff --git a/src/StatePulse.Net.Analyzers/Analyzer1Analyzer.cs b/src/StatePulse.Net.Analyzers/Analyzer1Analyzer.cs new file mode 100644 index 0000000..182fcff --- /dev/null +++ b/src/StatePulse.Net.Analyzers/Analyzer1Analyzer.cs @@ -0,0 +1,55 @@ +ο»Ώusing Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Immutable; + +namespace Analyzer1 +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public sealed class CapitalClassNameAnalyzer : DiagnosticAnalyzer + { + public const string DiagnosticId = "DEMO001"; + + private static readonly DiagnosticDescriptor Rule = + new DiagnosticDescriptor( + DiagnosticId, + "Class name starts with a capital letter", + "Class name '{0}' starts with a capital letter", + "Naming", + DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics + => ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + + context.RegisterSyntaxNodeAction( + AnalyzeClass, + SyntaxKind.ClassDeclaration); + } + + private static void AnalyzeClass(SyntaxNodeAnalysisContext context) + { + var classDecl = (ClassDeclarationSyntax)context.Node; + var name = classDecl.Identifier.Text; + + if (string.IsNullOrEmpty(name)) + return; + + if (char.IsUpper(name[0])) + { + var diagnostic = Diagnostic.Create( + Rule, + classDecl.Identifier.GetLocation(), + name); + + context.ReportDiagnostic(diagnostic); + } + } + } +} diff --git a/src/StatePulse.Net.Analyzers/FactSecondParamAnalyzer.cs b/src/StatePulse.Net.Analyzers/FactSecondParamAnalyzer.cs index ad0dfcf..a5715bb 100644 --- a/src/StatePulse.Net.Analyzers/FactSecondParamAnalyzer.cs +++ b/src/StatePulse.Net.Analyzers/FactSecondParamAnalyzer.cs @@ -31,18 +31,25 @@ public class FactSecondParamAnalyzer : DiagnosticAnalyzer public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); - context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + // Analyze generated code (Blazor .razor -> generated C#) and report diagnostics there + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); context.RegisterSyntaxNodeAction(AnalyzeInvocation, SyntaxKind.InvocationExpression); } private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context) { - if (context.Node is not InvocationExpressionSyntax invocation) + var invocation = context.Node as InvocationExpressionSyntax; + if (invocation == null) + { return; + } var symbolInfo = context.SemanticModel.GetSymbolInfo(invocation.Expression, context.CancellationToken); - if (symbolInfo.Symbol is not IMethodSymbol methodSymbol) + var methodSymbol = symbolInfo.Symbol as IMethodSymbol; + if (methodSymbol == null) + { return; + } // Ensure it's a method named StateOf if (methodSymbol.Name != "StateOf") @@ -55,6 +62,9 @@ private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context) return; // Check argument count + if (invocation.ArgumentList == null) + return; + var args = invocation.ArgumentList.Arguments; if (args.Count < 2) return; diff --git a/src/StatePulse.Net.Analyzers/Resources.Designer.cs b/src/StatePulse.Net.Analyzers/Resources.Designer.cs new file mode 100644 index 0000000..6b0e73d --- /dev/null +++ b/src/StatePulse.Net.Analyzers/Resources.Designer.cs @@ -0,0 +1,105 @@ +ο»Ώ//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +namespace Analyzer1 +{ + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if (object.ReferenceEquals(resourceMan, null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Analyzer1.Resources", typeof(Resources).GetTypeInfo().Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Type names should be all uppercase.. + /// + internal static string AnalyzerDescription + { + get + { + return ResourceManager.GetString("AnalyzerDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type name '{0}' contains lowercase letters. + /// + internal static string AnalyzerMessageFormat + { + get + { + return ResourceManager.GetString("AnalyzerMessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type name contains lowercase letters. + /// + internal static string AnalyzerTitle + { + get + { + return ResourceManager.GetString("AnalyzerTitle", resourceCulture); + } + } + } +} diff --git a/src/StatePulse.Net.Analyzers/Resources.resx b/src/StatePulse.Net.Analyzers/Resources.resx new file mode 100644 index 0000000..410edcc --- /dev/null +++ b/src/StatePulse.Net.Analyzers/Resources.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Type names should be all uppercase. + An optional longer localizable description of the diagnostic. + + + Type name '{0}' contains lowercase letters + The format-able message the diagnostic displays. + + + Type name contains lowercase letters + The title of the diagnostic. + + \ No newline at end of file diff --git a/src/StatePulse.Net.Analyzers/StatePulse.Net.Analyzers.csproj b/src/StatePulse.Net.Analyzers/StatePulse.Net.Analyzers.csproj index f8d45ee..31e9d61 100644 --- a/src/StatePulse.Net.Analyzers/StatePulse.Net.Analyzers.csproj +++ b/src/StatePulse.Net.Analyzers/StatePulse.Net.Analyzers.csproj @@ -1,55 +1,28 @@ -ο»Ώ + + + + netstandard2.0 + true + true + + StatePulse.Net.Analyzers + - - netstandard2.0 - 12.0 - enable - enable - enable - StatePulse.Net.Analyzers - StatePulse.Net.Analyzers - StatePulse.Net.Analyzers - True - README.md - https://github.com/mshimshon/StatePulse.NET - Maksim Shimshon Β© 2025 - StatePulse.Net.Analyzers - Maksim Shimshon - 1.0.0 - LICENSE - True - StatePulse.NET enables fast, consistent state/action dispatch with optional tracking and anti-duplicate flow control. It supports ordered chaining when needed, while maintaining high-performance fire-and-forget behavior for general use cases. - icon.png - true - blazor;state management;flux;dotnet;redux;components;webassembly - Analyzer - True - - - True - \ - - - True - \ - - - True - \ - + + + - - - - + + + - + diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pages/Counter.razor.cs b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pages/Counter.razor.cs index 8cf5cd0..bd3cc29 100644 --- a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pages/Counter.razor.cs +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pages/Counter.razor.cs @@ -1,7 +1,6 @@ ο»Ώusing Microsoft.AspNetCore.Components; using StatePulse.Net.BlazorServerTest.Client.Pulses.Counter.Action; using StatePulse.Net.BlazorServerTest.Client.Pulses.Counter.Stores; -using System.Diagnostics; namespace StatePulse.Net.BlazorServerTest.Client.Pages; @@ -12,9 +11,9 @@ public partial class Counter : ComponentBase [Inject] IPulseGlobalTracker _pulseGlobalTracker { get; set; } = default!; [Inject] IStatePulseRegistry _statePulseRegistry { get; set; } = default!; private int Update { get; set; } - + public CounterSingletonState Shared => _statePulse.StateOf(() => this, OnUpdate); - public CounterState State => _statePulse.StateOf(() => this, OnUpdate); + public CounterState State => _statePulse.StateOf(() => this, () => OnUpdate()); private async Task OnUpdate() => await InvokeAsync(StateHasChanged); protected override void OnInitialized() diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/StatePulse.Net.BlazorServerTest.Client.csproj b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/StatePulse.Net.BlazorServerTest.Client.csproj index 6e8e962..d8f7eba 100644 --- a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/StatePulse.Net.BlazorServerTest.Client.csproj +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/StatePulse.Net.BlazorServerTest.Client.csproj @@ -1,4 +1,4 @@ - +ο»Ώ net10.0 @@ -7,6 +7,7 @@ true Default true + true @@ -18,7 +19,6 @@ - From 9d5235a54ff4d8dcd39e6347c602f4be060eab57 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Sat, 3 Jan 2026 16:30:38 +0200 Subject: [PATCH 09/27] wip --- src/StatePulse.NET.sln | 6 ++ src/StatePulse.Net.Benchmark/Program.cs | 16 +++ .../Pulses/Actions/IncreaseCounterAction.cs | 5 + .../Pulses/Actions/IncreasedCounterAction.cs | 6 ++ .../Pulses/Effects/IncreaseCounterEffect.cs | 22 +++++ .../Reducers/IncreasedCounterReducer.cs | 18 ++++ .../Pulses/States/CounterState.cs | 14 +++ .../StatePulse.Net.Benchmark.csproj | 40 ++++++++ src/StatePulse.Net.Benchmark/Tests.cs | 99 +++++++++++++++++++ 9 files changed, 226 insertions(+) create mode 100644 src/StatePulse.Net.Benchmark/Program.cs create mode 100644 src/StatePulse.Net.Benchmark/Pulses/Actions/IncreaseCounterAction.cs create mode 100644 src/StatePulse.Net.Benchmark/Pulses/Actions/IncreasedCounterAction.cs create mode 100644 src/StatePulse.Net.Benchmark/Pulses/Effects/IncreaseCounterEffect.cs create mode 100644 src/StatePulse.Net.Benchmark/Pulses/Reducers/IncreasedCounterReducer.cs create mode 100644 src/StatePulse.Net.Benchmark/Pulses/States/CounterState.cs create mode 100644 src/StatePulse.Net.Benchmark/StatePulse.Net.Benchmark.csproj create mode 100644 src/StatePulse.Net.Benchmark/Tests.cs diff --git a/src/StatePulse.NET.sln b/src/StatePulse.NET.sln index d5e5fd8..db4adef 100644 --- a/src/StatePulse.NET.sln +++ b/src/StatePulse.NET.sln @@ -21,6 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatePulse.Net.BlazorServer EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatePulse.Net.BlazorServerTest.Client", "StatePulse.Net.BlazorServerTest\StatePulse.Net.BlazorServerTest.Client\StatePulse.Net.BlazorServerTest.Client.csproj", "{DCB8495F-3B22-4797-A027-C61850527E2B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatePulse.Net.Benchmark", "StatePulse.Net.Benchmark\StatePulse.Net.Benchmark.csproj", "{1608523F-D5DA-4C8D-AF14-F89565929876}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -47,6 +49,10 @@ Global {DCB8495F-3B22-4797-A027-C61850527E2B}.Debug|Any CPU.Build.0 = Debug|Any CPU {DCB8495F-3B22-4797-A027-C61850527E2B}.Release|Any CPU.ActiveCfg = Release|Any CPU {DCB8495F-3B22-4797-A027-C61850527E2B}.Release|Any CPU.Build.0 = Release|Any CPU + {1608523F-D5DA-4C8D-AF14-F89565929876}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1608523F-D5DA-4C8D-AF14-F89565929876}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1608523F-D5DA-4C8D-AF14-F89565929876}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1608523F-D5DA-4C8D-AF14-F89565929876}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/StatePulse.Net.Benchmark/Program.cs b/src/StatePulse.Net.Benchmark/Program.cs new file mode 100644 index 0000000..4defee8 --- /dev/null +++ b/src/StatePulse.Net.Benchmark/Program.cs @@ -0,0 +1,16 @@ +ο»Ώusing BenchmarkDotNet.Running; +using StatePulse.Net.Benchmark; + +namespace Medihater.Benchmark; + +public static class Program +{ + public static void Main(string[] args) + { + BenchmarkRunner.Run(); + + //var t = new Tests(); + //t.StatePulse_Dispatch(); + //t.Flux_Dispatch(); + } +} diff --git a/src/StatePulse.Net.Benchmark/Pulses/Actions/IncreaseCounterAction.cs b/src/StatePulse.Net.Benchmark/Pulses/Actions/IncreaseCounterAction.cs new file mode 100644 index 0000000..c2bd5bf --- /dev/null +++ b/src/StatePulse.Net.Benchmark/Pulses/Actions/IncreaseCounterAction.cs @@ -0,0 +1,5 @@ +ο»Ώnamespace StatePulse.Net.Benchmark.Pulses.Actions; + +public record IncreaseCounterAction : IAction +{ +} diff --git a/src/StatePulse.Net.Benchmark/Pulses/Actions/IncreasedCounterAction.cs b/src/StatePulse.Net.Benchmark/Pulses/Actions/IncreasedCounterAction.cs new file mode 100644 index 0000000..1ee5717 --- /dev/null +++ b/src/StatePulse.Net.Benchmark/Pulses/Actions/IncreasedCounterAction.cs @@ -0,0 +1,6 @@ +ο»Ώnamespace StatePulse.Net.Benchmark.Pulses.Actions; + +public record IncreasedCounterAction : IAction +{ + +} diff --git a/src/StatePulse.Net.Benchmark/Pulses/Effects/IncreaseCounterEffect.cs b/src/StatePulse.Net.Benchmark/Pulses/Effects/IncreaseCounterEffect.cs new file mode 100644 index 0000000..50e49ee --- /dev/null +++ b/src/StatePulse.Net.Benchmark/Pulses/Effects/IncreaseCounterEffect.cs @@ -0,0 +1,22 @@ +ο»Ώusing Fluxor; +using StatePulse.Net.Benchmark.Pulses.Actions; + +namespace StatePulse.Net.Benchmark.Pulses.Effects; + +public class IncreaseCounterEffect : IEffect +{ + public Task EffectAsync(IncreaseCounterAction action, IDispatcher dispatcher) + { + _ = dispatcher.Prepare().DispatchAsync(); + return Task.CompletedTask; + } +} + +public class IncreaseCounterFluxEffect : Effect +{ + public override Task HandleAsync(IncreaseCounterAction action, Fluxor.IDispatcher dispatcher) + { + dispatcher.Dispatch(new IncreasedCounterAction()); + return Task.CompletedTask; + } +} diff --git a/src/StatePulse.Net.Benchmark/Pulses/Reducers/IncreasedCounterReducer.cs b/src/StatePulse.Net.Benchmark/Pulses/Reducers/IncreasedCounterReducer.cs new file mode 100644 index 0000000..ba1ba33 --- /dev/null +++ b/src/StatePulse.Net.Benchmark/Pulses/Reducers/IncreasedCounterReducer.cs @@ -0,0 +1,18 @@ +ο»Ώusing Fluxor; +using StatePulse.Net.Benchmark.Pulses.Actions; +using StatePulse.Net.Benchmark.Pulses.States; + +namespace StatePulse.Net.Benchmark.Pulses.Reducers; + +public class IncreasedCounterReducer : IReducer +{ + public Task ReduceAsync(CounterState state, IncreasedCounterAction action) + => Task.FromResult(state with { Counter = state.Counter + 1 }); +} + + +public class IncreasedCounterFluxReducer : Reducer +{ + public override CounterState Reduce(CounterState state, IncreasedCounterAction action) + => state with { Counter = state.Counter + 1 }; +} diff --git a/src/StatePulse.Net.Benchmark/Pulses/States/CounterState.cs b/src/StatePulse.Net.Benchmark/Pulses/States/CounterState.cs new file mode 100644 index 0000000..f14a6fe --- /dev/null +++ b/src/StatePulse.Net.Benchmark/Pulses/States/CounterState.cs @@ -0,0 +1,14 @@ +ο»Ώusing Fluxor; + +namespace StatePulse.Net.Benchmark.Pulses.States; + +public record CounterState : IStateFeature +{ + public int Counter { get; init; } +} + +[FeatureState] +public record CounterFluxState +{ + public int Counter { get; init; } +} diff --git a/src/StatePulse.Net.Benchmark/StatePulse.Net.Benchmark.csproj b/src/StatePulse.Net.Benchmark/StatePulse.Net.Benchmark.csproj new file mode 100644 index 0000000..9a9c700 --- /dev/null +++ b/src/StatePulse.Net.Benchmark/StatePulse.Net.Benchmark.csproj @@ -0,0 +1,40 @@ +ο»Ώ + + + Exe + net10.0 + enable + enable + + + + + + Release + true + true + + + portable + true + + + true + + + + + + + + + + + + + + + + + + diff --git a/src/StatePulse.Net.Benchmark/Tests.cs b/src/StatePulse.Net.Benchmark/Tests.cs new file mode 100644 index 0000000..c4d1dc1 --- /dev/null +++ b/src/StatePulse.Net.Benchmark/Tests.cs @@ -0,0 +1,99 @@ +ο»Ώusing BenchmarkDotNet.Attributes; +using Fluxor; +using Microsoft.Extensions.DependencyInjection; +using StatePulse.Net.Benchmark.Pulses.Actions; +using StatePulse.Net.Benchmark.Pulses.States; + +namespace StatePulse.Net.Benchmark; + +public class Tests +{ + private readonly IDispatcher _pulseDispatcher; + private CounterState PulseCounter { get; set; } + private CounterFluxState FluxCounter { get; set; } + private readonly Fluxor.IDispatcher _fluxDispatcher; + + public Tests() + { + ServiceCollection services = new(); + services.AddStatePulseServices(c => + { + c.DispatchOrderBehavior = Configuration.DispatchOrdering.ReducersFirst; + c.DispatchEffectBehavior = Configuration.DispatchEffectBehavior.Parallel; + c.DispatchEffectExecutionBehavior = Configuration.DispatchEffectExecutionBehavior.FireAndForget; + c.MiddlewareEffectBehavior = Configuration.MiddlewareEffectBehavior.PerGroupEffects; + c.MiddlewareTaskBehavior = Configuration.MiddlewareTaskBehavior.DoNotAwait; + c.ScanAssemblies = [typeof(Tests).Assembly]; + }); + services.AddFluxor(c => + { + c.ScanAssemblies(typeof(Tests).Assembly); + }); + var provider = services.BuildServiceProvider(); + _pulseDispatcher = provider.GetRequiredService(); + _fluxDispatcher = provider.GetRequiredService(); + var access = provider.GetRequiredService>(); + PulseCounter = access.State; + access.OnStateChanged += (_, e) => { PulseCounter = e; }; + var fluxcces = provider.GetRequiredService>(); + FluxCounter = fluxcces.Value; + fluxcces.StateChanged += (_, e) => { FluxCounter = fluxcces.Value; }; + } + + [Benchmark] + public void StatePulse_Dispatch() + { + int counter = PulseCounter.Counter; + _ = _pulseDispatcher.Prepare().DispatchAsync(); + // lock until state changes + do { } while (counter == PulseCounter.Counter); + } + + [Benchmark] + public void StatePulse_SafeDispatch() + { + int counter = PulseCounter.Counter; + _ = _pulseDispatcher.Prepare().DispatchAsync(true); + // lock until state changes + do { } while (counter == PulseCounter.Counter); + } + + [Benchmark] + public void StatePulse_FireYieldDispatch() + { + int counter = PulseCounter.Counter; + _ = _pulseDispatcher.Prepare().ExecFireAndForget().DispatchAsync(); + // lock until state changes + do { } while (counter == PulseCounter.Counter); + } + + [Benchmark] + public void StatePulse_FireYield_SequentialEffectsDispatch() + { + int counter = PulseCounter.Counter; + _ = _pulseDispatcher.Prepare().ExecFireAndForget().SequentialEffects().DispatchAsync(); + // lock until state changes + do { } while (counter == PulseCounter.Counter); + } + + [Benchmark] + public async Task StatePulse_AwaitedDispatch() + { + int counter = PulseCounter.Counter; + await _pulseDispatcher.Prepare().ExecFireAndForget().Await().DispatchAsync(); + // lock until state changes + do { } while (counter == PulseCounter.Counter); + } + + //[Benchmark] + //public void Flux_Dispatch() + //{ + // int counter = FluxCounter.Counter; + // _fluxDispatcher.Dispatch(new IncreaseCounterAction()); + // // lock until state changes + // do + // { + // } while (counter == FluxCounter.Counter); + //} + +} \ No newline at end of file From 5dfdb991a6a6117dc6c4a9a0ca134db3262abaf3 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Sat, 3 Jan 2026 17:17:47 +0200 Subject: [PATCH 10/27] benchmarking --- src/Directory.Packages.props | 7 +++ src/StatePulse.NET.sln | 1 + src/StatePulse.NET/StatePulse.NET.csproj | 4 +- .../StatePulse.Net.Abstractions.csproj | 4 +- src/StatePulse.Net.Benchmark/Program.cs | 2 +- .../StatePulse.Net.Benchmark.csproj | 10 +--- src/StatePulse.Net.Benchmark/Tests.cs | 51 +++++++------------ 7 files changed, 31 insertions(+), 48 deletions(-) create mode 100644 src/Directory.Packages.props diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props new file mode 100644 index 0000000..96c0a84 --- /dev/null +++ b/src/Directory.Packages.props @@ -0,0 +1,7 @@ + + + 2.0.3 + Maksim Shimshon © 2026 + + + \ No newline at end of file diff --git a/src/StatePulse.NET.sln b/src/StatePulse.NET.sln index db4adef..b8dbf3f 100644 --- a/src/StatePulse.NET.sln +++ b/src/StatePulse.NET.sln @@ -8,6 +8,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .editorconfig = .editorconfig ..\.github\workflows\ci.yml = ..\.github\workflows\ci.yml ..\.github\workflows\deploy.yml = ..\.github\workflows\deploy.yml + Directory.Packages.props = Directory.Packages.props ..\README.md = ..\README.md EndProjectSection EndProject diff --git a/src/StatePulse.NET/StatePulse.NET.csproj b/src/StatePulse.NET/StatePulse.NET.csproj index 6b17153..2c690a6 100644 --- a/src/StatePulse.NET/StatePulse.NET.csproj +++ b/src/StatePulse.NET/StatePulse.NET.csproj @@ -11,11 +11,11 @@ True 0.Versions.md https://github.com/mshimshon/StatePulse.NET - Maksim Shimshon Β© 2026 StatePulse.NET Maksim Shimshon - 2.0.1 + $(GlobalVersion) + $(GlobalCopyright) LICENSE True StatePulse.NET enables fast, consistent state/action dispatch with optional tracking and anti-duplicate flow control. It supports ordered chaining when needed, while maintaining high-performance fire-and-forget behavior for general use cases. diff --git a/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj b/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj index f4fe222..b29a94b 100644 --- a/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj +++ b/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj @@ -11,11 +11,11 @@ True 0.Versions.md https://github.com/mshimshon/StatePulse.NET - Maksim Shimshon Β© 2026 StatePulse.Net.Abstractions Maksim Shimshon - 2.0.1 + $(GlobalVersion) + $(GlobalCopyright) LICENSE True StatePulse.NET enables fast, consistent state/action dispatch with optional tracking and anti-duplicate flow control. It supports ordered chaining when needed, while maintaining high-performance fire-and-forget behavior for general use cases. diff --git a/src/StatePulse.Net.Benchmark/Program.cs b/src/StatePulse.Net.Benchmark/Program.cs index 4defee8..b47a3e4 100644 --- a/src/StatePulse.Net.Benchmark/Program.cs +++ b/src/StatePulse.Net.Benchmark/Program.cs @@ -10,7 +10,7 @@ public static void Main(string[] args) BenchmarkRunner.Run(); //var t = new Tests(); - //t.StatePulse_Dispatch(); + //t.StatePulse_FireYield_SequentialEffectsDispatch(); //t.Flux_Dispatch(); } } diff --git a/src/StatePulse.Net.Benchmark/StatePulse.Net.Benchmark.csproj b/src/StatePulse.Net.Benchmark/StatePulse.Net.Benchmark.csproj index 9a9c700..d8cb307 100644 --- a/src/StatePulse.Net.Benchmark/StatePulse.Net.Benchmark.csproj +++ b/src/StatePulse.Net.Benchmark/StatePulse.Net.Benchmark.csproj @@ -9,16 +9,11 @@ - Release true true - - portable true - - true @@ -27,14 +22,11 @@ + - - - - diff --git a/src/StatePulse.Net.Benchmark/Tests.cs b/src/StatePulse.Net.Benchmark/Tests.cs index c4d1dc1..404b742 100644 --- a/src/StatePulse.Net.Benchmark/Tests.cs +++ b/src/StatePulse.Net.Benchmark/Tests.cs @@ -43,57 +43,40 @@ public Tests() [Benchmark] public void StatePulse_Dispatch() { - int counter = PulseCounter.Counter; - _ = _pulseDispatcher.Prepare().DispatchAsync(); - // lock until state changes - do { } while (counter == PulseCounter.Counter); + _ = _pulseDispatcher.Prepare().Await().DispatchAsync(); } [Benchmark] - public void StatePulse_SafeDispatch() + public async Task StatePulse_BusrtDispatch() { - int counter = PulseCounter.Counter; - _ = _pulseDispatcher.Prepare().DispatchAsync(true); - // lock until state changes - do { } while (counter == PulseCounter.Counter); + for (int i = 0; i < 100; i++) + await _pulseDispatcher.Prepare().DispatchAsync(); } [Benchmark] - public void StatePulse_FireYieldDispatch() + public async Task StatePulse_BusrtSafeDispatch() { - int counter = PulseCounter.Counter; - _ = _pulseDispatcher.Prepare().ExecFireAndForget().DispatchAsync(); - // lock until state changes - do { } while (counter == PulseCounter.Counter); + for (int i = 0; i < 100; i++) + await _pulseDispatcher.Prepare().DispatchAsync(true); } + [Benchmark] - public void StatePulse_FireYield_SequentialEffectsDispatch() + public async Task StatePulse_FireYieldDispatch() { - int counter = PulseCounter.Counter; - _ = _pulseDispatcher.Prepare().ExecFireAndForget().SequentialEffects().DispatchAsync(); - // lock until state changes - do { } while (counter == PulseCounter.Counter); + await _pulseDispatcher.Prepare().ExecFireAndForget().DispatchAsync(); } [Benchmark] - public async Task StatePulse_AwaitedDispatch() + public async Task StatePulse_FireYield_SequentialEffectsDispatch() { - int counter = PulseCounter.Counter; - await _pulseDispatcher.Prepare().ExecFireAndForget().Await().DispatchAsync(); - // lock until state changes - do { } while (counter == PulseCounter.Counter); + await _pulseDispatcher.Prepare().ExecYieldAndFire().SequentialEffects().DispatchAsync(); } - //[Benchmark] - //public void Flux_Dispatch() - //{ - // int counter = FluxCounter.Counter; - // _fluxDispatcher.Dispatch(new IncreaseCounterAction()); - // // lock until state changes - // do - // { - // } while (counter == FluxCounter.Counter); - //} + [Benchmark] + public async Task StatePulse_AwaitedDispatch() + { + await _pulseDispatcher.Prepare().ExecYieldAndFire().Await().DispatchAsync(); + } } \ No newline at end of file From b7df70e95ae6255021a45c02d95cae56124b2de1 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Sat, 3 Jan 2026 17:34:50 +0200 Subject: [PATCH 11/27] Benchmarkd update --- README.md | 16 ++++++++++++++++ src/StatePulse.NET.sln | 6 ++++++ 2 files changed, 22 insertions(+) diff --git a/README.md b/README.md index 3b37b10..ddd385b 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ # StatePulse.NET ### [Official Documentation](https://statepulse.net/) + StatePulse.NET is a precision-tuned state and action management system that balances high-performance fire-and-forget operations with optional, internally controlled execution order when explicitly required. It enables anti-duplication chaining for critical flows, preventing race conditions and ensuring consistent outcomes even under rapid user input or concurrent triggers. Its internal tracking infrastructure provides near-zero overhead cancellation and dispatch control, drastically reducing inconsistency. @@ -29,6 +30,21 @@ At the same time, it preserves the flexibility of traditional untracked state ma - **Transient `IStatePulse` Service:** Each component gets its own `IStatePulse` instance, isolating event subscriptions and making state updates scoped and efficient. +## Benchmark +| Method | Mean | Error | StdDev | Median | +|----------------------------------------------- |-----------:|----------:|----------:|-----------:| +| StatePulse_Dispatch | 2.458 ΞΌs | 0.0344 ΞΌs | 0.0322 ΞΌs | 2.455 ΞΌs | +| StatePulse_BusrtDispatch | 321.243 ΞΌs | 4.6181 ΞΌs | 4.3198 ΞΌs | 322.030 ΞΌs | +| StatePulse_BusrtSafeDispatch | 350.282 ΞΌs | 4.4814 ΞΌs | 4.1919 ΞΌs | 351.182 ΞΌs | +| StatePulse_FireYieldDispatch | 3.193 ΞΌs | 0.0631 ΞΌs | 0.0675 ΞΌs | 3.193 ΞΌs | +| StatePulse_FireYield_SequentialEffectsDispatch | 3.326 ΞΌs | 0.0661 ΞΌs | 0.0969 ΞΌs | 3.303 ΞΌs | +| StatePulse_AwaitedDispatch | 4.420 ΞΌs | 0.6850 ΞΌs | 2.0196 ΞΌs | 3.165 ΞΌs | + +StatePulse is very fast considering it's features but it should be avoided in tight loops which is not its intended use anyway. +I will be working to improve the performances over the long run, there are many areas which can be improved but at the moment, +i will be focusing on stable system, settings and features. + + ## πŸ“¦ Installation & Setup diff --git a/src/StatePulse.NET.sln b/src/StatePulse.NET.sln index b8dbf3f..1bbd08f 100644 --- a/src/StatePulse.NET.sln +++ b/src/StatePulse.NET.sln @@ -24,6 +24,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatePulse.Net.BlazorServer EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatePulse.Net.Benchmark", "StatePulse.Net.Benchmark\StatePulse.Net.Benchmark.csproj", "{1608523F-D5DA-4C8D-AF14-F89565929876}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatePulse.Net.Analyzers", "StatePulse.Net.Analyzers\StatePulse.Net.Analyzers.csproj", "{23754E59-BBAC-72AF-5A0C-48C0197057C1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -54,6 +56,10 @@ Global {1608523F-D5DA-4C8D-AF14-F89565929876}.Debug|Any CPU.Build.0 = Debug|Any CPU {1608523F-D5DA-4C8D-AF14-F89565929876}.Release|Any CPU.ActiveCfg = Release|Any CPU {1608523F-D5DA-4C8D-AF14-F89565929876}.Release|Any CPU.Build.0 = Release|Any CPU + {23754E59-BBAC-72AF-5A0C-48C0197057C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {23754E59-BBAC-72AF-5A0C-48C0197057C1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {23754E59-BBAC-72AF-5A0C-48C0197057C1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {23754E59-BBAC-72AF-5A0C-48C0197057C1}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From c164ca840eeab89323baf086b622a00fd5a8060b Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Sat, 3 Jan 2026 17:56:44 +0200 Subject: [PATCH 12/27] - Finally Roslyn Works --- doc/docs/0.Versions.md | 4 + src/Directory.Packages.props | 2 +- .../Analyzer1Analyzer.cs | 55 ---------- .../FactSecondParamAnalyzer.cs | 81 -------------- .../StatePulse.Net.Analyzers.csproj | 3 +- .../StatePulseStateOfAnalyzer.cs | 100 ++++++++++++++++++ 6 files changed, 107 insertions(+), 138 deletions(-) delete mode 100644 src/StatePulse.Net.Analyzers/Analyzer1Analyzer.cs delete mode 100644 src/StatePulse.Net.Analyzers/FactSecondParamAnalyzer.cs create mode 100644 src/StatePulse.Net.Analyzers/StatePulseStateOfAnalyzer.cs diff --git a/doc/docs/0.Versions.md b/doc/docs/0.Versions.md index 64b596a..2350308 100644 --- a/doc/docs/0.Versions.md +++ b/doc/docs/0.Versions.md @@ -49,6 +49,10 @@ sidebar_position: 0 - `IStateFeatureSingleton` - Define a singleton state across your app... not useful in WASM but very useful in Blazor Server... where one can share the state across client each client run their own action but the state update spread across all circuits. - `IReducerSingleton`, `IEffectSingleton`, `IEffectValidationSingleton`, `IEffectMiddlewareSingleton`, `IReducerMiddlewareSingleton` - Define a singleton for blazor server cross circuit logic. +### 🐞 Security +- Roslyn will now enforce `_statePulse.StateOf(() => this, OnUpdate);` on the two arguments this will avoid runtime errors and potential memory leaks. +- Fixed All Configure Internal... + ### 🐞 Fixes - Fixed Various Warnings - Fixed All Configure Internal... diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 96c0a84..1462854 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -1,6 +1,6 @@ - 2.0.3 + 2.0.5 Maksim Shimshon © 2026 diff --git a/src/StatePulse.Net.Analyzers/Analyzer1Analyzer.cs b/src/StatePulse.Net.Analyzers/Analyzer1Analyzer.cs deleted file mode 100644 index 182fcff..0000000 --- a/src/StatePulse.Net.Analyzers/Analyzer1Analyzer.cs +++ /dev/null @@ -1,55 +0,0 @@ -ο»Ώusing Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; -using System.Collections.Immutable; - -namespace Analyzer1 -{ - [DiagnosticAnalyzer(LanguageNames.CSharp)] - public sealed class CapitalClassNameAnalyzer : DiagnosticAnalyzer - { - public const string DiagnosticId = "DEMO001"; - - private static readonly DiagnosticDescriptor Rule = - new DiagnosticDescriptor( - DiagnosticId, - "Class name starts with a capital letter", - "Class name '{0}' starts with a capital letter", - "Naming", - DiagnosticSeverity.Error, - isEnabledByDefault: true); - - public override ImmutableArray SupportedDiagnostics - => ImmutableArray.Create(Rule); - - public override void Initialize(AnalysisContext context) - { - context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); - context.EnableConcurrentExecution(); - - context.RegisterSyntaxNodeAction( - AnalyzeClass, - SyntaxKind.ClassDeclaration); - } - - private static void AnalyzeClass(SyntaxNodeAnalysisContext context) - { - var classDecl = (ClassDeclarationSyntax)context.Node; - var name = classDecl.Identifier.Text; - - if (string.IsNullOrEmpty(name)) - return; - - if (char.IsUpper(name[0])) - { - var diagnostic = Diagnostic.Create( - Rule, - classDecl.Identifier.GetLocation(), - name); - - context.ReportDiagnostic(diagnostic); - } - } - } -} diff --git a/src/StatePulse.Net.Analyzers/FactSecondParamAnalyzer.cs b/src/StatePulse.Net.Analyzers/FactSecondParamAnalyzer.cs deleted file mode 100644 index a5715bb..0000000 --- a/src/StatePulse.Net.Analyzers/FactSecondParamAnalyzer.cs +++ /dev/null @@ -1,81 +0,0 @@ -ο»Ώusing Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; -using System.Collections.Immutable; - -namespace StatePulse.Net.Analyzers -{ - [DiagnosticAnalyzer(LanguageNames.CSharp)] - public class FactSecondParamAnalyzer : DiagnosticAnalyzer - { - public const string DiagnosticId = "SP0001"; - - private static readonly LocalizableString Title = "The onStateChanged parameter of StateOf should not be a lambda"; - private static readonly LocalizableString MessageFormat = "The onStateChanged argument to 'StateOf' cannot be a lambda expression"; - private static readonly LocalizableString Description = "The onStateChanged argument must be a method group, not an inline lambda."; - private const string Category = "Usage"; - - private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( - DiagnosticId, - Title, - MessageFormat, - Category, - DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: Description - ); - - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); - - public override void Initialize(AnalysisContext context) - { - context.EnableConcurrentExecution(); - // Analyze generated code (Blazor .razor -> generated C#) and report diagnostics there - context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); - context.RegisterSyntaxNodeAction(AnalyzeInvocation, SyntaxKind.InvocationExpression); - } - - private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context) - { - var invocation = context.Node as InvocationExpressionSyntax; - if (invocation == null) - { - return; - } - - var symbolInfo = context.SemanticModel.GetSymbolInfo(invocation.Expression, context.CancellationToken); - var methodSymbol = symbolInfo.Symbol as IMethodSymbol; - if (methodSymbol == null) - { - return; - } - - // Ensure it's a method named StateOf - if (methodSymbol.Name != "StateOf") - return; - - // Ensure it belongs to the correct interface - var containingType = methodSymbol.ContainingType; - var fullTypeName = containingType?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); - if (fullTypeName != "global::StatePulse.Net.IStatePulse") - return; - - // Check argument count - if (invocation.ArgumentList == null) - return; - - var args = invocation.ArgumentList.Arguments; - if (args.Count < 2) - return; - - var secondArg = args[1].Expression; - - if (secondArg is LambdaExpressionSyntax lambda) - { - var diagnostic = Diagnostic.Create(Rule, lambda.GetLocation()); - context.ReportDiagnostic(diagnostic); - } - } - } -} diff --git a/src/StatePulse.Net.Analyzers/StatePulse.Net.Analyzers.csproj b/src/StatePulse.Net.Analyzers/StatePulse.Net.Analyzers.csproj index 31e9d61..e049289 100644 --- a/src/StatePulse.Net.Analyzers/StatePulse.Net.Analyzers.csproj +++ b/src/StatePulse.Net.Analyzers/StatePulse.Net.Analyzers.csproj @@ -2,7 +2,8 @@ netstandard2.0 - true + 12.0 + true true StatePulse.Net.Analyzers diff --git a/src/StatePulse.Net.Analyzers/StatePulseStateOfAnalyzer.cs b/src/StatePulse.Net.Analyzers/StatePulseStateOfAnalyzer.cs new file mode 100644 index 0000000..a466b70 --- /dev/null +++ b/src/StatePulse.Net.Analyzers/StatePulseStateOfAnalyzer.cs @@ -0,0 +1,100 @@ +ο»Ώusing Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Immutable; +using System.Threading.Tasks; + +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public sealed class StatePulseStateOfAnalyzer : DiagnosticAnalyzer +{ + public const string DiagnosticId = "SP001"; + + private static readonly DiagnosticDescriptor Rule = + new DiagnosticDescriptor( + DiagnosticId, + "Invalid StateOf binding", + "StateOf requires first argument '() => this' and second argument a method group returning Task", + "StatePulse", + DiagnosticSeverity.Error, + isEnabledByDefault: true + ); + + public override ImmutableArray SupportedDiagnostics + => ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSyntaxNodeAction(AnalyzeInvocation, SyntaxKind.InvocationExpression); + } + + private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context) + { + var invocation = (InvocationExpressionSyntax)context.Node; + + var symbol = context.SemanticModel.GetSymbolInfo(invocation).Symbol as IMethodSymbol; + if (symbol == null) + return; + + if (symbol.Name != "StateOf") + return; + + if (symbol.ContainingType.Name != "IStatePulse") + return; + + var args = invocation.ArgumentList.Arguments; + if (args.Count < 2) + return; + + var arg0 = args[0].Expression; + var arg1 = args[1].Expression; + + if (!IsLambdaThis(arg0, context)) + { + context.ReportDiagnostic(Diagnostic.Create(Rule, arg0.GetLocation())); + return; + } + + if (arg1 is LambdaExpressionSyntax) + { + context.ReportDiagnostic(Diagnostic.Create(Rule, arg1.GetLocation())); + return; + } + + var methodSymbol = context.SemanticModel.GetSymbolInfo(arg1).Symbol as IMethodSymbol; + if (methodSymbol == null) + { + context.ReportDiagnostic(Diagnostic.Create(Rule, arg1.GetLocation())); + return; + } + + if (!IsTask(methodSymbol.ReturnType)) + { + context.ReportDiagnostic(Diagnostic.Create(Rule, arg1.GetLocation())); + } + } + + private static bool IsLambdaThis(ExpressionSyntax expr, SyntaxNodeAnalysisContext context) + { + if (expr is not LambdaExpressionSyntax lambda) + return false; + + ExpressionSyntax body = lambda switch + { + SimpleLambdaExpressionSyntax s => s.Body as ExpressionSyntax, + ParenthesizedLambdaExpressionSyntax p => p.Body as ExpressionSyntax, + _ => null + }; + + if (body is not ThisExpressionSyntax) + return false; + + var typeInfo = context.SemanticModel.GetTypeInfo(body).Type; + return typeInfo != null; + } + + private static bool IsTask(ITypeSymbol type) + => type.ToDisplayString() == typeof(Task).FullName; +} From f317b70e15b6aa54d02462b61d8ef1a71924ec11 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Mon, 5 Jan 2026 22:30:28 +0200 Subject: [PATCH 13/27] wip --- doc/docs/0.Versions.md | 3 +++ src/Directory.Packages.props | 2 +- src/StatePulse.NET/ServiceRegisterExt.cs | 2 +- src/StatePulse.NET/StatePulse.NET.csproj | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/docs/0.Versions.md b/doc/docs/0.Versions.md index 2350308..4037467 100644 --- a/doc/docs/0.Versions.md +++ b/doc/docs/0.Versions.md @@ -29,6 +29,9 @@ sidebar_position: 0 - **Configuration Scan Assembly Type Changed** The property `ConfigureOptions.ScanAssemblies` is now taking a `Assembly[]` instead of `Type[]`. +- **IPulseGlobalTracker registration changed** + The IPulseGlobalTracker is now registered as Scoped instead of singleton... issues were occuring with some blazor server projects. + ### ✨ New Features - **βš™οΈ Enhanced Configuration Options** - New global configuration properties: - `DispatchOrderBehavior` - Set default ordering (EffectsFirst/ReducersFirst) diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 1462854..340c5fd 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -1,6 +1,6 @@ - 2.0.5 + 2.0.52 Maksim Shimshon © 2026 diff --git a/src/StatePulse.NET/ServiceRegisterExt.cs b/src/StatePulse.NET/ServiceRegisterExt.cs index 709c712..bd3ad6a 100644 --- a/src/StatePulse.NET/ServiceRegisterExt.cs +++ b/src/StatePulse.NET/ServiceRegisterExt.cs @@ -19,7 +19,6 @@ public static IServiceCollection AddStatePulseServices(this IServiceCollection s services.AddTransient(); configure(ConfigureOptions); ConfigureOptions.ValidateConfiguration(); - services.AddSingleton(); bool isSingleThreadModel = ConfigureOptions.PulseTrackingPerformance == PulseTrackingModel.SingleThreadFast || ConfigureOptions.PulseTrackingPerformance == PulseTrackingModel.BlazorWebAssemblyFast; if (isSingleThreadModel) @@ -27,6 +26,7 @@ public static IServiceCollection AddStatePulseServices(this IServiceCollection s else services.AddTransient(); + services.AddScoped(); services.AddSingleton(Registry); services.ScanStatePulseAssemblies(ConfigureOptions.ScanAssemblies); diff --git a/src/StatePulse.NET/StatePulse.NET.csproj b/src/StatePulse.NET/StatePulse.NET.csproj index 2c690a6..0792ac8 100644 --- a/src/StatePulse.NET/StatePulse.NET.csproj +++ b/src/StatePulse.NET/StatePulse.NET.csproj @@ -1,7 +1,7 @@ ο»Ώ - net8.0;net10.0 + net10.0;net8.0 12.0 enable enable From 72b9734bb820397f793224cac97f2b3d83aac490 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Tue, 13 Jan 2026 00:58:33 +0200 Subject: [PATCH 14/27] wip --- doc/docs/0.Versions.md | 23 ++- src/Directory.Packages.props | 4 +- .../Configuration/ConfigureOptions.cs | 20 +- .../DispatchEffectExecutionBehavior.cs | 12 +- src/StatePulse.NET/Engine/DispatchEntry.cs | 3 + ...nableToRegisterExplicitServiceException.cs | 8 + src/StatePulse.NET/Engine/IDispatchTracker.cs | 15 +- .../Engine/Implementations/DispatchTracker.cs | 35 ++++ .../DispatchTrackingIdentity.cs | 3 + .../Engine/Implementations/Dispatcher.cs | 4 +- .../Implementations/DispatcherPrepper.cs | 134 ++++++++----- .../DispatcherPrepper_Flags.cs | 54 +----- .../Engine/Implementations/StateAccessor.cs | 3 + src/StatePulse.NET/ServiceRegisterExt.cs | 178 ++++++------------ .../IDispatcherMiddleware.cs | 2 + .../IDispatcherMiddlewareSingleton.cs | 4 - .../IDispatcherPrepper.cs | 3 +- .../IEffectMiddlewareSingleton.cs | 11 -- .../IEffectSingleton.cs | 12 -- .../IEffectValidationSingleton.cs | 13 -- .../IReducerMiddlewareSingleton.cs | 11 -- .../IReducerSingleton.cs | 13 -- .../IStateAccessor.cs | 3 + tests/StatPulse.NET.Tests/TestBase.cs | 54 +++--- .../InitializerTests/StatePulseInitTests.cs | 73 ++++--- .../MainMenuLoaderStartDispatchMiddleware.cs | 4 + .../Actions/ProfileCardDefineAction.cs | 2 + .../Effects/ProfileCardDefineEffect.cs | 5 +- 28 files changed, 338 insertions(+), 368 deletions(-) create mode 100644 src/StatePulse.NET/Engine/Exceptions/UnableToRegisterExplicitServiceException.cs delete mode 100644 src/StatePulse.Net.Abstractions/IDispatcherMiddlewareSingleton.cs delete mode 100644 src/StatePulse.Net.Abstractions/IEffectMiddlewareSingleton.cs delete mode 100644 src/StatePulse.Net.Abstractions/IEffectSingleton.cs delete mode 100644 src/StatePulse.Net.Abstractions/IEffectValidationSingleton.cs delete mode 100644 src/StatePulse.Net.Abstractions/IReducerMiddlewareSingleton.cs delete mode 100644 src/StatePulse.Net.Abstractions/IReducerSingleton.cs diff --git a/doc/docs/0.Versions.md b/doc/docs/0.Versions.md index 4037467..d3216fb 100644 --- a/doc/docs/0.Versions.md +++ b/doc/docs/0.Versions.md @@ -19,6 +19,7 @@ sidebar_position: 0 Per‑effect middleware proved unreliable and is no longer supported. All effects now run as a batch, followed by a single AfterEffect phase. Middleware can still be awaited before the BeforeEffect phase and after the AfterEffect phase. + Middlewares for effects if not awaited they are still ganrantueed to be running sequentially BeforeEffect Parallel with Effects then AfterEffects. - **Actions can never be singleton.** Action are essentially data contract and should remain at the scope level which in blazor server case is circuit bound. @@ -32,15 +33,28 @@ sidebar_position: 0 - **IPulseGlobalTracker registration changed** The IPulseGlobalTracker is now registered as Scoped instead of singleton... issues were occuring with some blazor server projects. + +- **Removed .AddStatePulse** + the extension method were removed from public access... now you use `.AddStatePulseService()` which will auto detect from action to effect to reducers to middlewares. + Reason: Better dev experience less confusing and annoying when having to register stuff manually instead of by scanning. + Alternative: You can also add types into `.AddStatePulseServices(o=>{ o.AutoRegisterTypes = [typeof(AAA)];});` which will perform manual registration automatically without scanning assemblies. + +- **Added to IDispatchMiddleware** + `OnDispatchFailure(Exception exception, object action)` is now available to middleware hit is receive on any dispatch failure... + +- **Removed Throw for Dispatch Failure** + Re-Throw only occurs when using Synchronous `Await()` otherwise dispatch will swallow any uncaught exception thrown at it. + + ### ✨ New Features - **βš™οΈ Enhanced Configuration Options** - New global configuration properties: - `DispatchOrderBehavior` - Set default ordering (EffectsFirst/ReducersFirst) - `DispatchEffectExecutionBehavior` - Set default execution mode (YieldAndFire/FireAndForget) - **πŸŽ›οΈ Configurable Dispatch Ordering** - Choose between `EffectsFirst` (default) or `ReducersFirst` execution order globally or per-dispatch +- **πŸŽ›οΈ Configurable Dispatch Ordering** - The Middleware BeforeReducers will run before the AfterReducer as garantueed... +- The reducer will however run in parallel with BeforeReducing if settings is to not await for middlewares. - **⚑ True Fire-and-Forget Execution Mode** - New `DispatchEffectExecutionBehavior.FireAndForget` for true background execution without yielding and awaiting effects - **πŸ”§ Per-Dispatch Execution Control** - Override global settings per dispatch with fluent API: - - `.ExecFireAndForget()` - Fully detached background execution - - `.ExecYieldAndFire()` - Yield to caller but await until all effects are done to move down the pipeline - `.EffectsFirst()` - Run effects before reducers - `.ReducersFirst()` - Run reducers before effects - `.SequentialEffects()` - Force effects to run in sequence @@ -50,7 +64,7 @@ sidebar_position: 0 - `PulseTrackingModel` - Clear option for the tracking model! Either Thread-Safe (`Default`) or Single Threaded Fast Application... WASM/Blazor Server. - `GlobalTrackerLifetime` - Define clearly lifetime scope for the Global Tracker singleton or scoped. `BlazorServer`, `WASM`, `Scoped` (Default) or `Singleton`. - `IStateFeatureSingleton` - Define a singleton state across your app... not useful in WASM but very useful in Blazor Server... where one can share the state across client each client run their own action but the state update spread across all circuits. -- `IReducerSingleton`, `IEffectSingleton`, `IEffectValidationSingleton`, `IEffectMiddlewareSingleton`, `IReducerMiddlewareSingleton` - Define a singleton for blazor server cross circuit logic. +- `IReducer`, `IEffect`, `IEffectValidation`, `IEffectMiddleware`, `IReducerMiddleware` - Are ALWAYS transient from now on. ### 🐞 Security - Roslyn will now enforce `_statePulse.StateOf(() => this, OnUpdate);` on the two arguments this will avoid runtime errors and potential memory leaks. @@ -59,6 +73,9 @@ sidebar_position: 0 ### 🐞 Fixes - Fixed Various Warnings - Fixed All Configure Internal... +- Fixed Middleware are now added via Scanned Assemblies. +- Fixed some issues where `Await()` was not respected. +- Fixed major issue where all race condition elements where cancelled leading to full chain cancellation including the last action. ## πŸ“¦ v1.1.0 diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 340c5fd..f019832 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -1,7 +1,7 @@ - 2.0.52 - Maksim Shimshon © 2026 + 2.0.521 + Maksim Shimshon Β© 2026 \ No newline at end of file diff --git a/src/StatePulse.NET/Configuration/ConfigureOptions.cs b/src/StatePulse.NET/Configuration/ConfigureOptions.cs index fb73299..bc26574 100644 --- a/src/StatePulse.NET/Configuration/ConfigureOptions.cs +++ b/src/StatePulse.NET/Configuration/ConfigureOptions.cs @@ -1,5 +1,4 @@ -ο»Ώusing StatePulse.Net.Engine.Exceptions; -using System.Reflection; +ο»Ώusing System.Reflection; namespace StatePulse.Net.Configuration; @@ -11,21 +10,16 @@ public class ConfigureOptions public MiddlewareEffectBehavior MiddlewareEffectBehavior { get; set; } = MiddlewareEffectBehavior.PerGroupEffects; public MiddlewareTaskBehavior MiddlewareTaskBehavior { get; set; } = MiddlewareTaskBehavior.DoNotAwait; public DispatchEffectBehavior DispatchEffectBehavior { get; set; } = DispatchEffectBehavior.Parallel; - public DispatchEffectExecutionBehavior DispatchEffectExecutionBehavior { get; set; } = DispatchEffectExecutionBehavior.YieldAndFire; public DispatchOrdering DispatchOrderBehavior { get; set; } = DispatchOrdering.ReducersFirst; public PulseTrackingModel PulseTrackingPerformance { get; set; } = PulseTrackingModel.ThreadSafe; public Assembly[] ScanAssemblies { get; set; } = new Assembly[] { }; + public Type[] AutoRegisterTypes { get; set; } = new Type[] { }; + private long _versionTicker; - public void ValidateConfiguration() + public long GetNextVersion() { - // FireAndForget can't be Sequential - if (DispatchEffectExecutionBehavior == DispatchEffectExecutionBehavior.FireAndForget - && DispatchEffectBehavior == DispatchEffectBehavior.Sequential) - { - throw new InvalidDispatchCombinationException( - "DispatchEffectExecutionBehavior.FireAndForget execution cannot be combined with DispatchEffectBehavior.Sequential. " + - "FireAndForget doesn't await effects, so ordering cannot be guaranteed. " + - "Use DispatchEffectExecutionBehavior.YieldAndFire with DispatchEffectBehavior.Sequential/DispatchEffectBehavior.Parallel or DispatchEffectExecutionBehavior.FireAndForget and DispatchEffectBehavior.Parallel"); - } + var next = Interlocked.Increment(ref _versionTicker); + return next; } + } diff --git a/src/StatePulse.NET/Configuration/DispatchEffectExecutionBehavior.cs b/src/StatePulse.NET/Configuration/DispatchEffectExecutionBehavior.cs index 8a0fce5..762987e 100644 --- a/src/StatePulse.NET/Configuration/DispatchEffectExecutionBehavior.cs +++ b/src/StatePulse.NET/Configuration/DispatchEffectExecutionBehavior.cs @@ -1,10 +1,4 @@ -ο»Ώusing System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace StatePulse.Net.Configuration; +ο»Ώnamespace StatePulse.Net.Configuration; public enum DispatchEffectExecutionBehavior { @@ -12,8 +6,4 @@ public enum DispatchEffectExecutionBehavior /// (Default): Like fire and forget but the statepulse engine still awaits all the effects before calling the middlewares. /// YieldAndFire, - /// - /// Nothing is awaited, effects runs as they want and after effect middleware have not garantuees the effect actually ran. (This will disable DispatchEffectBehavior.Sequential) - /// - FireAndForget } diff --git a/src/StatePulse.NET/Engine/DispatchEntry.cs b/src/StatePulse.NET/Engine/DispatchEntry.cs index 0678ba1..f070b31 100644 --- a/src/StatePulse.NET/Engine/DispatchEntry.cs +++ b/src/StatePulse.NET/Engine/DispatchEntry.cs @@ -8,11 +8,14 @@ public class DispatchEntry where TAction : IAction public Guid Id => _guid; public IDispatcherPrepper Action => _action; private readonly CancellationTokenSource _tokenSource = new(); + public DateTime Execution { get; } private int _disposed; public DispatchEntry(Guid id, IDispatcherPrepper action) { _guid = id; _action = action; + Execution = DateTime.UtcNow; + } public void Cancel() { diff --git a/src/StatePulse.NET/Engine/Exceptions/UnableToRegisterExplicitServiceException.cs b/src/StatePulse.NET/Engine/Exceptions/UnableToRegisterExplicitServiceException.cs new file mode 100644 index 0000000..023f826 --- /dev/null +++ b/src/StatePulse.NET/Engine/Exceptions/UnableToRegisterExplicitServiceException.cs @@ -0,0 +1,8 @@ +ο»Ώnamespace StatePulse.Net.Engine.Exceptions; + +public class UnableToRegisterExplicitServiceException : Exception +{ + public UnableToRegisterExplicitServiceException(string? message) : base(message) + { + } +} diff --git a/src/StatePulse.NET/Engine/IDispatchTracker.cs b/src/StatePulse.NET/Engine/IDispatchTracker.cs index a01df78..e50b042 100644 --- a/src/StatePulse.NET/Engine/IDispatchTracker.cs +++ b/src/StatePulse.NET/Engine/IDispatchTracker.cs @@ -1,6 +1,16 @@ -ο»Ώnamespace StatePulse.Net.Engine; -public interface IDispatchTracker where TAction : IAction +ο»Ώusing System.Collections.Concurrent; + +namespace StatePulse.Net.Engine; + +public interface IDispatchTracker { + public bool IsCancelled(Guid id, long version); + public long CurrentVersion { get; } + public bool CreateExecutingAction(Guid id, object action, long version); +} +public interface IDispatchTracker : IDispatchTracker where TAction : IAction +{ + public ConcurrentDictionary> CancellationTracker { get; } public EventHandler>? OnCancel { get; set; } public EventHandler>? OnEntry { get; set; } public void CreateEntryPoint(Guid id, object action); @@ -8,4 +18,5 @@ public interface IDispatchTracker where TAction : IAction public void CancelDispatchFor(Guid id); public void CancelAll(); public bool IsCancelled(Guid id); + } diff --git a/src/StatePulse.NET/Engine/Implementations/DispatchTracker.cs b/src/StatePulse.NET/Engine/Implementations/DispatchTracker.cs index 92a9d9c..05c55a1 100644 --- a/src/StatePulse.NET/Engine/Implementations/DispatchTracker.cs +++ b/src/StatePulse.NET/Engine/Implementations/DispatchTracker.cs @@ -1,14 +1,41 @@ ο»Ώusing System.Collections.Concurrent; namespace StatePulse.Net.Engine.Implementations; + internal class DispatchTracker : IDispatchTracker where TAction : IAction { private readonly ConcurrentDictionary> _cancelTracker = new(); public EventHandler>? OnCancel { get; set; } public EventHandler>? OnEntry { get; set; } + + public ConcurrentDictionary> CancellationTracker => _cancelTracker; + + public long CurrentVersion => _currentVersion; + + private long _currentVersion = 0; + public bool CreateExecutingAction(Guid id, object action, long version) + { + long current = Volatile.Read(ref _currentVersion); + + // If my version is not greater, I lose + if (version <= current) + return false; + + // Try to atomically promote the version + long original = Interlocked.CompareExchange( + ref _currentVersion, + version, + current); + + // If original == current, I successfully promoted + return original == current; + + } + public void CreateEntryPoint(Guid id, object action) { CancelAll(); var item = new DispatchEntry(id, (IDispatcherPrepper)action); + _cancelTracker.TryAdd(id, item); OnEntry?.Invoke(this, item); } @@ -44,4 +71,12 @@ public void CancelAll() foreach (var item in _cancelTracker.Keys) DeleteEntryPoint(item); } + + public bool CreateEntryPoint(Guid id, object action, long version) => throw new NotImplementedException(); + public bool IsCancelled(Guid id, long version) + { + long current = Volatile.Read(ref _currentVersion); + return current != version; + + } } diff --git a/src/StatePulse.NET/Engine/Implementations/DispatchTrackingIdentity.cs b/src/StatePulse.NET/Engine/Implementations/DispatchTrackingIdentity.cs index ef8eeed..7b6c37b 100644 --- a/src/StatePulse.NET/Engine/Implementations/DispatchTrackingIdentity.cs +++ b/src/StatePulse.NET/Engine/Implementations/DispatchTrackingIdentity.cs @@ -1,6 +1,9 @@ ο»Ώnamespace StatePulse.Net.Engine.Implementations; + public record DispatchTrackingIdentity { public Guid Id { get; init; } public Type EntryType { get; init; } = default!; + public long Version { get; init; } + public IDispatchTracker Tracker { get; init; } = default!; } diff --git a/src/StatePulse.NET/Engine/Implementations/Dispatcher.cs b/src/StatePulse.NET/Engine/Implementations/Dispatcher.cs index 1519e3a..acf09a4 100644 --- a/src/StatePulse.NET/Engine/Implementations/Dispatcher.cs +++ b/src/StatePulse.NET/Engine/Implementations/Dispatcher.cs @@ -1,4 +1,5 @@ ο»Ώnamespace StatePulse.Net.Engine.Implementations; + internal class Dispatcher : IDispatcher, IDispatchHandler { private readonly IServiceProvider _serviceProvider; @@ -29,7 +30,8 @@ public IDispatcherPrepper Prepare(Func createInstance private IDispatcherPrepper CreatePrepper(TAction Instance) where TAction : IAction { - var dispatcherPrepperType = typeof(DispatcherPrepper<,>).MakeGenericType(typeof(TAction), _chainKey?.EntryType ?? typeof(TAction)); + var passKeyChain = _chainKey?.EntryType ?? typeof(TAction); + var dispatcherPrepperType = typeof(DispatcherPrepper<,>).MakeGenericType(typeof(TAction), passKeyChain); var instance = Activator.CreateInstance(dispatcherPrepperType, Instance, _serviceProvider, _chainKey) ?? throw new InvalidOperationException($"Cannot create instance of {typeof(TAction).Name} with given constructor parameters."); return (instance as IDispatcherPrepper)!; diff --git a/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs b/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs index 9aa13d3..051dbb6 100644 --- a/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs +++ b/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs @@ -1,9 +1,9 @@ ο»Ώ using Microsoft.Extensions.DependencyInjection; using StatePulse.Net.Configuration; -using System.Collections.Concurrent; using System.Reflection; namespace StatePulse.Net.Engine.Implementations; + internal partial class DispatcherPrepper : IDispatcherPrepper where TAction : IAction where TActionChain : IAction @@ -13,7 +13,7 @@ internal partial class DispatcherPrepper : IDispatcherPre private readonly IStatePulseRegistry _statePulseRegistry; private readonly DispatchTrackingIdentity? _chainKey; private readonly IDispatchTracker _tracker; - + private readonly long _currentVersion; public DispatcherPrepper(TAction action, IServiceProvider serviceProvider, DispatchTrackingIdentity? chainKey) { _action = action!; @@ -22,13 +22,15 @@ public DispatcherPrepper(TAction action, IServiceProvider serviceProvider, Dispa _chainKey = chainKey; var trackerTypeAction = typeof(IDispatchTracker<>).MakeGenericType(typeof(TActionChain)); _tracker = (IDispatchTracker)_serviceProvider.GetRequiredService(trackerTypeAction); + _currentVersion = ServiceRegisterExt.ConfigureOptions.GetNextVersion(); + } public TAction ActionInstance => _action; public async Task DispatchFastAsync() { - if (_chainKey != default && _tracker.IsCancelled(_chainKey.Id)) + if (_chainKey != default && _chainKey.Tracker.IsCancelled(_chainKey.Id, _chainKey.Version)) return; if (_chainKey == default) if (_forceSyncronous) @@ -37,6 +39,8 @@ public async Task DispatchFastAsync() _ = ProcessDispatch(false, Guid.Empty); else { + if (_chainKey.Tracker.IsCancelled(_chainKey.Id, _chainKey.Version)) + return; if (_forceSyncronous) await ProcessDispatch(false, Guid.Empty); else @@ -47,8 +51,6 @@ public async Task DispatchFastAsync() public async Task DispatchSafeAsync() { - if (_chainKey != default && _tracker.IsCancelled(_chainKey.Id)) - return _chainKey.Id; if (_chainKey == default) { Guid nextKey = Guid.NewGuid(); @@ -59,24 +61,22 @@ public async Task DispatchSafeAsync() return nextKey; } else + { // ignore requested dispatch if cancelled - if (!_tracker.IsCancelled(_chainKey.Id)) await ProcessDispatch(false, Guid.Empty); + if (!_tracker.IsCancelled(_chainKey.Id, _chainKey.Version)) + if (_forceSyncronous) + await ProcessDispatch(false, Guid.Empty); + else + _ = ProcessDispatch(false, Guid.Empty); + } + return _chainKey?.Id ?? Guid.Empty; } private static MethodInfo? _cachedEffectMethod; private static MethodInfo? _cachedActionValidatorMethod; - private static readonly ConcurrentDictionary _cachedEffectInterfaceTypes = new(); protected async Task ProcessDispatch(bool entryPoint, Guid nextId) { - var disaptchMiddlewares = _serviceProvider.GetServices(); - var dispatchMiddlewareTasks = new List(); - foreach (var item in disaptchMiddlewares) - { - dispatchMiddlewareTasks.Add(item.BeforeDispatch(_action)); - } - - await Task.WhenAll(dispatchMiddlewareTasks); // we are tracking next chain key only when there is an entry point to avoid tracker during fast dispatch. // by default it will be null otherwise chain should be passed down the next calls. var nextChain = _chainKey; @@ -85,11 +85,26 @@ protected async Task ProcessDispatch(bool entryPoint, Guid nextId) nextChain = new DispatchTrackingIdentity() { Id = nextId, - EntryType = typeof(TAction) + EntryType = typeof(TAction), + Version = _currentVersion, + Tracker = _tracker }; + bool preCancel = _tracker.CreateExecutingAction(nextChain.Id, this, nextChain.Version); + if (!preCancel) + return; _tracker.CreateEntryPoint(nextChain.Id, this); } -#pragma warning disable S2737 // "catch" clauses should do more than rethrow + + + var disaptchMiddlewares = _serviceProvider.GetServices(); + var dispatchMiddlewareTasks = new List(); + foreach (var item in disaptchMiddlewares) + { + dispatchMiddlewareTasks.Add(item.BeforeDispatch(_action)); + } + await Task.WhenAll(dispatchMiddlewareTasks); + + try { var dispatcherService = _serviceProvider.GetRequiredService(); @@ -98,28 +113,24 @@ protected async Task ProcessDispatch(bool entryPoint, Guid nextId) if (_dispatchOrdering == DispatchOrdering.ReducersFirst) await RunReducer(nextChain); - if (_dispatchEffectExecutionBehavior == DispatchEffectExecutionBehavior.FireAndForget) - { - _ = RunEffects(nextChain, dispatcherService); - } - else - { - await RunEffects(nextChain, dispatcherService); - } + await RunEffects(nextChain, dispatcherService); if (_dispatchOrdering == DispatchOrdering.EffectsFirst) await RunReducer(nextChain); } - catch + catch (Exception ex) { - throw; + foreach (var item in disaptchMiddlewares) + _ = item.OnDispatchFailure(ex, _action); + + + + if (_forceSyncronous) + throw; } finally { - // if entry point just untrack current action - if (entryPoint && nextChain != default) - _tracker.DeleteEntryPoint(nextChain.Id); dispatchMiddlewareTasks = new List(); foreach (var item in disaptchMiddlewares) @@ -128,13 +139,11 @@ protected async Task ProcessDispatch(bool entryPoint, Guid nextId) } await Task.WhenAll(dispatchMiddlewareTasks); } -#pragma warning restore S2737 // "catch" clauses should do more than rethrow } public async Task DispatchAsync(bool asSafe = false) { - ValidateConfiguration(); if ((_action is ISafeAction) || asSafe) return await DispatchSafeAsync(); await DispatchFastAsync(); @@ -180,8 +189,8 @@ private async Task RunEffects(DispatchTrackingIdentity? nextChain, IDispatchFact foreach (var effectService in effectServices) { - if (nextChain != default && _tracker.IsCancelled(nextChain.Id)) - break; + if (nextChain != default && nextChain.Tracker.IsCancelled(nextChain.Id, nextChain.Version)) + return; bool validationPassed = await RunEffectValidators(effectService!.GetType(), effectMiddlewares); if (!validationPassed) @@ -195,23 +204,32 @@ private async Task RunEffects(DispatchTrackingIdentity? nextChain, IDispatchFact if (del(_action, dispatcherService.Dispatcher) is Task effectTask) { effects.Add(effectTask); - if (_dispatchEffectBehavior == DispatchEffectBehavior.Parallel || _dispatchEffectExecutionBehavior == DispatchEffectExecutionBehavior.FireAndForget) + if (!_forceSyncronous && _dispatchEffectBehavior == DispatchEffectBehavior.Parallel) _ = effectTask; else await effectTask; } } - if (_dispatchEffectExecutionBehavior == DispatchEffectExecutionBehavior.FireAndForget) - { - _ = Task.WhenAll(effects); - _ = effectMiddlewareTasks; - }else + Task allEffects = Task.WhenAll(effects); + + if (!allEffects.IsCompletedSuccessfully) + await allEffects; + + if (ServiceRegisterExt.ConfigureOptions.MiddlewareTaskBehavior != Configuration.MiddlewareTaskBehavior.Await) + _ = Task.Run(async () => + { + if (!effectMiddlewareTasks.IsCompletedSuccessfully) + await effectMiddlewareTasks; + await RunMiddlewareEffect(effectMiddlewares, p => p.AfterEffect(_action), p => p == MiddlewareEffectBehavior.PerGroupEffects); + }); + else { - await Task.WhenAll(effects); - await effectMiddlewareTasks; + if (!effectMiddlewareTasks.IsCompletedSuccessfully) + await effectMiddlewareTasks; + await RunMiddlewareEffect(effectMiddlewares, p => p.AfterEffect(_action), p => p == MiddlewareEffectBehavior.PerGroupEffects); } - _ = RunMiddlewareEffect(effectMiddlewares, p => p.AfterEffect(_action), p => p == MiddlewareEffectBehavior.PerGroupEffects); + } private async Task RunEffectValidators(Type effectService, IEnumerable effectMiddlewares) { @@ -251,8 +269,9 @@ private async Task RunReducer(DispatchTrackingIdentity? nextChain) foreach (var stateType in _statePulseRegistry.KnownStates) { - if (nextChain != default && _tracker.IsCancelled(nextChain.Id)) - break; + bool isCancelled = nextChain != default && nextChain.Tracker.IsCancelled(nextChain.Id, nextChain.Version); + if (isCancelled) + return; var reducerType = typeof(IReducer<,>).MakeGenericType(stateType, actionType); var stateAccessorType = _statePulseRegistry.KnownStateToAccessors[stateType]; var stateService = _serviceProvider.GetRequiredService(stateAccessorType); @@ -271,17 +290,32 @@ private async Task RunReducer(DispatchTrackingIdentity? nextChain) currentState, _action }!)!; + isCancelled = nextChain != default && nextChain.Tracker.IsCancelled(nextChain.Id, nextChain.Version); + if (isCancelled) + return; await reduceTask; - // make sure middlewares are done before starting to call after reduced - await middlewareTasks; + var newState = _statePulseRegistry.KnownReducersTaskResult[reducerType](reduceTask); if (newState == null) throw new InvalidOperationException("Reducer returned null state."); _statePulseRegistry.KnownStateAccessorsStateSetter[stateAccessorType](stateService, newState); - middlewareTasks = RunMiddlewareReducer(middlewares, p => p.AfterReducing(newState, _action)); - if (ServiceRegisterExt.ConfigureOptions.MiddlewareTaskBehavior == Configuration.MiddlewareTaskBehavior.Await) - await middlewareTasks; + // Regardless of settings ensure BeforeReducing is finished before calling after reducing. + if (ServiceRegisterExt.ConfigureOptions.MiddlewareTaskBehavior != Configuration.MiddlewareTaskBehavior.Await) + _ = Task.Run(async () => + { + if (!middlewareTasks.IsCompletedSuccessfully) + await middlewareTasks; + await RunMiddlewareReducer(middlewares, p => p.AfterReducing(newState, _action)); + }); + else + { + if (!middlewareTasks.IsCompletedSuccessfully) + await middlewareTasks; + await RunMiddlewareReducer(middlewares, p => p.AfterReducing(newState, _action)); + + } + } } } diff --git a/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper_Flags.cs b/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper_Flags.cs index b2e80ca..fb2ec7e 100644 --- a/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper_Flags.cs +++ b/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper_Flags.cs @@ -1,17 +1,12 @@ -ο»Ώ -using Microsoft.Extensions.DependencyInjection; -using StatePulse.Net.Configuration; -using StatePulse.Net.Engine.Exceptions; -using System.Collections.Concurrent; -using System.Reflection; +ο»Ώusing StatePulse.Net.Configuration; namespace StatePulse.Net.Engine.Implementations; + internal partial class DispatcherPrepper : IDispatcherPrepper where TAction : IAction where TActionChain : IAction { - + private DispatchEffectBehavior _dispatchEffectBehavior = ServiceRegisterExt.ConfigureOptions.DispatchEffectBehavior; - private DispatchEffectExecutionBehavior _dispatchEffectExecutionBehavior = ServiceRegisterExt.ConfigureOptions.DispatchEffectExecutionBehavior; private DispatchOrdering _dispatchOrdering = ServiceRegisterExt.ConfigureOptions.DispatchOrderBehavior; private bool _forceSyncronous; @@ -22,7 +17,8 @@ public IDispatcherPrepper Await() return this; } - public IDispatcherPrepper EffectsFirst() { + public IDispatcherPrepper EffectsFirst() + { _dispatchOrdering = DispatchOrdering.EffectsFirst; return this; } @@ -33,56 +29,20 @@ public IDispatcherPrepper ReducersFirst() return this; } - public IDispatcherPrepper ExecFireAndForget() - { - _dispatchEffectExecutionBehavior = DispatchEffectExecutionBehavior.FireAndForget; - return this; - } - public IDispatcherPrepper ExecYieldAndFire() - { - _dispatchEffectExecutionBehavior = DispatchEffectExecutionBehavior.YieldAndFire; - return this; - } public IDispatcherPrepper SequentialEffects() { _dispatchEffectBehavior = DispatchEffectBehavior.Sequential; return this; } - public IDispatcherPrepper ParallelEffects() { + public IDispatcherPrepper ParallelEffects() + { _dispatchEffectBehavior = DispatchEffectBehavior.Parallel; return this; } - private void ValidateConfiguration() - { - // FireAndForget can't be Sequential - if (_dispatchEffectExecutionBehavior == DispatchEffectExecutionBehavior.FireAndForget - && _dispatchEffectBehavior == DispatchEffectBehavior.Sequential) - { - throw new InvalidDispatchCombinationException( - "FireAndForget execution cannot be combined with Sequential effects. " + - "FireAndForget doesn't await effects, so ordering cannot be guaranteed. " + - "Use ExecYieldAndFire().SequentialEffects() or ExecFireAndForget().ParallelEffects()"); - } - // Await() is locked to YieldAndFire + Sequential - if (_forceSyncronous) - { - if (_dispatchEffectExecutionBehavior != DispatchEffectExecutionBehavior.YieldAndFire) - { - throw new InvalidDispatchCombinationException( - "Await() requires YieldAndFire execution. Cannot use ExecFireAndForget() with Await()"); - } - // REMOVED IT WOULD BREAK EXISTING PROJECTS - //if (_dispatchEffectBehavior != DispatchEffectBehavior.Sequential) - //{ - // throw new InvalidDispatchCombinationException( - // "Await() requires Sequential effects. Cannot use ParallelEffects() with Await()"); - //} - } - } } diff --git a/src/StatePulse.NET/Engine/Implementations/StateAccessor.cs b/src/StatePulse.NET/Engine/Implementations/StateAccessor.cs index 1917904..a12ae23 100644 --- a/src/StatePulse.NET/Engine/Implementations/StateAccessor.cs +++ b/src/StatePulse.NET/Engine/Implementations/StateAccessor.cs @@ -9,6 +9,8 @@ public StateAccessor() { InitializeState(); } + public DateTime LastChange { get; set; } + public long Version { get; set; } private TState _state = default!; public TState State { @@ -18,6 +20,7 @@ public TState State // make sure state can never be set null always has a default state. if (value == null) InitializeState(); else _state = value; + LastChange = DateTime.UtcNow; OnStateChanged?.Invoke(this, _state); OnStateChangedNoDetails?.Invoke(this, new EventArgs()); } diff --git a/src/StatePulse.NET/ServiceRegisterExt.cs b/src/StatePulse.NET/ServiceRegisterExt.cs index bd3ad6a..65e19bf 100644 --- a/src/StatePulse.NET/ServiceRegisterExt.cs +++ b/src/StatePulse.NET/ServiceRegisterExt.cs @@ -1,6 +1,7 @@ ο»Ώusing Microsoft.Extensions.DependencyInjection; using StatePulse.Net.Configuration; using StatePulse.Net.Engine; +using StatePulse.Net.Engine.Exceptions; using StatePulse.Net.Engine.Implementations; using System.Reflection; @@ -8,6 +9,7 @@ namespace StatePulse.Net; public static class ServiceRegisterExt { + private static bool _scanned; public static ConfigureOptions ConfigureOptions { get; set; } = new ConfigureOptions(); private static StatePulseRegistry Registry = new StatePulseRegistry(); @@ -15,10 +17,9 @@ public static class ServiceRegisterExt public static IServiceCollection AddStatePulseServices(this IServiceCollection services, Action configure) { - services.AddTransient(); - services.AddTransient(); + services.AddScoped(); + services.AddScoped(); configure(ConfigureOptions); - ConfigureOptions.ValidateConfiguration(); bool isSingleThreadModel = ConfigureOptions.PulseTrackingPerformance == PulseTrackingModel.SingleThreadFast || ConfigureOptions.PulseTrackingPerformance == PulseTrackingModel.BlazorWebAssemblyFast; if (isSingleThreadModel) @@ -28,62 +29,45 @@ public static IServiceCollection AddStatePulseServices(this IServiceCollection s services.AddScoped(); services.AddSingleton(Registry); + services.AutoRegisterTypes(ConfigureOptions.AutoRegisterTypes); services.ScanStatePulseAssemblies(ConfigureOptions.ScanAssemblies); + return services; + } + public static IServiceCollection AddStatePulseService(this IServiceCollection services) + { + services.AddStatePulseService(typeof(TImplementation)); + return services; + } + public static IServiceCollection AddStatePulseService(this IServiceCollection services, Type implementation) + { + services.RegisterTypeService(implementation); return services; } - public static IServiceCollection AddStatePulseEffect(this IServiceCollection services) + private static void AutoRegisterTypes(this IServiceCollection services, Type[] types) { - var implType = typeof(TImplementation); - - var effectInterface = implType.GetInterfaces().FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEffect<>)); - if (effectInterface == null) - throw new InvalidOperationException($"{implType.Name} must implement {typeof(IEffect<>).Name}"); - return services.AddStatePulseEffect(effectInterface!, implType); + foreach (var type in types) + services.AddStatePulseService(type); } - private static IServiceCollection AddStatePulseEffect(this IServiceCollection services, Type iFace, Type implementation) { if (services.IsImplementationRegistered(iFace, implementation)) return services; - bool isSingletonFeature = implementation.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEffectSingleton<>)); - - if (!isSingletonFeature) - services.AddScoped(iFace, implementation); - else - services.AddSingleton(iFace, implementation); + services.AddTransient(iFace, implementation); Registry.RegisterEffect(iFace, implementation); return services; } - public static IServiceCollection AddStatePulseReducer(this IServiceCollection services) - { - var implType = typeof(TImplementation); - - var reducerInterface = implType.GetInterfaces().FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IReducer<,>)); - if (reducerInterface == null) - throw new InvalidOperationException($"{implType.Name} must implement {typeof(IReducer<,>).Name}"); - - return services.AddStatePulseReducer(reducerInterface!, implType); - } private static IServiceCollection AddStatePulseReducer(this IServiceCollection services, Type iFace, Type implementation) { if (services.IsReducerRegistered(iFace)) return services; - bool isSingleton = implementation.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IReducerSingleton<,>)); - if (!isSingleton) - services.AddScoped(iFace, implementation); - else - services.AddSingleton(iFace, implementation); + services.AddTransient(iFace, implementation); Registry.RegisterReducer(iFace, implementation); return services; } - public static IServiceCollection AddStatePulseStateFeature(this IServiceCollection services) - where TImplementation : IStateFeature - => services.AddStatePulseStateFeature(typeof(TImplementation)); - private static IServiceCollection AddStatePulseStateFeature(this IServiceCollection services, Type implementation) { var accessorType = typeof(IStateAccessor<>).MakeGenericType(implementation); @@ -105,32 +89,14 @@ private static IServiceCollection AddStatePulseStateFeature(this IServiceCollect return services; } - public static IServiceCollection AddStatePulseEffectValidator(this IServiceCollection services) - { - var implType = typeof(TImplementation); - - var validatorInterface = implType.GetInterfaces().FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEffectValidator<,>)); - if (validatorInterface == null) - throw new InvalidOperationException($"{implType.Name} must implement {typeof(IEffectValidator<,>).Name}"); - - - return services.AddStatePulseEffectValidator(validatorInterface!, implType); - } private static IServiceCollection AddStatePulseEffectValidator(this IServiceCollection services, Type iFace, Type implementation) { if (services.IsEffectValidatorImplementationRegistered(implementation)) return services; - bool isSingleton = implementation.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEffectValidator<,>)); - if (isSingleton) - services.AddScoped(iFace, implementation); - else - services.AddSingleton(iFace, implementation); + services.AddTransient(iFace, implementation); Registry.RegisterEffectValidator(iFace, implementation); return services; } - - public static IServiceCollection AddStatePulseAction(this IServiceCollection services) where TImplementation : IAction - => services.AddStatePulseAction(typeof(TImplementation)); private static IServiceCollection AddStatePulseAction(this IServiceCollection services, Type implementation) { @@ -155,78 +121,56 @@ private static void ScanStatePulseAssemblies(this IServiceCollection services, p if (_scanned) return; _scanned = true; + foreach (var assembly in assemblies) + { + var types = assembly.GetTypes().Where(p => (!p.IsAbstract && !p.IsInterface)).ToArray(); + services.AutoRegisterTypes(types); + } + } + + private static void RegisterTypeService(this IServiceCollection services, Type type) + { + + if (type.IsAbstract || type.IsInterface) + throw new UnableToRegisterExplicitServiceException($"{type.Name} is Abstract or Interface!"); + foreach (var iface in type.GetInterfaces()) + services.RegisterSelfDetectedInterface(iface, type); + + } + + private static void RegisterSelfDetectedInterface(this IServiceCollection services, Type iface, Type type) + { var effectMiddlewareType = typeof(IEffectMiddleware); var reducerMiddlewareType = typeof(IReducerMiddleware); var dispatchMiddlewareType = typeof(IDispatcherMiddleware); var effectType = typeof(IEffect<>); var reducerType = typeof(IReducer<,>); var stateFeatureType = typeof(IStateFeature); + var stateFeatureSingletonType = typeof(IStateFeatureSingleton); var actionType = typeof(IAction); var actionSafeType = typeof(ISafeAction); var actionValidatorType = typeof(IEffectValidator<,>); - foreach (var assembly in assemblies) - { - var types = assembly.GetTypes(); - - foreach (var type in types) - { - if (type.IsAbstract || type.IsInterface) - continue; - - var interfaces = type.GetInterfaces(); - foreach (var iface in interfaces) - { - // TODO: Allow Extension MEthods to manually add each types and perform registration. - - if (!iface.IsGenericType && - (iface == effectMiddlewareType || iface == reducerMiddlewareType || iface == dispatchMiddlewareType)) - { - if (services.IsImplementationRegistered(type, iface)) continue; - bool isSingletonEffectMiddleware = typeof(IEffectMiddlewareSingleton).IsAssignableFrom(type); - bool isSingletonReducerMiddleware = typeof(IReducerMiddleware).IsAssignableFrom(type); - bool isSingletonDispatcherMiddleware = typeof(IDispatcherMiddlewareSingleton).IsAssignableFrom(type); - bool isSingleton = isSingletonEffectMiddleware || isSingletonReducerMiddleware || isSingletonDispatcherMiddleware; - if (!isSingleton) - services.AddScoped(iface, type); - else - services.AddSingleton(iface, type); - continue; - } - - if (iface.IsGenericType && iface.GetGenericTypeDefinition() == effectType) - { - services.AddStatePulseEffect(iface, type); - continue; - } - - if (iface.IsGenericType && iface.GetGenericTypeDefinition() == reducerType) - { - services.AddStatePulseReducer(iface, type); - continue; - } - - if (!iface.IsGenericType && iface == stateFeatureType) - { - services.AddStatePulseStateFeature(type); - continue; - } - - if (iface.IsGenericType && iface.GetGenericTypeDefinition() == actionValidatorType) - { - services.AddStatePulseEffectValidator(iface, type); - continue; - } - - if (!iface.IsGenericType && (iface == actionType || iface == actionSafeType)) - { - services.AddStatePulseAction(type); - } - } - } - } - - + bool isMiddlewareType = !iface.IsGenericType && + (iface == effectMiddlewareType || iface == reducerMiddlewareType || iface == dispatchMiddlewareType) && + !services.IsImplementationRegistered(type, iface); + + if (isMiddlewareType) + services.AddTransient(iface, type); + else if (!iface.IsGenericType && (iface == actionType || iface == actionSafeType)) + services.AddStatePulseAction(type); + else if (!iface.IsGenericType && (iface == stateFeatureType || iface == stateFeatureSingletonType)) + services.AddStatePulseStateFeature(type); + + if (!iface.IsGenericType) return; + + var genericDef = iface.GetGenericTypeDefinition(); + if (iface.IsGenericType && genericDef == effectType) + services.AddStatePulseEffect(iface, type); + else if (iface.IsGenericType && genericDef == reducerType) + services.AddStatePulseReducer(iface, type); + else if (genericDef == actionValidatorType) + services.AddStatePulseEffectValidator(iface, type); } diff --git a/src/StatePulse.Net.Abstractions/IDispatcherMiddleware.cs b/src/StatePulse.Net.Abstractions/IDispatcherMiddleware.cs index 9a4c28e..e4b2385 100644 --- a/src/StatePulse.Net.Abstractions/IDispatcherMiddleware.cs +++ b/src/StatePulse.Net.Abstractions/IDispatcherMiddleware.cs @@ -1,6 +1,8 @@ ο»Ώnamespace StatePulse.Net; + public interface IDispatcherMiddleware { Task BeforeDispatch(object action); + Task OnDispatchFailure(Exception exception, object action); Task AfterDispatch(object action); } diff --git a/src/StatePulse.Net.Abstractions/IDispatcherMiddlewareSingleton.cs b/src/StatePulse.Net.Abstractions/IDispatcherMiddlewareSingleton.cs deleted file mode 100644 index ecb672d..0000000 --- a/src/StatePulse.Net.Abstractions/IDispatcherMiddlewareSingleton.cs +++ /dev/null @@ -1,4 +0,0 @@ -ο»Ώnamespace StatePulse.Net; -public interface IDispatcherMiddlewareSingleton: IDispatcherMiddleware -{ -} diff --git a/src/StatePulse.Net.Abstractions/IDispatcherPrepper.cs b/src/StatePulse.Net.Abstractions/IDispatcherPrepper.cs index cfd1d3d..6e67d2c 100644 --- a/src/StatePulse.Net.Abstractions/IDispatcherPrepper.cs +++ b/src/StatePulse.Net.Abstractions/IDispatcherPrepper.cs @@ -1,4 +1,5 @@ ο»Ώnamespace StatePulse.Net; + public interface IDispatcherPrepper where TAction : IAction { TAction ActionInstance { get; } @@ -6,8 +7,6 @@ public interface IDispatcherPrepper where TAction : IAction Task DispatchAsync(bool asSafe = false); IDispatcherPrepper EffectsFirst(); IDispatcherPrepper ReducersFirst(); - IDispatcherPrepper ExecFireAndForget(); - IDispatcherPrepper ExecYieldAndFire(); IDispatcherPrepper SequentialEffects(); IDispatcherPrepper ParallelEffects(); diff --git a/src/StatePulse.Net.Abstractions/IEffectMiddlewareSingleton.cs b/src/StatePulse.Net.Abstractions/IEffectMiddlewareSingleton.cs deleted file mode 100644 index 9234b30..0000000 --- a/src/StatePulse.Net.Abstractions/IEffectMiddlewareSingleton.cs +++ /dev/null @@ -1,11 +0,0 @@ -ο»Ώusing System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace StatePulse.Net; - -public interface IEffectMiddlewareSingleton : IEffectMiddleware -{ -} diff --git a/src/StatePulse.Net.Abstractions/IEffectSingleton.cs b/src/StatePulse.Net.Abstractions/IEffectSingleton.cs deleted file mode 100644 index 7c19df9..0000000 --- a/src/StatePulse.Net.Abstractions/IEffectSingleton.cs +++ /dev/null @@ -1,12 +0,0 @@ -ο»Ώusing System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace StatePulse.Net; - -public interface IEffectSingleton : IEffect - where TAction : IAction -{ -} diff --git a/src/StatePulse.Net.Abstractions/IEffectValidationSingleton.cs b/src/StatePulse.Net.Abstractions/IEffectValidationSingleton.cs deleted file mode 100644 index 726d82f..0000000 --- a/src/StatePulse.Net.Abstractions/IEffectValidationSingleton.cs +++ /dev/null @@ -1,13 +0,0 @@ -ο»Ώusing System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace StatePulse.Net; - -internal interface IEffectValidationSingleton : IEffectValidator - where TAction : IAction - where TEffect : IEffect -{ -} diff --git a/src/StatePulse.Net.Abstractions/IReducerMiddlewareSingleton.cs b/src/StatePulse.Net.Abstractions/IReducerMiddlewareSingleton.cs deleted file mode 100644 index 1a603b1..0000000 --- a/src/StatePulse.Net.Abstractions/IReducerMiddlewareSingleton.cs +++ /dev/null @@ -1,11 +0,0 @@ -ο»Ώusing System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace StatePulse.Net; - -public interface IReducerMiddlewareSingleton : IReducerMiddleware -{ -} diff --git a/src/StatePulse.Net.Abstractions/IReducerSingleton.cs b/src/StatePulse.Net.Abstractions/IReducerSingleton.cs deleted file mode 100644 index 46d85d0..0000000 --- a/src/StatePulse.Net.Abstractions/IReducerSingleton.cs +++ /dev/null @@ -1,13 +0,0 @@ -ο»Ώusing System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace StatePulse.Net; - -public interface IReducerSingleton : IReducer - where TState : IStateFeature - where TAction : IAction -{ -} diff --git a/src/StatePulse.Net.Abstractions/IStateAccessor.cs b/src/StatePulse.Net.Abstractions/IStateAccessor.cs index 965d1ae..f85997a 100644 --- a/src/StatePulse.Net.Abstractions/IStateAccessor.cs +++ b/src/StatePulse.Net.Abstractions/IStateAccessor.cs @@ -1,8 +1,11 @@ ο»Ώnamespace StatePulse.Net; + public delegate void OnChangeEventHandler(object sender, T args); public interface IStateAccessor { TState State { get; } + DateTime LastChange { get; } + long Version { get; } event OnChangeEventHandler? OnStateChanged; event EventHandler? OnStateChangedNoDetails; diff --git a/tests/StatPulse.NET.Tests/TestBase.cs b/tests/StatPulse.NET.Tests/TestBase.cs index 72cc2ae..8e7e459 100644 --- a/tests/StatPulse.NET.Tests/TestBase.cs +++ b/tests/StatPulse.NET.Tests/TestBase.cs @@ -15,6 +15,7 @@ using StatePulse.NET.Tests.TestCases.Pulsars.Profile.Store; namespace StatePulse.NET.Tests; + public abstract class TestBase : IDisposable { protected IServiceProvider ServiceProvider { get; set; } @@ -24,36 +25,37 @@ protected TestBase() ServiceCollection = new ServiceCollection(); // TOOD: Remove Scan Add Manual for Tests which is best policy would most lekily avoid inconsistent // service exceptions du to thread safe on bulk testing. - ServiceCollection.AddStatePulseServices(o => { - + ServiceCollection.AddStatePulseServices(o => + { + }); - ServiceCollection.AddStatePulseAction(); - ServiceCollection.AddStatePulseAction(); - ServiceCollection.AddStatePulseAction(); - ServiceCollection.AddStatePulseAction(); - ServiceCollection.AddStatePulseAction(); - ServiceCollection.AddStatePulseAction(); - ServiceCollection.AddStatePulseAction(); - ServiceCollection.AddStatePulseAction(); - ServiceCollection.AddStatePulseAction(); - ServiceCollection.AddStatePulseAction(); - ServiceCollection.AddStatePulseEffect(); - ServiceCollection.AddStatePulseEffect(); - ServiceCollection.AddStatePulseEffect(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); - ServiceCollection.AddStatePulseEffectValidator(); - ServiceCollection.AddStatePulseEffectValidator(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); - ServiceCollection.AddStatePulseReducer(); - ServiceCollection.AddStatePulseReducer(); - ServiceCollection.AddStatePulseReducer(); - ServiceCollection.AddStatePulseReducer(); - ServiceCollection.AddStatePulseReducer(); - ServiceCollection.AddStatePulseReducer(); - ServiceCollection.AddStatePulseStateFeature(); - ServiceCollection.AddStatePulseStateFeature(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); - ServiceCollection.AddStatePulseStateFeature(); + ServiceCollection.AddStatePulseService(); // Register your services ServiceProvider = ServiceCollection.BuildServiceProvider(); } diff --git a/tests/StatPulse.NET.Tests/TestCases/InitializerTests/StatePulseInitTests.cs b/tests/StatPulse.NET.Tests/TestCases/InitializerTests/StatePulseInitTests.cs index bbc35cb..49b05a2 100644 --- a/tests/StatPulse.NET.Tests/TestCases/InitializerTests/StatePulseInitTests.cs +++ b/tests/StatPulse.NET.Tests/TestCases/InitializerTests/StatePulseInitTests.cs @@ -1,5 +1,4 @@ -ο»Ώusing Microsoft.Diagnostics.Tracing.Parsers.MicrosoftWindowsWPF; -using Microsoft.Extensions.DependencyInjection; +ο»Ώusing Microsoft.Extensions.DependencyInjection; using StatePulse.Net; using StatePulse.Net.Engine; using StatePulse.NET.Tests.TestCases.Pulsars.Counter.Actions; @@ -8,6 +7,7 @@ using StatePulse.NET.Tests.TestCases.Pulsars.MainMenu.Store; using StatePulse.NET.Tests.TestCases.Pulsars.Profile.Actions; using StatePulse.NET.Tests.TestCases.Pulsars.Profile.Store; +using System.Diagnostics; namespace StatePulse.NET.Tests.TestCases.InitializerTests; @@ -69,41 +69,60 @@ await dispatcher.Prepare().With(p => p.TestData, name) [Fact] public async Task DispatchingBurstShouldTriggerSafetyCancel() { - var dispatcher = ServiceProvider.GetRequiredService(); - var tracker = ServiceProvider.GetRequiredService>(); - var stateAccessor = ServiceProvider.GetRequiredService>(); + var scopedServices = ServiceProvider.CreateScope().ServiceProvider; + var dispatcher = scopedServices.GetRequiredService(); + var stateAccessor = scopedServices.GetRequiredService>(); + var tracker = scopedServices.GetRequiredService>(); + var tracker2 = scopedServices.GetRequiredService>(); + int cancelled = 0; + tracker.OnCancel += (o, action) => + { + + cancelled++; + }; // Dispatch action that changes state int changes = 0; stateAccessor.OnStateChanged += (s, state) => { changes++; }; - Guid a = Guid.Empty, b = Guid.Empty; - bool cont = false, aDone = false, bDone = false; - tracker.OnCancel += (o, action) => - { - if (action.Id == a) aDone = true; - if (action.Id == b) bDone = true; - if (aDone && bDone) cont = true; - }; - List result = new(); - for (int i = 0; i < 100; i++) + List dispatches = new(); + Random random = new Random(); + int[] timing = [ + 50, // Entry + 25, // Cancels 0 + 75, // + 50, + 25, + 50, + 1000, + 25, + 50, + 25 + ]; + string winingValue = $"Profile"; + List possibleRaceConditions = new(); + for (int i = 0; i < 10; i++) { - a = await dispatcher.Prepare() - .With(p => p.TestData, "Profile 1") + winingValue = $"Profile {random.Next()}"; + var id = await dispatcher.Prepare() + .With(p => p.TestData, winingValue) + .With(p => p.Delay, timing[i]) .DispatchAsync(true); + dispatches.Add(id); + possibleRaceConditions.Add(winingValue); + } + await Task.Delay(timing.Sum()); - b = await dispatcher.Prepare() - .With(p => p.TestData, "Profile 2") - .DispatchAsync(true); - while (!cont) { await Task.Delay(100); } - cont = false; - result.Add(stateAccessor.State.ProfileName!); - } - foreach (var item in result) - Assert.Equal("Profile 2", item); - Assert.True(result.Count > 0); + do + { + + + } while (changes <= 0); + bool isPassing = stateAccessor.State.ProfileName == possibleRaceConditions.Last(); + if (!isPassing) Debugger.Break(); + Assert.True(isPassing); } [Fact] diff --git a/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Middlewares/MainMenuLoaderStartDispatchMiddleware.cs b/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Middlewares/MainMenuLoaderStartDispatchMiddleware.cs index 054b248..e632d46 100644 --- a/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Middlewares/MainMenuLoaderStartDispatchMiddleware.cs +++ b/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Middlewares/MainMenuLoaderStartDispatchMiddleware.cs @@ -1,6 +1,7 @@ ο»Ώusing StatePulse.Net; namespace StatePulse.NET.Tests.TestCases.Pulsars.MainMenu.Middlewares; + internal class MainMenuLoaderStartDispatchMiddleware : IDispatcherMiddleware, IEffectMiddleware, IReducerMiddleware { public Task AfterDispatch(object action) @@ -39,6 +40,9 @@ public Task BeforeReducing(object state, object action) return Task.CompletedTask; } + public Task OnDispatchFailure(Exception exception, object action) + => Task.CompletedTask; + public Task WhenEffectValidationFailed(object action, object effectValidator) { Console.WriteLine($"{action.GetType().Name} {effectValidator.GetType().Name}r Executed."); diff --git a/tests/StatPulse.NET.Tests/TestCases/Pulsars/Profile/Actions/ProfileCardDefineAction.cs b/tests/StatPulse.NET.Tests/TestCases/Pulsars/Profile/Actions/ProfileCardDefineAction.cs index afbf995..b7bd5f2 100644 --- a/tests/StatPulse.NET.Tests/TestCases/Pulsars/Profile/Actions/ProfileCardDefineAction.cs +++ b/tests/StatPulse.NET.Tests/TestCases/Pulsars/Profile/Actions/ProfileCardDefineAction.cs @@ -1,7 +1,9 @@ ο»Ώusing StatePulse.Net; namespace StatePulse.NET.Tests.TestCases.Pulsars.Profile.Actions; + public record ProfileCardDefineAction : IAction { public string? TestData { get; set; } + public int Delay { get; set; } = 100; } diff --git a/tests/StatPulse.NET.Tests/TestCases/Pulsars/Profile/Effects/ProfileCardDefineEffect.cs b/tests/StatPulse.NET.Tests/TestCases/Pulsars/Profile/Effects/ProfileCardDefineEffect.cs index 30bd075..f826e8e 100644 --- a/tests/StatPulse.NET.Tests/TestCases/Pulsars/Profile/Effects/ProfileCardDefineEffect.cs +++ b/tests/StatPulse.NET.Tests/TestCases/Pulsars/Profile/Effects/ProfileCardDefineEffect.cs @@ -3,6 +3,7 @@ using StatePulse.NET.Tests.TestCases.Pulsars.Profile.Actions; using StatePulse.NET.Tests.TestCases.Pulsars.Shared.Contracts.Response; namespace StatePulse.NET.Tests.TestCases.Pulsars.Profile.Effects; + internal class ProfileCardDefineEffect : IEffect { private readonly IStateAccessor _stateAccessor; @@ -14,10 +15,8 @@ public ProfileCardDefineEffect(IStateAccessor stateAccessor) public async Task EffectAsync(ProfileCardDefineAction action, IDispatcher dispatcher) { await dispatcher.Prepare().DispatchAsync(); - var random = new Random(); - int value = random.Next(100, 1001); // Upper bound is exclusive, so use 1001 - await Task.Delay(value); + await Task.Delay(action.Delay); var myProfile = new UserResponse(); await dispatcher.Prepare(() => new ProfileCardDefineResultAction(action.TestData ?? myProfile.Name, myProfile.Picture, myProfile.Id) { UnitTestStringer = action.TestData }).DispatchAsync(); await dispatcher.Prepare().DispatchAsync(); From 068cc4cb80354e91c4a62d2f04956d42eef7ca47 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Tue, 13 Jan 2026 12:12:40 +0200 Subject: [PATCH 15/27] fix --- .../Configuration/ConfigureOptions.cs | 10 +- src/StatePulse.NET/Engine/DispatchEntry.cs | 6 +- .../Engine/DispatchFactoryElement.cs | 16 +++ src/StatePulse.NET/Engine/IDispatchEntry.cs | 6 + src/StatePulse.NET/Engine/IDispatchFactory.cs | 6 +- src/StatePulse.NET/Engine/IDispatchTracker.cs | 17 +-- .../Engine/Implementations/DispatchFactory.cs | 13 ++- .../Engine/Implementations/DispatchTracker.cs | 12 +- .../DispatchTrackingIdentity.cs | 3 +- .../Implementations/DispatcherPrepper.cs | 105 ++++++++++-------- .../Engine/Implementations/StateAccessor.cs | 18 ++- .../Implementations/StatePulseRegistry.cs | 60 +++++++++- .../IStateAccessor.cs | 7 +- .../IStatePulseRegistry.cs | 6 +- .../StateVersioning.cs | 16 +++ .../InitializerTests/StatePulseInitTests.cs | 33 +++--- 16 files changed, 221 insertions(+), 113 deletions(-) create mode 100644 src/StatePulse.NET/Engine/DispatchFactoryElement.cs create mode 100644 src/StatePulse.NET/Engine/IDispatchEntry.cs create mode 100644 src/StatePulse.Net.Abstractions/StateVersioning.cs diff --git a/src/StatePulse.NET/Configuration/ConfigureOptions.cs b/src/StatePulse.NET/Configuration/ConfigureOptions.cs index bc26574..212087c 100644 --- a/src/StatePulse.NET/Configuration/ConfigureOptions.cs +++ b/src/StatePulse.NET/Configuration/ConfigureOptions.cs @@ -14,12 +14,16 @@ public class ConfigureOptions public PulseTrackingModel PulseTrackingPerformance { get; set; } = PulseTrackingModel.ThreadSafe; public Assembly[] ScanAssemblies { get; set; } = new Assembly[] { }; public Type[] AutoRegisterTypes { get; set; } = new Type[] { }; - private long _versionTicker; + private long _versionTicker; + private readonly static Object _lock = new(); public long GetNextVersion() { - var next = Interlocked.Increment(ref _versionTicker); - return next; + lock (_lock) + { + var next = Interlocked.Increment(ref _versionTicker); + return next; + } } } diff --git a/src/StatePulse.NET/Engine/DispatchEntry.cs b/src/StatePulse.NET/Engine/DispatchEntry.cs index f070b31..fa53707 100644 --- a/src/StatePulse.NET/Engine/DispatchEntry.cs +++ b/src/StatePulse.NET/Engine/DispatchEntry.cs @@ -1,7 +1,7 @@ ο»Ώnamespace StatePulse.Net.Engine; using StatePulse.Net; -public class DispatchEntry where TAction : IAction +public class DispatchEntry : IDispatchEntry where TAction : IAction { private readonly IDispatcherPrepper _action; private readonly Guid _guid; @@ -30,6 +30,8 @@ public void Cancel() } } - public bool IsCancelled => _disposed == 1 || _tokenSource.IsCancellationRequested; + public bool IsCancelled => + Volatile.Read(ref _disposed) == 1 || + _tokenSource.IsCancellationRequested; } diff --git a/src/StatePulse.NET/Engine/DispatchFactoryElement.cs b/src/StatePulse.NET/Engine/DispatchFactoryElement.cs new file mode 100644 index 0000000..a3cd926 --- /dev/null +++ b/src/StatePulse.NET/Engine/DispatchFactoryElement.cs @@ -0,0 +1,16 @@ +ο»Ώusing StatePulse.Net.Engine; +using StatePulse.Net.Engine.Implementations; + +namespace StatePulse.Net; + +internal class DispatchFactoryElement +{ + public DispatchFactoryElement(Dispatcher dispatcher) + { + Handler = dispatcher; + Dispatcher = dispatcher; + } + + public IDispatchHandler Handler { get; } + public IDispatcher Dispatcher { get; } +} diff --git a/src/StatePulse.NET/Engine/IDispatchEntry.cs b/src/StatePulse.NET/Engine/IDispatchEntry.cs new file mode 100644 index 0000000..1a53e30 --- /dev/null +++ b/src/StatePulse.NET/Engine/IDispatchEntry.cs @@ -0,0 +1,6 @@ +ο»Ώnamespace StatePulse.Net.Engine; + +public interface IDispatchEntry +{ + bool IsCancelled { get; } +} diff --git a/src/StatePulse.NET/Engine/IDispatchFactory.cs b/src/StatePulse.NET/Engine/IDispatchFactory.cs index c298062..6981bf4 100644 --- a/src/StatePulse.NET/Engine/IDispatchFactory.cs +++ b/src/StatePulse.NET/Engine/IDispatchFactory.cs @@ -1,6 +1,6 @@ ο»Ώnamespace StatePulse.Net.Engine; -public interface IDispatchFactory + +internal interface IDispatchFactory { - IDispatcher Dispatcher { get; } - IDispatchHandler DispatchHandler { get; } + DispatchFactoryElement CreateDispatch(); } diff --git a/src/StatePulse.NET/Engine/IDispatchTracker.cs b/src/StatePulse.NET/Engine/IDispatchTracker.cs index e50b042..d04cb82 100644 --- a/src/StatePulse.NET/Engine/IDispatchTracker.cs +++ b/src/StatePulse.NET/Engine/IDispatchTracker.cs @@ -1,6 +1,4 @@ -ο»Ώusing System.Collections.Concurrent; - -namespace StatePulse.Net.Engine; +ο»Ώnamespace StatePulse.Net.Engine; public interface IDispatchTracker { @@ -10,13 +8,8 @@ public interface IDispatchTracker } public interface IDispatchTracker : IDispatchTracker where TAction : IAction { - public ConcurrentDictionary> CancellationTracker { get; } - public EventHandler>? OnCancel { get; set; } - public EventHandler>? OnEntry { get; set; } - public void CreateEntryPoint(Guid id, object action); - public void DeleteEntryPoint(Guid id); - public void CancelDispatchFor(Guid id); - public void CancelAll(); - public bool IsCancelled(Guid id); - + IDispatchEntry CreateEntryPoint(Guid id, object action); + void DeleteEntryPoint(Guid id); + void CancelDispatchFor(Guid id); + void CancelAll(); } diff --git a/src/StatePulse.NET/Engine/Implementations/DispatchFactory.cs b/src/StatePulse.NET/Engine/Implementations/DispatchFactory.cs index 49f0879..7c8b0de 100644 --- a/src/StatePulse.NET/Engine/Implementations/DispatchFactory.cs +++ b/src/StatePulse.NET/Engine/Implementations/DispatchFactory.cs @@ -2,12 +2,15 @@ internal class DispatchFactory : IDispatchFactory { - private readonly Dispatcher _dispatcher; + private readonly IServiceProvider _serviceProvider; + public DispatchFactory(IServiceProvider serviceProvider) { - _dispatcher = new Dispatcher(serviceProvider); + _serviceProvider = serviceProvider; + } + public DispatchFactoryElement CreateDispatch() + { + var dispatch = new Dispatcher(_serviceProvider); + return new DispatchFactoryElement(dispatch); } - public IDispatcher Dispatcher => _dispatcher; - - public IDispatchHandler DispatchHandler => _dispatcher; } diff --git a/src/StatePulse.NET/Engine/Implementations/DispatchTracker.cs b/src/StatePulse.NET/Engine/Implementations/DispatchTracker.cs index 05c55a1..7e27377 100644 --- a/src/StatePulse.NET/Engine/Implementations/DispatchTracker.cs +++ b/src/StatePulse.NET/Engine/Implementations/DispatchTracker.cs @@ -29,15 +29,17 @@ public bool CreateExecutingAction(Guid id, object action, long version) // If original == current, I successfully promoted return original == current; + } - public void CreateEntryPoint(Guid id, object action) + public IDispatchEntry CreateEntryPoint(Guid id, object action) { CancelAll(); var item = new DispatchEntry(id, (IDispatcherPrepper)action); _cancelTracker.TryAdd(id, item); OnEntry?.Invoke(this, item); + return item; } public void DeleteEntryPoint(Guid id) @@ -59,20 +61,12 @@ public void CancelDispatchFor(Guid id) } } - public bool IsCancelled(Guid id) - { - if (!_cancelTracker.TryGetValue(id, out var entry)) - return true; - return entry.IsCancelled; - } - public void CancelAll() { foreach (var item in _cancelTracker.Keys) DeleteEntryPoint(item); } - public bool CreateEntryPoint(Guid id, object action, long version) => throw new NotImplementedException(); public bool IsCancelled(Guid id, long version) { long current = Volatile.Read(ref _currentVersion); diff --git a/src/StatePulse.NET/Engine/Implementations/DispatchTrackingIdentity.cs b/src/StatePulse.NET/Engine/Implementations/DispatchTrackingIdentity.cs index 7b6c37b..f9eaef4 100644 --- a/src/StatePulse.NET/Engine/Implementations/DispatchTrackingIdentity.cs +++ b/src/StatePulse.NET/Engine/Implementations/DispatchTrackingIdentity.cs @@ -4,6 +4,7 @@ public record DispatchTrackingIdentity { public Guid Id { get; init; } public Type EntryType { get; init; } = default!; + public IDispatchEntry TrackedEntry { get; set; } = default!; public long Version { get; init; } - public IDispatchTracker Tracker { get; init; } = default!; + public Func Tracker { get; init; } = default!; } diff --git a/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs b/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs index 051dbb6..9217434 100644 --- a/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs +++ b/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs @@ -13,7 +13,7 @@ internal partial class DispatcherPrepper : IDispatcherPre private readonly IStatePulseRegistry _statePulseRegistry; private readonly DispatchTrackingIdentity? _chainKey; private readonly IDispatchTracker _tracker; - private readonly long _currentVersion; + private long _currentVersion = -1; public DispatcherPrepper(TAction action, IServiceProvider serviceProvider, DispatchTrackingIdentity? chainKey) { _action = action!; @@ -22,16 +22,12 @@ public DispatcherPrepper(TAction action, IServiceProvider serviceProvider, Dispa _chainKey = chainKey; var trackerTypeAction = typeof(IDispatchTracker<>).MakeGenericType(typeof(TActionChain)); _tracker = (IDispatchTracker)_serviceProvider.GetRequiredService(trackerTypeAction); - _currentVersion = ServiceRegisterExt.ConfigureOptions.GetNextVersion(); - } public TAction ActionInstance => _action; public async Task DispatchFastAsync() { - if (_chainKey != default && _chainKey.Tracker.IsCancelled(_chainKey.Id, _chainKey.Version)) - return; if (_chainKey == default) if (_forceSyncronous) await ProcessDispatch(false, Guid.Empty); @@ -39,7 +35,7 @@ public async Task DispatchFastAsync() _ = ProcessDispatch(false, Guid.Empty); else { - if (_chainKey.Tracker.IsCancelled(_chainKey.Id, _chainKey.Version)) + if (IsChainCancelled()) return; if (_forceSyncronous) await ProcessDispatch(false, Guid.Empty); @@ -63,7 +59,7 @@ public async Task DispatchSafeAsync() else { // ignore requested dispatch if cancelled - if (!_tracker.IsCancelled(_chainKey.Id, _chainKey.Version)) + if (!IsChainCancelled()) if (_forceSyncronous) await ProcessDispatch(false, Guid.Empty); else @@ -82,17 +78,18 @@ protected async Task ProcessDispatch(bool entryPoint, Guid nextId) var nextChain = _chainKey; if (entryPoint) { + _currentVersion = ServiceRegisterExt.ConfigureOptions.GetNextVersion(); nextChain = new DispatchTrackingIdentity() { Id = nextId, EntryType = typeof(TAction), Version = _currentVersion, - Tracker = _tracker + Tracker = () => _tracker }; bool preCancel = _tracker.CreateExecutingAction(nextChain.Id, this, nextChain.Version); + nextChain.TrackedEntry = _tracker.CreateEntryPoint(nextChain.Id, this); if (!preCancel) return; - _tracker.CreateEntryPoint(nextChain.Id, this); } @@ -104,16 +101,19 @@ protected async Task ProcessDispatch(bool entryPoint, Guid nextId) } await Task.WhenAll(dispatchMiddlewareTasks); + if (IsChainCancelled(nextChain)) + return; try { var dispatcherService = _serviceProvider.GetRequiredService(); + var dispatchElement = dispatcherService.CreateDispatch(); if (nextChain != default) - await dispatcherService.DispatchHandler.MaintainChainKey(nextChain); + await dispatchElement.Handler.MaintainChainKey(nextChain); if (_dispatchOrdering == DispatchOrdering.ReducersFirst) await RunReducer(nextChain); - await RunEffects(nextChain, dispatcherService); + await RunEffects(nextChain, dispatchElement); if (_dispatchOrdering == DispatchOrdering.EffectsFirst) await RunReducer(nextChain); @@ -150,31 +150,7 @@ public async Task DispatchAsync(bool asSafe = false) return Guid.Empty; } - private Task RunMiddlewareEffect(IEnumerable middlewares, Func func, Func conditionBehavior) - { - if (!conditionBehavior(ServiceRegisterExt.ConfigureOptions.MiddlewareEffectBehavior)) - return Task.CompletedTask; - - var effectMiddlewaresTasks = new List(); - foreach (var item in middlewares) - { - effectMiddlewaresTasks.Add(func(item)); - } - return Task.WhenAll(effectMiddlewaresTasks); - - - } - private Task RunMiddlewareReducer(IEnumerable middlewares, Func func) - { - - var middlewaresTasks = new List(); - foreach (var item in middlewares) - { - middlewaresTasks.Add(func(item)); - } - return Task.WhenAll(middlewaresTasks); - } - private async Task RunEffects(DispatchTrackingIdentity? nextChain, IDispatchFactory dispatcherService) + private async Task RunEffects(DispatchTrackingIdentity? nextChain, DispatchFactoryElement dispatcherService) { var effectType = typeof(IEffect<>).MakeGenericType(_action!.GetType()); @@ -189,7 +165,7 @@ private async Task RunEffects(DispatchTrackingIdentity? nextChain, IDispatchFact foreach (var effectService in effectServices) { - if (nextChain != default && nextChain.Tracker.IsCancelled(nextChain.Id, nextChain.Version)) + if (IsChainCancelled(nextChain)) return; bool validationPassed = await RunEffectValidators(effectService!.GetType(), effectMiddlewares); @@ -266,21 +242,20 @@ private async Task RunReducer(DispatchTrackingIdentity? nextChain) { var actionType = typeof(TAction); var middlewares = _serviceProvider.GetServices(); - foreach (var stateType in _statePulseRegistry.KnownStates) { - bool isCancelled = nextChain != default && nextChain.Tracker.IsCancelled(nextChain.Id, nextChain.Version); - if (isCancelled) + + if (IsChainCancelled(nextChain)) return; var reducerType = typeof(IReducer<,>).MakeGenericType(stateType, actionType); var stateAccessorType = _statePulseRegistry.KnownStateToAccessors[stateType]; - var stateService = _serviceProvider.GetRequiredService(stateAccessorType); + var stateService = () => _serviceProvider.GetRequiredService(stateAccessorType); var reducerService = _serviceProvider.GetService(reducerType); // Trigger Reducer if (reducerService != default) { - var currentState = _statePulseRegistry.KnownStateAccessorsStateGetter[stateAccessorType](stateService)!; + var currentState = _statePulseRegistry.KnownStateAccessorsStateGetter[stateAccessorType](stateService())!; var middlewareTasks = RunMiddlewareReducer(middlewares, p => p.BeforeReducing(currentState, _action)); if (ServiceRegisterExt.ConfigureOptions.MiddlewareTaskBehavior == Configuration.MiddlewareTaskBehavior.Await) await middlewareTasks; @@ -289,17 +264,26 @@ private async Task RunReducer(DispatchTrackingIdentity? nextChain) new object[] { currentState, _action }!)!; - - isCancelled = nextChain != default && nextChain.Tracker.IsCancelled(nextChain.Id, nextChain.Version); - if (isCancelled) - return; await reduceTask; + if (IsChainCancelled(nextChain)) + return; var newState = _statePulseRegistry.KnownReducersTaskResult[reducerType](reduceTask); if (newState == null) throw new InvalidOperationException("Reducer returned null state."); - _statePulseRegistry.KnownStateAccessorsStateSetter[stateAccessorType](stateService, newState); + long usedVersion = -1; + if (nextChain != default) + usedVersion = nextChain.Version; + if (usedVersion <= -1) usedVersion = _currentVersion; + + Type originType = typeof(TAction); + if (nextChain != default) + originType = nextChain.EntryType; + var isAccepted = _statePulseRegistry.KnownStateAccessorsStateUpdater[stateAccessorType](stateService(), newState, originType, usedVersion, nextChain?.Id ?? Guid.Empty); + var stateVersioning = (StateVersioning)_statePulseRegistry.KnownStateAccessorsVersionGetter[stateAccessorType].Invoke(stateService())!; + + if (!isAccepted) return; // Regardless of settings ensure BeforeReducing is finished before calling after reducing. if (ServiceRegisterExt.ConfigureOptions.MiddlewareTaskBehavior != Configuration.MiddlewareTaskBehavior.Await) _ = Task.Run(async () => @@ -320,6 +304,33 @@ private async Task RunReducer(DispatchTrackingIdentity? nextChain) } } + private Task RunMiddlewareEffect(IEnumerable middlewares, Func func, Func conditionBehavior) + { + if (!conditionBehavior(ServiceRegisterExt.ConfigureOptions.MiddlewareEffectBehavior)) + return Task.CompletedTask; + + var effectMiddlewaresTasks = new List(); + foreach (var item in middlewares) + { + effectMiddlewaresTasks.Add(func(item)); + } + return Task.WhenAll(effectMiddlewaresTasks); + + + } + private Task RunMiddlewareReducer(IEnumerable middlewares, Func func) + { + var middlewaresTasks = new List(); + foreach (var item in middlewares) + { + middlewaresTasks.Add(func(item)); + } + return Task.WhenAll(middlewaresTasks); + } + private bool IsChainCancelled(DispatchTrackingIdentity? nextChain = default) + => + (nextChain != default && (nextChain.TrackedEntry.IsCancelled || nextChain.Tracker().IsCancelled(nextChain.Id, nextChain.Version))) || + (_chainKey != default && (_chainKey.TrackedEntry.IsCancelled || _chainKey.Tracker().IsCancelled(_chainKey.Id, _chainKey.Version))); } diff --git a/src/StatePulse.NET/Engine/Implementations/StateAccessor.cs b/src/StatePulse.NET/Engine/Implementations/StateAccessor.cs index a12ae23..850ad75 100644 --- a/src/StatePulse.NET/Engine/Implementations/StateAccessor.cs +++ b/src/StatePulse.NET/Engine/Implementations/StateAccessor.cs @@ -9,9 +9,9 @@ public StateAccessor() { InitializeState(); } - public DateTime LastChange { get; set; } - public long Version { get; set; } + public StateVersioning Version { get; set; } = new(typeof(TState), -1, Guid.Empty); private TState _state = default!; + public TState State { get => _state; set @@ -20,7 +20,6 @@ public TState State // make sure state can never be set null always has a default state. if (value == null) InitializeState(); else _state = value; - LastChange = DateTime.UtcNow; OnStateChanged?.Invoke(this, _state); OnStateChangedNoDetails?.Invoke(this, new EventArgs()); } @@ -29,6 +28,19 @@ public TState State public event OnChangeEventHandler? OnStateChanged; public event EventHandler? OnStateChangedNoDetails; + public readonly static Object _lock = new object(); + public bool ChangeState(TState state, Type originType, long version, Guid dispatchWriter) + { + lock (_lock) + { + if (version >= 0 && Version.Version > version) + return false; + Version = new(originType, version, dispatchWriter); + State = state; + return true; + } + + } private void InitializeState() { // add default initialized state. diff --git a/src/StatePulse.NET/Engine/Implementations/StatePulseRegistry.cs b/src/StatePulse.NET/Engine/Implementations/StatePulseRegistry.cs index 35cee74..441a1e4 100644 --- a/src/StatePulse.NET/Engine/Implementations/StatePulseRegistry.cs +++ b/src/StatePulse.NET/Engine/Implementations/StatePulseRegistry.cs @@ -3,12 +3,16 @@ namespace StatePulse.Net.Engine.Implementations; using StatePulse.Net; +using System.Linq.Expressions; +using System.Reflection; + internal class StatePulseRegistry : IStatePulseRegistry { private readonly List _knownStates = new(); private readonly Dictionary _knownStateToAccessors = new(); private readonly Dictionary> _knownStateAccessorsStateGetter = new(); - private readonly Dictionary> _knownStateAccessorsStateSetter = new(); + private readonly Dictionary> _knownStateAccessorsStateUpdater = new(); + private readonly Dictionary> _knownStateAccessorsVersionGetter = new(); private readonly Dictionary _knownEffects = new(); private readonly Dictionary _knownReducers = new(); @@ -24,7 +28,8 @@ internal class StatePulseRegistry : IStatePulseRegistry public IReadOnlyList KnownActions => _knownActions; public IReadOnlyDictionary KnownActionValidators => _knownActionValidators; public IReadOnlyDictionary> KnownStateAccessorsStateGetter => _knownStateAccessorsStateGetter; - public IReadOnlyDictionary> KnownStateAccessorsStateSetter => _knownStateAccessorsStateSetter; + public IReadOnlyDictionary> KnownStateAccessorsStateUpdater => _knownStateAccessorsStateUpdater; + public IReadOnlyDictionary> KnownStateAccessorsVersionGetter => _knownStateAccessorsVersionGetter; public IReadOnlyDictionary> KnownReducersReduceMethod => _knownReducersReduceMethod; @@ -32,6 +37,7 @@ internal class StatePulseRegistry : IStatePulseRegistry public IReadOnlyDictionary KnownStateToAccessors => _knownStateToAccessors; + public void RegisterEffect(Type effectType, Type interfaceType) => _knownEffects[effectType] = interfaceType; public void RegisterReducer(Type reducerType, Type interfaceType) { @@ -50,7 +56,12 @@ public void RegisterState(Type stateType) var property = accessorImplementationType.GetProperty(nameof(IStateAccessor.State))!; _knownStateAccessorsStateGetter[accessorType] = property.CreateGetterDynamic(); - _knownStateAccessorsStateSetter[accessorType] = property.CreateSetterDynamic(); + var stateUpdateMethod = accessorImplementationType.GetMethod(nameof(IStateAccessor.ChangeState))!; + _knownStateAccessorsStateUpdater[accessorType] = BuildChangeStateDelegate(stateUpdateMethod); + + var propertyVersion = accessorImplementationType.GetProperty(nameof(IStateAccessor.Version))!; + _knownStateAccessorsVersionGetter[accessorType] = propertyVersion.CreateGetterDynamic(); + _knownStateToAccessors[stateType] = accessorType; if (!_knownStates.Contains(stateType)) _knownStates.Add(stateType); @@ -61,5 +72,48 @@ public void RegisterAction(Type actionType) _knownActions.Add(actionType); } public void RegisterEffectValidator(Type actionValType, Type interfaceType) => _knownActionValidators[actionValType] = interfaceType; + private static Func BuildChangeStateDelegate( + MethodInfo changeStateMethod) + { + // Parameters of the dynamic delegate + var targetParam = Expression.Parameter(typeof(object), "target"); + var stateParam = Expression.Parameter(typeof(object), "state"); + var originTypeParam = Expression.Parameter(typeof(Type), "originType"); + var versionParam = Expression.Parameter(typeof(long), "version"); + var writerParam = Expression.Parameter(typeof(Guid), "writer"); + // Cast target to StateAccessor + var typedTarget = Expression.Convert(targetParam, changeStateMethod.DeclaringType!); + + // Cast state to TState + var typedState = Expression.Convert( + stateParam, + changeStateMethod.GetParameters()[0].ParameterType + ); + + // Call ChangeState(TState, Type, long, Guid) + var call = Expression.Call( + typedTarget, + changeStateMethod, + typedState, + originTypeParam, + versionParam, + writerParam + ); + + // Wrap the call and return true (since ChangeState returns void) + var body = Expression.Block( + call, + Expression.Constant(true) + ); + + return Expression.Lambda>( + body, + targetParam, + stateParam, + originTypeParam, + versionParam, + writerParam + ).Compile(); + } } diff --git a/src/StatePulse.Net.Abstractions/IStateAccessor.cs b/src/StatePulse.Net.Abstractions/IStateAccessor.cs index f85997a..8bed1a4 100644 --- a/src/StatePulse.Net.Abstractions/IStateAccessor.cs +++ b/src/StatePulse.Net.Abstractions/IStateAccessor.cs @@ -1,12 +1,11 @@ ο»Ώnamespace StatePulse.Net; public delegate void OnChangeEventHandler(object sender, T args); -public interface IStateAccessor +public interface IStateAccessor { TState State { get; } - DateTime LastChange { get; } - long Version { get; } + StateVersioning Version { get; } event OnChangeEventHandler? OnStateChanged; event EventHandler? OnStateChangedNoDetails; - + bool ChangeState(TState state, Type originType, long version, Guid dispatchWriter); } diff --git a/src/StatePulse.Net.Abstractions/IStatePulseRegistry.cs b/src/StatePulse.Net.Abstractions/IStatePulseRegistry.cs index 5f00d68..ec91ba5 100644 --- a/src/StatePulse.Net.Abstractions/IStatePulseRegistry.cs +++ b/src/StatePulse.Net.Abstractions/IStatePulseRegistry.cs @@ -1,4 +1,5 @@ ο»Ώnamespace StatePulse.Net; + public interface IStatePulseRegistry { @@ -9,7 +10,10 @@ public interface IStatePulseRegistry IReadOnlyList KnownActions { get; } IReadOnlyDictionary KnownActionValidators { get; } IReadOnlyDictionary> KnownStateAccessorsStateGetter { get; } - IReadOnlyDictionary> KnownStateAccessorsStateSetter { get; } + IReadOnlyDictionary> KnownStateAccessorsStateUpdater { get; } + + IReadOnlyDictionary> KnownStateAccessorsVersionGetter { get; } + IReadOnlyDictionary> KnownReducersTaskResult { get; } IReadOnlyDictionary KnownStateToAccessors { get; } diff --git a/src/StatePulse.Net.Abstractions/StateVersioning.cs b/src/StatePulse.Net.Abstractions/StateVersioning.cs new file mode 100644 index 0000000..01c9e4c --- /dev/null +++ b/src/StatePulse.Net.Abstractions/StateVersioning.cs @@ -0,0 +1,16 @@ +ο»Ώnamespace StatePulse.Net; + +public sealed record StateVersioning +{ + public StateVersioning(Type originType, long version, Guid dispatchWriter) + { + OriginType = originType; + Version = version; + DispatchWriter = dispatchWriter; + LastChange = DateTime.UtcNow; + } + public DateTime LastChange { get; } + public Type OriginType { get; } + public long Version { get; } + public Guid DispatchWriter { get; } +} diff --git a/tests/StatPulse.NET.Tests/TestCases/InitializerTests/StatePulseInitTests.cs b/tests/StatPulse.NET.Tests/TestCases/InitializerTests/StatePulseInitTests.cs index 49b05a2..feaa088 100644 --- a/tests/StatPulse.NET.Tests/TestCases/InitializerTests/StatePulseInitTests.cs +++ b/tests/StatPulse.NET.Tests/TestCases/InitializerTests/StatePulseInitTests.cs @@ -70,16 +70,9 @@ await dispatcher.Prepare().With(p => p.TestData, name) public async Task DispatchingBurstShouldTriggerSafetyCancel() { var scopedServices = ServiceProvider.CreateScope().ServiceProvider; - var dispatcher = scopedServices.GetRequiredService(); var stateAccessor = scopedServices.GetRequiredService>(); var tracker = scopedServices.GetRequiredService>(); - var tracker2 = scopedServices.GetRequiredService>(); - int cancelled = 0; - tracker.OnCancel += (o, action) => - { - cancelled++; - }; // Dispatch action that changes state int changes = 0; stateAccessor.OnStateChanged += (s, state) => @@ -89,27 +82,27 @@ public async Task DispatchingBurstShouldTriggerSafetyCancel() List dispatches = new(); Random random = new Random(); int[] timing = [ - 50, // Entry - 25, // Cancels 0 - 75, // - 50, - 25, - 50, - 1000, + 51, // Entry + 22, // Cancels 0 + 73, // + 54, 25, - 50, - 25 + 56, + 1007, + 28, + 59, + 20 ]; string winingValue = $"Profile"; List possibleRaceConditions = new(); for (int i = 0; i < 10; i++) { - winingValue = $"Profile {random.Next()}"; - var id = await dispatcher.Prepare() + winingValue = $"Profile {timing[i]}"; + var dispatcher = scopedServices.GetRequiredService(); + _ = dispatcher.Prepare() .With(p => p.TestData, winingValue) .With(p => p.Delay, timing[i]) .DispatchAsync(true); - dispatches.Add(id); possibleRaceConditions.Add(winingValue); } await Task.Delay(timing.Sum()); @@ -120,7 +113,7 @@ public async Task DispatchingBurstShouldTriggerSafetyCancel() } while (changes <= 0); - bool isPassing = stateAccessor.State.ProfileName == possibleRaceConditions.Last(); + bool isPassing = stateAccessor.State.ProfileName.Equals(winingValue); if (!isPassing) Debugger.Break(); Assert.True(isPassing); } From 6e8bc60634b659db2ea916d60062bce7037d377f Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Tue, 13 Jan 2026 12:16:24 +0200 Subject: [PATCH 16/27] wip --- doc/docs/0.Versions.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/docs/0.Versions.md b/doc/docs/0.Versions.md index d3216fb..fd992a2 100644 --- a/doc/docs/0.Versions.md +++ b/doc/docs/0.Versions.md @@ -65,6 +65,8 @@ sidebar_position: 0 - `GlobalTrackerLifetime` - Define clearly lifetime scope for the Global Tracker singleton or scoped. `BlazorServer`, `WASM`, `Scoped` (Default) or `Singleton`. - `IStateFeatureSingleton` - Define a singleton state across your app... not useful in WASM but very useful in Blazor Server... where one can share the state across client each client run their own action but the state update spread across all circuits. - `IReducer`, `IEffect`, `IEffectValidation`, `IEffectMiddleware`, `IReducerMiddleware` - Are ALWAYS transient from now on. +- `StateVersioning` long global ticker used to calculate version of a state... this will help prevent further race conditions related to multi-threading (blazor server singleton). +- State update will automatically discard stale states. you can also acces the information using `IStateAccessor` ### 🐞 Security - Roslyn will now enforce `_statePulse.StateOf(() => this, OnUpdate);` on the two arguments this will avoid runtime errors and potential memory leaks. @@ -76,6 +78,7 @@ sidebar_position: 0 - Fixed Middleware are now added via Scanned Assemblies. - Fixed some issues where `Await()` was not respected. - Fixed major issue where all race condition elements where cancelled leading to full chain cancellation including the last action. +- Fixed inconsistence with race conditions. ## πŸ“¦ v1.1.0 From d4c68c2b1e9c54dcb8bb7509524db296a6094116 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Tue, 13 Jan 2026 21:28:34 +0200 Subject: [PATCH 17/27] wip --- doc/docs/0.Versions.md | 14 +++++++------- src/Directory.Packages.props | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/docs/0.Versions.md b/doc/docs/0.Versions.md index fd992a2..95f3058 100644 --- a/doc/docs/0.Versions.md +++ b/doc/docs/0.Versions.md @@ -47,20 +47,20 @@ sidebar_position: 0 ### ✨ New Features -- **βš™οΈ Enhanced Configuration Options** - New global configuration properties: +- **Enhanced Configuration Options** - New global configuration properties: - `DispatchOrderBehavior` - Set default ordering (EffectsFirst/ReducersFirst) - `DispatchEffectExecutionBehavior` - Set default execution mode (YieldAndFire/FireAndForget) -- **πŸŽ›οΈ Configurable Dispatch Ordering** - Choose between `EffectsFirst` (default) or `ReducersFirst` execution order globally or per-dispatch -- **πŸŽ›οΈ Configurable Dispatch Ordering** - The Middleware BeforeReducers will run before the AfterReducer as garantueed... +- **Configurable Dispatch Ordering** - Choose between `EffectsFirst` (default) or `ReducersFirst` execution order globally or per-dispatch +- **Configurable Dispatch Ordering** - The Middleware BeforeReducers will run before the AfterReducer as garantueed... - The reducer will however run in parallel with BeforeReducing if settings is to not await for middlewares. -- **⚑ True Fire-and-Forget Execution Mode** - New `DispatchEffectExecutionBehavior.FireAndForget` for true background execution without yielding and awaiting effects -- **πŸ”§ Per-Dispatch Execution Control** - Override global settings per dispatch with fluent API: +- **True Fire-and-Forget Execution Mode** - New `DispatchEffectExecutionBehavior.FireAndForget` for true background execution without yielding and awaiting effects +- **Per-Dispatch Execution Control** - Override global settings per dispatch with fluent API: - `.EffectsFirst()` - Run effects before reducers - `.ReducersFirst()` - Run reducers before effects - `.SequentialEffects()` - Force effects to run in sequence - `.ParallelEffects()` - Force effects to run in parallel -- **πŸ›‘οΈ Invalid Configuration Detection** - New `InvalidDispatchCombinationException` thrown at dispatch time for incompatible configuration combinations (Plan to generate compiler errors later) -- **♻️ Recursive Dispatch Support** - Fire-and-forget mode enables safe recursive dispatch patterns without deadlocks +- **Invalid Configuration Detection** - New `InvalidDispatchCombinationException` thrown at dispatch time for incompatible configuration combinations (Plan to generate compiler errors later) +- **Recursive Dispatch Support** - Fire-and-forget mode enables safe recursive dispatch patterns without deadlocks - `PulseTrackingModel` - Clear option for the tracking model! Either Thread-Safe (`Default`) or Single Threaded Fast Application... WASM/Blazor Server. - `GlobalTrackerLifetime` - Define clearly lifetime scope for the Global Tracker singleton or scoped. `BlazorServer`, `WASM`, `Scoped` (Default) or `Singleton`. - `IStateFeatureSingleton` - Define a singleton state across your app... not useful in WASM but very useful in Blazor Server... where one can share the state across client each client run their own action but the state update spread across all circuits. diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index f019832..f995adb 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -1,6 +1,6 @@ - 2.0.521 + 2.0.522 Maksim Shimshon Β© 2026 From 92be1695297bd993ac91caa1d008046aae1d2e1a Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Tue, 13 Jan 2026 23:18:33 +0200 Subject: [PATCH 18/27] wip --- doc/docs/0.Versions.md | 8 ++ src/Directory.Packages.props | 2 +- .../Engine/Implementations/Dispatcher.cs | 3 + .../Implementations/DispatcherPrepper.cs | 4 +- .../Implementations/StatePulseRegistry.cs | 5 +- src/StatePulse.NET/ReducerExt.cs | 57 ----------- .../IDispatcher.cs | 4 + src/StatePulse.Net.Abstractions/IReducer.cs | 2 +- .../WithPropertyAnalyzer.cs | 99 +++++++++++++++++++ .../Reducers/CounterIncreaseReducer.cs | 5 +- .../CounterSingletonIncreaseReducer.cs | 8 +- .../Program.cs | 1 - .../Counter/Reducers/UpdateCounterReducer.cs | 12 +-- ...ainMenuLoadNavigationItemsResultReducer.cs | 8 +- .../Reducers/MainMenuLoaderStartReducer.cs | 8 +- .../Reducers/MainMenuLoaderStopReducer.cs | 8 +- .../MainMenu/Reducers/MainMenuOpenReducer.cs | 8 +- .../ProfileCardDefineResultReducer.cs | 7 +- 18 files changed, 161 insertions(+), 88 deletions(-) delete mode 100644 src/StatePulse.NET/ReducerExt.cs create mode 100644 src/StatePulse.Net.Analyzers/WithPropertyAnalyzer.cs diff --git a/doc/docs/0.Versions.md b/doc/docs/0.Versions.md index 95f3058..a0de890 100644 --- a/doc/docs/0.Versions.md +++ b/doc/docs/0.Versions.md @@ -45,6 +45,14 @@ sidebar_position: 0 - **Removed Throw for Dispatch Failure** Re-Throw only occurs when using Synchronous `Await()` otherwise dispatch will swallow any uncaught exception thrown at it. +- **Reducers are no longer Tasks** + With the full introduction of middlewares it is no longer justifiable to have reducers as Task... nothing should be in the reducers to the exception of generating a new state. + +- **ReducerExt is removed** + ReducerExt is no longer available as it was used as helper for Task return. + - +- **IDispatcherPrepper Prepare(Func createInstance) deprecated** + Use Prepared(instance).DispatchAsync() instead; ### ✨ New Features - **Enhanced Configuration Options** - New global configuration properties: diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index f995adb..1dc044e 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -1,6 +1,6 @@ - 2.0.522 + 2.0.523 Maksim Shimshon Β© 2026 diff --git a/src/StatePulse.NET/Engine/Implementations/Dispatcher.cs b/src/StatePulse.NET/Engine/Implementations/Dispatcher.cs index acf09a4..bc1f558 100644 --- a/src/StatePulse.NET/Engine/Implementations/Dispatcher.cs +++ b/src/StatePulse.NET/Engine/Implementations/Dispatcher.cs @@ -28,6 +28,9 @@ public IDispatcherPrepper Prepare(Func createInstance return CreatePrepper(createInstance.Invoke()); } + public IDispatcherPrepper Prepared(TAction instance) where TAction : IAction + => CreatePrepper(instance); + private IDispatcherPrepper CreatePrepper(TAction Instance) where TAction : IAction { var passKeyChain = _chainKey?.EntryType ?? typeof(TAction); diff --git a/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs b/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs index 9217434..74d0891 100644 --- a/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs +++ b/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs @@ -260,16 +260,14 @@ private async Task RunReducer(DispatchTrackingIdentity? nextChain) if (ServiceRegisterExt.ConfigureOptions.MiddlewareTaskBehavior == Configuration.MiddlewareTaskBehavior.Await) await middlewareTasks; - var reduceTask = (Task)_statePulseRegistry.KnownReducersReduceMethod[reducerType](reducerService, + var newState = _statePulseRegistry.KnownReducersReduceMethod[reducerType](reducerService, new object[] { currentState, _action }!)!; - await reduceTask; if (IsChainCancelled(nextChain)) return; - var newState = _statePulseRegistry.KnownReducersTaskResult[reducerType](reduceTask); if (newState == null) throw new InvalidOperationException("Reducer returned null state."); long usedVersion = -1; diff --git a/src/StatePulse.NET/Engine/Implementations/StatePulseRegistry.cs b/src/StatePulse.NET/Engine/Implementations/StatePulseRegistry.cs index 441a1e4..96b9ab5 100644 --- a/src/StatePulse.NET/Engine/Implementations/StatePulseRegistry.cs +++ b/src/StatePulse.NET/Engine/Implementations/StatePulseRegistry.cs @@ -41,10 +41,9 @@ internal class StatePulseRegistry : IStatePulseRegistry public void RegisterEffect(Type effectType, Type interfaceType) => _knownEffects[effectType] = interfaceType; public void RegisterReducer(Type reducerType, Type interfaceType) { - var reduceMethodName = nameof(IReducer.ReduceAsync); + var reduceMethodName = nameof(IReducer.Reduce); var method = reducerType.GetMethod(reduceMethodName)!; - var returnTaskType = method.ReturnType; - var stateType = returnTaskType.GetGenericArguments()[0]; // This is TState + var stateType = method.ReturnType; // This is TState _knownReducersTaskResult[reducerType] = stateType.BuildTaskResultGetter(); _knownReducersReduceMethod[reducerType] = method.CreateDynamicReflectionInvoker(); _knownReducers.TryAdd(reducerType, interfaceType); diff --git a/src/StatePulse.NET/ReducerExt.cs b/src/StatePulse.NET/ReducerExt.cs deleted file mode 100644 index de63bdf..0000000 --- a/src/StatePulse.NET/ReducerExt.cs +++ /dev/null @@ -1,57 +0,0 @@ -ο»Ώusing System.Linq.Expressions; -using System.Reflection; - -namespace StatePulse.Net; -public static class ReducerExt -{ - public static Cloner ReducerResult(T state) - where T : class, new() - => new(state); - - public class Cloner where T : class, new() - { - private readonly T _source; - private readonly Dictionary _overrides = new(); - - public Cloner(T source) - { - _source = source; - } - - public Cloner With(Expression> selector, TProp value) - { - if (selector.Body is not MemberExpression member) - throw new ArgumentException("Expression must be a property access.", nameof(selector)); - - _overrides[member.Member.Name] = value; - return this; - } - - public Task ToTask() - { - var result = CloneWithOverrides(_source, _overrides); - return Task.FromResult(result); - } - - private static T CloneWithOverrides(T source, Dictionary overrides) - { - var type = typeof(T); - var clone = Activator.CreateInstance(); - - foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) - { - if (!prop.CanWrite) - continue; - - var value = overrides.TryGetValue(prop.Name, out var overrideValue) - ? overrideValue - : prop.GetValue(source); - - prop.SetValue(clone, value); - } - - return clone; - } - } - -} diff --git a/src/StatePulse.Net.Abstractions/IDispatcher.cs b/src/StatePulse.Net.Abstractions/IDispatcher.cs index de6752a..dbb86eb 100644 --- a/src/StatePulse.Net.Abstractions/IDispatcher.cs +++ b/src/StatePulse.Net.Abstractions/IDispatcher.cs @@ -6,5 +6,9 @@ namespace StatePulse.Net; public interface IDispatcher { IDispatcherPrepper Prepare(params object[] constructor) where TAction : IAction; + + [Obsolete("Use Prepared instead.")] IDispatcherPrepper Prepare(Func createInstance) where TAction : IAction; + IDispatcherPrepper Prepared(TAction instance) where TAction : IAction; + } diff --git a/src/StatePulse.Net.Abstractions/IReducer.cs b/src/StatePulse.Net.Abstractions/IReducer.cs index 44d70c2..b9ed4e5 100644 --- a/src/StatePulse.Net.Abstractions/IReducer.cs +++ b/src/StatePulse.Net.Abstractions/IReducer.cs @@ -6,5 +6,5 @@ public interface IReducer where TState : IStateFeature where TAction : IAction { - Task ReduceAsync(TState state, TAction action); + TState Reduce(TState state, TAction action); } diff --git a/src/StatePulse.Net.Analyzers/WithPropertyAnalyzer.cs b/src/StatePulse.Net.Analyzers/WithPropertyAnalyzer.cs new file mode 100644 index 0000000..6457b16 --- /dev/null +++ b/src/StatePulse.Net.Analyzers/WithPropertyAnalyzer.cs @@ -0,0 +1,99 @@ +ο»Ώusing Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; + +namespace StatePulse.Net.Analyzers; + +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public sealed class WithPropertyAnalyzer : DiagnosticAnalyzer +{ + public static readonly DiagnosticDescriptor InvalidPropertyRule = + new DiagnosticDescriptor( + id: "SP002", + title: "Property cannot be used with .With", + messageFormat: "Property '{0}' must be get; set;. It is get-only or init-only.", + category: "Usage", + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics => + ImmutableArray.Create(InvalidPropertyRule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSyntaxNodeAction(AnalyzeInvocation, SyntaxKind.InvocationExpression); + } + + private void AnalyzeInvocation(SyntaxNodeAnalysisContext context) + { + var invocation = (InvocationExpressionSyntax)context.Node; + + // Must be something like: .With(...) + if (invocation.Expression is not MemberAccessExpressionSyntax memberAccess) + return; + + if (memberAccess.Name.Identifier.Text != "With") + return; + + // Resolve the invoked method symbol + var symbol = context.SemanticModel.GetSymbolInfo(memberAccess).Symbol as IMethodSymbol; + if (symbol is null) + return; + + // --- FILTER: Only our specific extension method --- + if (!symbol.IsExtensionMethod) + return; + + if (symbol.Name != "With") + return; + + // Namespace + class must match your extension class + if (symbol.ContainingNamespace.ToDisplayString() != "StatePulse.Net") + return; + + if (symbol.ContainingType.Name != "DispatcherPrepperExtensions") + return; + + // Must have at least one argument (the lambda) + if (invocation.ArgumentList.Arguments.Count == 0) + return; + + var lambdaExpr = invocation.ArgumentList.Arguments[0].Expression; + + if (lambdaExpr is not LambdaExpressionSyntax lambda) + return; + + // Lambda must be: p => p.Prop + if (lambda.Body is not MemberAccessExpressionSyntax propAccess) + return; + + // Resolve the property symbol + var propSymbol = context.SemanticModel.GetSymbolInfo(propAccess).Symbol as IPropertySymbol; + if (propSymbol is null) + return; + + var setter = propSymbol.SetMethod; + + // --- PROPERTY VALIDATION --- + bool invalid = + setter is null || // get-only + setter.IsInitOnly || // init-only + setter.DeclaredAccessibility != Accessibility.Public; // private/protected/internal setter + + if (invalid) + { + var diagnostic = Diagnostic.Create( + InvalidPropertyRule, + propAccess.Name.GetLocation(), + propSymbol.Name); + + context.ReportDiagnostic(diagnostic); + } + } +} \ No newline at end of file diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Reducers/CounterIncreaseReducer.cs b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Reducers/CounterIncreaseReducer.cs index 80a2e5d..71b35b9 100644 --- a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Reducers/CounterIncreaseReducer.cs +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Reducers/CounterIncreaseReducer.cs @@ -2,8 +2,9 @@ using StatePulse.Net.BlazorServerTest.Client.Pulses.Counter.Stores; namespace StatePulse.Net.BlazorServerTest.Client.Pulses.Counter.Reducers; + internal class CounterIncreaseReducer : IReducer { - public Task ReduceAsync(CounterState state, CounterIncreaseAction action) - => Task.FromResult(state with { Count = state.Count + 1 }); + public CounterState Reduce(CounterState state, CounterIncreaseAction action) + => state with { Count = state.Count + 1 }; } diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Reducers/CounterSingletonIncreaseReducer.cs b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Reducers/CounterSingletonIncreaseReducer.cs index 055343a..aa230c2 100644 --- a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Reducers/CounterSingletonIncreaseReducer.cs +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest.Client/Pulses/Counter/Reducers/CounterSingletonIncreaseReducer.cs @@ -2,8 +2,12 @@ using StatePulse.Net.BlazorServerTest.Client.Pulses.Counter.Stores; namespace StatePulse.Net.BlazorServerTest.Client.Pulses.Counter.Reducers; + internal class CounterSingletonIncreaseReducer : IReducer { - public Task ReduceAsync(CounterSingletonState state, CounterSingletonIncreaseAction action) - => Task.FromResult(state with { Count = state.Count + 1 }); + public CounterSingletonState Reduce(CounterSingletonState state, CounterSingletonIncreaseAction action) + => state with + { + Count = state.Count + 1 + }; } diff --git a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Program.cs b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Program.cs index 97ac450..244f0f5 100644 --- a/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Program.cs +++ b/src/StatePulse.Net.BlazorServerTest/StatePulse.Net.BlazorServerTest/Program.cs @@ -11,7 +11,6 @@ builder.Services.AddStatePulseServices(c => { c.PulseTrackingPerformance = PulseTrackingModel.BlazorServerSafe; - c.DispatchEffectExecutionBehavior = DispatchEffectExecutionBehavior.YieldAndFire; c.DispatchEffectBehavior = DispatchEffectBehavior.Sequential; c.ScanAssemblies = [typeof(Program).Assembly, typeof(StatePulse.Net.BlazorServerTest.Client._Imports).Assembly]; diff --git a/tests/StatPulse.NET.Tests/TestCases/Pulsars/Counter/Reducers/UpdateCounterReducer.cs b/tests/StatPulse.NET.Tests/TestCases/Pulsars/Counter/Reducers/UpdateCounterReducer.cs index 51bbcc1..eba873d 100644 --- a/tests/StatPulse.NET.Tests/TestCases/Pulsars/Counter/Reducers/UpdateCounterReducer.cs +++ b/tests/StatPulse.NET.Tests/TestCases/Pulsars/Counter/Reducers/UpdateCounterReducer.cs @@ -1,16 +1,14 @@ ο»Ώusing StatePulse.Net; using StatePulse.NET.Tests.TestCases.Pulsars.Counter.Actions; using StatePulse.NET.Tests.TestCases.Pulsars.Counter.States; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace StatePulse.NET.Tests.TestCases.Pulsars.Counter.Reducers; internal class UpdateCounterReducer : IReducer { - public async Task ReduceAsync(CounterState state, UpdateCounterAction action) - => await Task.FromResult(state with { Counter = action.Counter }); + public CounterState Reduce(CounterState state, UpdateCounterAction action) + => state with + { + Counter = action.Counter + }; } diff --git a/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Reducers/MainMenuLoadNavigationItemsResultReducer.cs b/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Reducers/MainMenuLoadNavigationItemsResultReducer.cs index 352e007..e186f33 100644 --- a/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Reducers/MainMenuLoadNavigationItemsResultReducer.cs +++ b/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Reducers/MainMenuLoadNavigationItemsResultReducer.cs @@ -3,8 +3,12 @@ using StatePulse.NET.Tests.TestCases.Pulsars.MainMenu.Store; namespace StatePulse.NET.Tests.TestCases.Pulsars.MainMenu.Reducers; + internal class MainMenuLoadNavigationItemsResultReducer : IReducer { - public async Task ReduceAsync(MainMenuState state, MainMenuLoadNavigationItemsResultAction action) - => await Task.FromResult(state with { NavigationItems = action.Items }); + public MainMenuState Reduce(MainMenuState state, MainMenuLoadNavigationItemsResultAction action) + => state with + { + NavigationItems = action.Items + }; } diff --git a/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Reducers/MainMenuLoaderStartReducer.cs b/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Reducers/MainMenuLoaderStartReducer.cs index 0cf82b8..ad29b7a 100644 --- a/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Reducers/MainMenuLoaderStartReducer.cs +++ b/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Reducers/MainMenuLoaderStartReducer.cs @@ -3,8 +3,12 @@ using StatePulse.NET.Tests.TestCases.Pulsars.MainMenu.Store; namespace StatePulse.NET.Tests.TestCases.Pulsars.MainMenu.Reducers; + internal class MainMenuLoaderStartReducer : IReducer { - public Task ReduceAsync(MainMenuState state, MainMenuLoaderStartAction action) - => Task.FromResult(state with { IsLoading = true }); + public MainMenuState Reduce(MainMenuState state, MainMenuLoaderStartAction action) + => state with + { + IsLoading = true + }; } diff --git a/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Reducers/MainMenuLoaderStopReducer.cs b/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Reducers/MainMenuLoaderStopReducer.cs index 53572ed..174fcb4 100644 --- a/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Reducers/MainMenuLoaderStopReducer.cs +++ b/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Reducers/MainMenuLoaderStopReducer.cs @@ -3,8 +3,12 @@ using StatePulse.NET.Tests.TestCases.Pulsars.MainMenu.Store; namespace StatePulse.NET.Tests.TestCases.Pulsars.MainMenu.Reducers; + internal class MainMenuLoaderStopReducer : IReducer { - public async Task ReduceAsync(MainMenuState state, MainMenuLoaderStopAction action) - => await Task.FromResult(state with { IsLoading = false }); + public MainMenuState Reduce(MainMenuState state, MainMenuLoaderStopAction action) + => state with + { + IsLoading = false + }; } diff --git a/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Reducers/MainMenuOpenReducer.cs b/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Reducers/MainMenuOpenReducer.cs index ca9607c..6d7cc97 100644 --- a/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Reducers/MainMenuOpenReducer.cs +++ b/tests/StatPulse.NET.Tests/TestCases/Pulsars/MainMenu/Reducers/MainMenuOpenReducer.cs @@ -3,8 +3,12 @@ using StatePulse.NET.Tests.TestCases.Pulsars.MainMenu.Store; namespace StatePulse.NET.Tests.TestCases.Pulsars.MainMenu.Reducers; + internal class MainMenuOpenReducer : IReducer { - public Task ReduceAsync(MainMenuState state, MainMenuOpenAction action) => - Task.FromResult(state with { IsOpened = true }); + public MainMenuState Reduce(MainMenuState state, MainMenuOpenAction action) + => state with + { + IsOpened = true + }; } diff --git a/tests/StatPulse.NET.Tests/TestCases/Pulsars/Profile/Reducers/ProfileCardDefineResultReducer.cs b/tests/StatPulse.NET.Tests/TestCases/Pulsars/Profile/Reducers/ProfileCardDefineResultReducer.cs index 17d1af3..2f0223d 100644 --- a/tests/StatPulse.NET.Tests/TestCases/Pulsars/Profile/Reducers/ProfileCardDefineResultReducer.cs +++ b/tests/StatPulse.NET.Tests/TestCases/Pulsars/Profile/Reducers/ProfileCardDefineResultReducer.cs @@ -3,15 +3,16 @@ using StatePulse.NET.Tests.TestCases.Pulsars.Profile.Store; namespace StatePulse.NET.Tests.TestCases.Pulsars.Profile.Reducers; + internal class ProfileCardDefineResultReducer : IReducer { - public Task ReduceAsync(ProfileCardState state, ProfileCardDefineResultAction action) - => Task.FromResult(state with + public ProfileCardState Reduce(ProfileCardState state, ProfileCardDefineResultAction action) + => state with { LastUpdate = DateTime.UtcNow, ProfileId = action.Id, ProfileName = action.Name, ProfilePicture = action.Picture, UnitTestStringer = action.UnitTestStringer - }); + }; } From 2f91b3bf5706831709022666c1f7e3a2afd4b6af Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Tue, 13 Jan 2026 23:20:58 +0200 Subject: [PATCH 19/27] wip --- doc/docs/0.Versions.md | 52 +++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/doc/docs/0.Versions.md b/doc/docs/0.Versions.md index a0de890..3f4e66c 100644 --- a/doc/docs/0.Versions.md +++ b/doc/docs/0.Versions.md @@ -4,8 +4,8 @@ title: Updates sidebar_position: 0 --- -## πŸ“¦ v2.0.0 -### ✨ BREAKING CHANGES +## v2.0.0 +### BREAKING CHANGES - **Interface signatures have changed.** Core interface updates may break plugin‑based systems if the core updates while plugins do not. @@ -50,11 +50,11 @@ sidebar_position: 0 - **ReducerExt is removed** ReducerExt is no longer available as it was used as helper for Task return. - - + - **IDispatcherPrepper Prepare(Func createInstance) deprecated** Use Prepared(instance).DispatchAsync() instead; -### ✨ New Features +### New Features - **Enhanced Configuration Options** - New global configuration properties: - `DispatchOrderBehavior` - Set default ordering (EffectsFirst/ReducersFirst) - `DispatchEffectExecutionBehavior` - Set default execution mode (YieldAndFire/FireAndForget) @@ -76,11 +76,11 @@ sidebar_position: 0 - `StateVersioning` long global ticker used to calculate version of a state... this will help prevent further race conditions related to multi-threading (blazor server singleton). - State update will automatically discard stale states. you can also acces the information using `IStateAccessor` -### 🐞 Security +### Security - Roslyn will now enforce `_statePulse.StateOf(() => this, OnUpdate);` on the two arguments this will avoid runtime errors and potential memory leaks. - Fixed All Configure Internal... -### 🐞 Fixes +### Fixes - Fixed Various Warnings - Fixed All Configure Internal... - Fixed Middleware are now added via Scanned Assemblies. @@ -89,32 +89,32 @@ sidebar_position: 0 - Fixed inconsistence with race conditions. -## πŸ“¦ v1.1.0 -### ✨ Minor Change +## v1.1.0 +### Minor Change - Upgraded to .NET 10 -## πŸ“¦ v1.0.2 -### 🐞 Fixes +## v1.0.2 +### Fixes - Added StatePulse.Net.Abstractions package reference instead of project reference to fix IL trimming issues. -## πŸ“¦ v1.0.1 -### ✨ Minor Change +## v1.0.1 +### Minor Change - Splited Abstractions into StatePulse.Net.Abstractions (Will not break anything Namespace is the same) -## πŸ“¦ v1.0.0 -### ✨ New Features +## v1.0.0 +### New Features -- βœ… **Action Effect Validator**: Allows effects to run conditionally by validating them before execution. -- 🧩 **Middleware Support**: +- **Action Effect Validator**: Allows effects to run conditionally by validating them before execution. +- **Middleware Support**: - `IEffectMiddleware` - `IReducerMiddleware` - `IDispatchMiddleware` -- βš™οΈ **Behavior Configuration**: You can configure execution behaviors via: +- **Behavior Configuration**: You can configure execution behaviors via: - `DispatchEffectBehavior` - `MiddlewareEffectBehavior` - `MiddlewareTaskBehavior` -- πŸ› οΈ **Strict Manual Registration**: Manual service registration **must use** extension methods: +- **Strict Manual Registration**: Manual service registration **must use** extension methods: - `AddStatePulse()` - `AddStatePulseEffect<>()` - `AddStatePulseAction<>()` @@ -124,26 +124,26 @@ sidebar_position: 0 ### πŸ’₯ Breaking Changes -- ❌ Removed **Action Validator** – validating action data is not the responsibility of the state management layer. -- πŸ”„ Renamed: +- Removed **Action Validator** – validating action data is not the responsibility of the state management layer. +- Renamed: - `IStateAccessor<>.StateChanged` β†’ `OnStateChanged` - `UsingSynchronousMode` β†’ **Removed** - `Sync()` β†’ `Await()` for clarity and accuracy ### πŸš€ Performance Improvements -- 🧠 Improved **dispatcher caching** -- ⚑ Enhanced **type cache** in `StatePulseRegistry` -- 🧬 Replaced reflection with **dynamic method caching** for faster dispatching +- Improved **dispatcher caching** +- Enhanced **type cache** in `StatePulseRegistry` +- Replaced reflection with **dynamic method caching** for faster dispatching ### 🧼 Clean Code Improvements -- 🧹 Refactored `DispatchPrepper` for cleaner and lighter internal logic +- Refactored `DispatchPrepper` for cleaner and lighter internal logic ### 🐞 Fixes -- πŸ› οΈ Resolved several **null reference warnings** -- 🧽 Removed leftover **internal artifacts** +- Resolved several **null reference warnings** +- Removed leftover **internal artifacts** ## v0.9.41 - Fix: Added Anti-Service duplication to avoid double triggers. From 5d92660ac359ffd6733dd6cd93a9b68bd6d682ff Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Wed, 14 Jan 2026 11:37:41 +0200 Subject: [PATCH 20/27] - wip add analyzer --- doc/docs/0.Versions.md | 2 + src/Directory.Packages.props | 2 +- .../PrepareConstructorValidator.cs | 83 +++++++++++++++++ .../WithPropertyAnalyzer.cs | 91 +++++++------------ 4 files changed, 121 insertions(+), 57 deletions(-) create mode 100644 src/StatePulse.Net.Analyzers/PrepareConstructorValidator.cs diff --git a/doc/docs/0.Versions.md b/doc/docs/0.Versions.md index 3f4e66c..9fdb9fc 100644 --- a/doc/docs/0.Versions.md +++ b/doc/docs/0.Versions.md @@ -75,6 +75,8 @@ sidebar_position: 0 - `IReducer`, `IEffect`, `IEffectValidation`, `IEffectMiddleware`, `IReducerMiddleware` - Are ALWAYS transient from now on. - `StateVersioning` long global ticker used to calculate version of a state... this will help prevent further race conditions related to multi-threading (blazor server singleton). - State update will automatically discard stale states. you can also acces the information using `IStateAccessor` +- Roslyn Analyzer will now trigger error `.Prepare(entity)` if constructor object does not match the underlying object's constructor type and it supports overload. +- Roslyn Analyzer will now trigger error `.Prepare().With(p => p.PROP, data)` when PROP is `init;` or `get;` only... this will eleminate runtime issues. ### Security - Roslyn will now enforce `_statePulse.StateOf(() => this, OnUpdate);` on the two arguments this will avoid runtime errors and potential memory leaks. diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 1dc044e..81a2640 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -1,6 +1,6 @@ - 2.0.523 + 2.0.534 Maksim Shimshon Β© 2026 diff --git a/src/StatePulse.Net.Analyzers/PrepareConstructorValidator.cs b/src/StatePulse.Net.Analyzers/PrepareConstructorValidator.cs new file mode 100644 index 0000000..7040077 --- /dev/null +++ b/src/StatePulse.Net.Analyzers/PrepareConstructorValidator.cs @@ -0,0 +1,83 @@ +ο»Ώusing Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Immutable; +using System.Linq; + +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public sealed class PrepareCtorAnalyzer : DiagnosticAnalyzer +{ + public const string DiagnosticId = "SP003"; + + private static readonly DiagnosticDescriptor Rule = + new DiagnosticDescriptor( + DiagnosticId, + "Invalid Prepare arguments", + "Arguments passed to Prepare<{0}> do not match any constructor of {0}", + "StatePulse", + DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics + => ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSyntaxNodeAction(AnalyzeInvocation, SyntaxKind.InvocationExpression); + } + + private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context) + { + var invocation = (InvocationExpressionSyntax)context.Node; + + var method = context.SemanticModel.GetSymbolInfo(invocation).Symbol as IMethodSymbol; + if (method is null) + return; + + if (method.Name != "Prepare" || !method.IsGenericMethod) + return; + + var reduced = method.ReducedFrom ?? method; + + if (reduced.ContainingType.Name != "IDispatcher") + return; + + var actionType = reduced.TypeArguments[0]; + + var args = invocation.ArgumentList.Arguments; + var argTypes = args + .Select(a => context.SemanticModel.GetTypeInfo(a.Expression).Type) + .ToArray(); + + var ctors = actionType + .GetMembers() + .OfType() + .Where(m => m.MethodKind == MethodKind.Constructor); + + bool match = ctors.Any(ctor => + { + if (ctor.Parameters.Length != argTypes.Length) + return false; + + for (int i = 0; i < argTypes.Length; i++) + { + if (!SymbolEqualityComparer.Default.Equals( + ctor.Parameters[i].Type, argTypes[i])) + return false; + } + + return true; + }); + + if (!match) + { + context.ReportDiagnostic(Diagnostic.Create( + Rule, + invocation.GetLocation(), + actionType.Name)); + } + } +} diff --git a/src/StatePulse.Net.Analyzers/WithPropertyAnalyzer.cs b/src/StatePulse.Net.Analyzers/WithPropertyAnalyzer.cs index 6457b16..7eeb8bb 100644 --- a/src/StatePulse.Net.Analyzers/WithPropertyAnalyzer.cs +++ b/src/StatePulse.Net.Analyzers/WithPropertyAnalyzer.cs @@ -2,26 +2,25 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; -using System; -using System.Collections.Generic; using System.Collections.Immutable; -namespace StatePulse.Net.Analyzers; - [DiagnosticAnalyzer(LanguageNames.CSharp)] public sealed class WithPropertyAnalyzer : DiagnosticAnalyzer { - public static readonly DiagnosticDescriptor InvalidPropertyRule = + public const string DiagnosticId = "SP002"; + + private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( - id: "SP002", - title: "Property cannot be used with .With", - messageFormat: "Property '{0}' must be get; set;. It is get-only or init-only.", - category: "Usage", - defaultSeverity: DiagnosticSeverity.Error, - isEnabledByDefault: true); + DiagnosticId, + "Invalid With property", + "Property '{0}' must be get; set;. init-only or non-public setters are forbidden.", + "StatePulse", + DiagnosticSeverity.Error, + true + ); - public override ImmutableArray SupportedDiagnostics => - ImmutableArray.Create(InvalidPropertyRule); + public override ImmutableArray SupportedDiagnostics + => ImmutableArray.Create(Rule); public override void Initialize(AnalysisContext context) { @@ -30,70 +29,50 @@ public override void Initialize(AnalysisContext context) context.RegisterSyntaxNodeAction(AnalyzeInvocation, SyntaxKind.InvocationExpression); } - private void AnalyzeInvocation(SyntaxNodeAnalysisContext context) + private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context) { var invocation = (InvocationExpressionSyntax)context.Node; - // Must be something like: .With(...) - if (invocation.Expression is not MemberAccessExpressionSyntax memberAccess) - return; - - if (memberAccess.Name.Identifier.Text != "With") + var symbol = context.SemanticModel.GetSymbolInfo(invocation).Symbol as IMethodSymbol; + if (symbol == null || symbol.Name != "With") return; - // Resolve the invoked method symbol - var symbol = context.SemanticModel.GetSymbolInfo(memberAccess).Symbol as IMethodSymbol; - if (symbol is null) - return; - - // --- FILTER: Only our specific extension method --- if (!symbol.IsExtensionMethod) return; - if (symbol.Name != "With") - return; - - // Namespace + class must match your extension class if (symbol.ContainingNamespace.ToDisplayString() != "StatePulse.Net") return; - if (symbol.ContainingType.Name != "DispatcherPrepperExtensions") - return; - - // Must have at least one argument (the lambda) - if (invocation.ArgumentList.Arguments.Count == 0) + if (invocation.ArgumentList.Arguments.Count < 1) return; - var lambdaExpr = invocation.ArgumentList.Arguments[0].Expression; + var arg = invocation.ArgumentList.Arguments[0].Expression; - if (lambdaExpr is not LambdaExpressionSyntax lambda) + if (arg is not LambdaExpressionSyntax lambda) return; - // Lambda must be: p => p.Prop - if (lambda.Body is not MemberAccessExpressionSyntax propAccess) - return; + ExpressionSyntax body = lambda switch + { + SimpleLambdaExpressionSyntax s => s.Body as ExpressionSyntax, + ParenthesizedLambdaExpressionSyntax p => p.Body as ExpressionSyntax, + _ => null + }; - // Resolve the property symbol - var propSymbol = context.SemanticModel.GetSymbolInfo(propAccess).Symbol as IPropertySymbol; - if (propSymbol is null) + if (body is not MemberAccessExpressionSyntax member) return; - var setter = propSymbol.SetMethod; + var prop = context.SemanticModel.GetSymbolInfo(member).Symbol as IPropertySymbol; + if (prop == null) + return; - // --- PROPERTY VALIDATION --- - bool invalid = - setter is null || // get-only - setter.IsInitOnly || // init-only - setter.DeclaredAccessibility != Accessibility.Public; // private/protected/internal setter + var setter = prop.SetMethod; - if (invalid) + if (setter == null || setter.IsInitOnly || setter.DeclaredAccessibility != Accessibility.Public) { - var diagnostic = Diagnostic.Create( - InvalidPropertyRule, - propAccess.Name.GetLocation(), - propSymbol.Name); - - context.ReportDiagnostic(diagnostic); + context.ReportDiagnostic(Diagnostic.Create( + Rule, + member.Name.GetLocation(), + prop.Name)); } } -} \ No newline at end of file +} From 24438730d3bfe0bd58665086bd4708518b7152f0 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Wed, 14 Jan 2026 16:41:18 +0200 Subject: [PATCH 21/27] wip --- src/Directory.Packages.props | 2 +- src/StatePulse.NET/Engine/PulseLazyStateBase.cs | 5 +++++ src/StatePulse.Net.Abstractions/IStatePulse.cs | 3 +++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 81a2640..7e7d176 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -1,6 +1,6 @@ - 2.0.534 + 2.0.535 Maksim Shimshon Β© 2026 diff --git a/src/StatePulse.NET/Engine/PulseLazyStateBase.cs b/src/StatePulse.NET/Engine/PulseLazyStateBase.cs index 00dc005..8cdccbb 100644 --- a/src/StatePulse.NET/Engine/PulseLazyStateBase.cs +++ b/src/StatePulse.NET/Engine/PulseLazyStateBase.cs @@ -4,6 +4,7 @@ using System.Reflection; namespace StatePulse.Net.Engine; + internal abstract class PulseLazyStateBase : IStatePulse { private bool _disposed; @@ -12,10 +13,14 @@ internal abstract class PulseLazyStateBase : IStatePulse private WeakReference _instance = new WeakReference(default); private Func _compiledListener = default!; private MethodInfo _methodListener = default!; + + public IDispatcher Dispatcher { get; private set; } + public PulseLazyStateBase(IServiceProvider services) { _services = services ?? throw new ArgumentNullException(nameof(services)); _globalStash = services.GetRequiredService(); + Dispatcher = services.GetRequiredService(); } /// /// Should be implemented by children class diff --git a/src/StatePulse.Net.Abstractions/IStatePulse.cs b/src/StatePulse.Net.Abstractions/IStatePulse.cs index 57f9b7b..46269bd 100644 --- a/src/StatePulse.Net.Abstractions/IStatePulse.cs +++ b/src/StatePulse.Net.Abstractions/IStatePulse.cs @@ -1,8 +1,11 @@ ο»Ώnamespace StatePulse.Net; + public interface IStatePulse : IDisposable { TState StateOf(Func getInstance, Func onStateChanged) where TState : IStateFeature; bool IsReferenceAlive(); void SelfDisposeCheck(); + IDispatcher Dispatcher { get; } + } From b75b07fb113e18717efbfd3d6260a705f17afea8 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Thu, 15 Jan 2026 09:17:43 +0200 Subject: [PATCH 22/27] wip --- doc/docs/0.Versions.md | 2 +- src/Directory.Packages.props | 2 +- .../PulseLazyStateBlazorServer.cs | 5 +++-- .../Implementations/PulseLazyStateWebAssembly.cs | 5 +++-- .../Engine/Implementations/StateAccessor.cs | 3 +++ src/StatePulse.NET/Engine/PulseLazyStateBase.cs | 16 ++++++---------- .../IStateAccessor.cs | 11 ++++++++--- .../InitializerTests/StatePulseInitTests.cs | 14 ++++++++++++++ 8 files changed, 39 insertions(+), 19 deletions(-) diff --git a/doc/docs/0.Versions.md b/doc/docs/0.Versions.md index 9fdb9fc..5761164 100644 --- a/doc/docs/0.Versions.md +++ b/doc/docs/0.Versions.md @@ -89,7 +89,7 @@ sidebar_position: 0 - Fixed some issues where `Await()` was not respected. - Fixed major issue where all race condition elements where cancelled leading to full chain cancellation including the last action. - Fixed inconsistence with race conditions. - +- Fixed `StateOf()` throwing inability to cast to `IStateAccessor`. ## v1.1.0 ### Minor Change diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 7e7d176..bfd7e2d 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -1,6 +1,6 @@ - 2.0.535 + 2.0.537 Maksim Shimshon Β© 2026 diff --git a/src/StatePulse.NET/Engine/Implementations/PulseLazyStateBlazorServer.cs b/src/StatePulse.NET/Engine/Implementations/PulseLazyStateBlazorServer.cs index a2d5909..96ac7bf 100644 --- a/src/StatePulse.NET/Engine/Implementations/PulseLazyStateBlazorServer.cs +++ b/src/StatePulse.NET/Engine/Implementations/PulseLazyStateBlazorServer.cs @@ -1,10 +1,11 @@ ο»Ώusing System.Collections.Concurrent; namespace StatePulse.Net.Engine.Implementations; + internal sealed class PulseLazyStateBlazorServer : PulseLazyStateBase { - private readonly ConcurrentDictionary> _stash = new(); + private readonly ConcurrentDictionary _stash = new(); public PulseLazyStateBlazorServer(IServiceProvider services) : base(services) { } - protected override IDictionary> GetState() => _stash; + protected override IDictionary GetState() => _stash; } diff --git a/src/StatePulse.NET/Engine/Implementations/PulseLazyStateWebAssembly.cs b/src/StatePulse.NET/Engine/Implementations/PulseLazyStateWebAssembly.cs index 808e9ee..3b54cfc 100644 --- a/src/StatePulse.NET/Engine/Implementations/PulseLazyStateWebAssembly.cs +++ b/src/StatePulse.NET/Engine/Implementations/PulseLazyStateWebAssembly.cs @@ -1,12 +1,13 @@ ο»Ώnamespace StatePulse.Net.Engine.Implementations; + using System; internal sealed class PulseLazyStateWebAssembly : PulseLazyStateBase { - private readonly Dictionary> _stash = new(); + private readonly Dictionary _stash = new(); public PulseLazyStateWebAssembly(IServiceProvider services) : base(services) { } - protected override IDictionary> GetState() => _stash; + protected override IDictionary GetState() => _stash; } \ No newline at end of file diff --git a/src/StatePulse.NET/Engine/Implementations/StateAccessor.cs b/src/StatePulse.NET/Engine/Implementations/StateAccessor.cs index 850ad75..09f0131 100644 --- a/src/StatePulse.NET/Engine/Implementations/StateAccessor.cs +++ b/src/StatePulse.NET/Engine/Implementations/StateAccessor.cs @@ -47,4 +47,7 @@ private void InitializeState() var obj = Activator.CreateInstance(); _state = obj; } + + public T GetAs() where T : class, IStateFeature + => (State as T)!; } diff --git a/src/StatePulse.NET/Engine/PulseLazyStateBase.cs b/src/StatePulse.NET/Engine/PulseLazyStateBase.cs index 8cdccbb..84e0ba9 100644 --- a/src/StatePulse.NET/Engine/PulseLazyStateBase.cs +++ b/src/StatePulse.NET/Engine/PulseLazyStateBase.cs @@ -1,7 +1,6 @@ ο»Ώ using Microsoft.Extensions.DependencyInjection; using StatePulse.Net.Engine.Extensions; -using System.Reflection; namespace StatePulse.Net.Engine; @@ -12,11 +11,10 @@ internal abstract class PulseLazyStateBase : IStatePulse private readonly IPulseGlobalTracker _globalStash; private WeakReference _instance = new WeakReference(default); private Func _compiledListener = default!; - private MethodInfo _methodListener = default!; public IDispatcher Dispatcher { get; private set; } - public PulseLazyStateBase(IServiceProvider services) + protected PulseLazyStateBase(IServiceProvider services) { _services = services ?? throw new ArgumentNullException(nameof(services)); _globalStash = services.GetRequiredService(); @@ -27,7 +25,7 @@ public PulseLazyStateBase(IServiceProvider services) /// /// /// - protected virtual IDictionary> GetState() => throw new NotImplementedException(); + protected virtual IDictionary GetState() => throw new NotImplementedException(); private TState StateOf(Func getInstance) where TState : IStateFeature { var instance = getInstance(); @@ -40,9 +38,7 @@ private TState StateOf(Func getInstance) where TState : IStateFe { var accessorType = typeof(IStateAccessor<>).MakeGenericType(type); var service = _services.GetRequiredService(accessorType); - var serviceObject = (IStateAccessor)service; - GetState().TryAdd(type, serviceObject); - + GetState().TryAdd(type, service); var accessor = (IStateAccessor)service; _globalStash.Register(this); accessor.OnStateChangedNoDetails -= OnStateChanged; @@ -73,7 +69,7 @@ public void Dispose() if (_disposed) return; _disposed = true; _globalStash.UnRegister(this); - foreach (var item in GetState().Values) + foreach (var item in GetState().Values.Select(p => (IStateAccessor)p)) item.OnStateChangedNoDetails -= OnStateChanged; } @@ -81,8 +77,8 @@ public void Dispose() public TState StateOf(Func getInstance, Func onStateChanged) where TState : IStateFeature { var instance = getInstance(); - _methodListener = onStateChanged.GetMethodInfoOrThrow(); - _compiledListener = _methodListener.CreateDynamicInvoker(); + var c = onStateChanged.GetMethodInfoOrThrow(); + _compiledListener = c.CreateDynamicInvoker(); return StateOf(() => instance); } } diff --git a/src/StatePulse.Net.Abstractions/IStateAccessor.cs b/src/StatePulse.Net.Abstractions/IStateAccessor.cs index 8bed1a4..f815d2b 100644 --- a/src/StatePulse.Net.Abstractions/IStateAccessor.cs +++ b/src/StatePulse.Net.Abstractions/IStateAccessor.cs @@ -1,11 +1,16 @@ ο»Ώnamespace StatePulse.Net; public delegate void OnChangeEventHandler(object sender, T args); -public interface IStateAccessor + +public interface IStateAccessor { - TState State { get; } + event EventHandler? OnStateChangedNoDetails; StateVersioning Version { get; } + T GetAs() where T : class, IStateFeature; +} +public interface IStateAccessor : IStateAccessor +{ + TState State { get; } event OnChangeEventHandler? OnStateChanged; - event EventHandler? OnStateChangedNoDetails; bool ChangeState(TState state, Type originType, long version, Guid dispatchWriter); } diff --git a/tests/StatPulse.NET.Tests/TestCases/InitializerTests/StatePulseInitTests.cs b/tests/StatPulse.NET.Tests/TestCases/InitializerTests/StatePulseInitTests.cs index feaa088..bd77a52 100644 --- a/tests/StatPulse.NET.Tests/TestCases/InitializerTests/StatePulseInitTests.cs +++ b/tests/StatPulse.NET.Tests/TestCases/InitializerTests/StatePulseInitTests.cs @@ -40,6 +40,20 @@ public async Task DispatchingActionShouldChangeState() Assert.Equal("Maksim Shimshon", stateAccessor.State.ProfileName); } + public Task OnUpdate() => Task.CompletedTask; + // Testing action dispatch + [Fact] + public async Task DispatchingActionShouldChangeStateUsingStateOf() + { + var dispatcher = ServiceProvider.GetRequiredService(); + var sp = ServiceProvider.GetRequiredService(); + var state = () => sp.StateOf(() => this, OnUpdate); + // Dispatch action that changes state + var action = new ProfileCardDefineAction(); + await dispatcher.Prepare(() => action).Await().DispatchAsync(); + + Assert.Equal("Maksim Shimshon", state().ProfileName); + } [Fact] public async Task DispatchingEffectShouldCorrectlyTriggerActions() From a6851d716225fa30d0e016efd9c3ab79a8df6094 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Mon, 19 Jan 2026 17:00:16 +0200 Subject: [PATCH 23/27] wip --- src/StatePulse.NET/Engine/Implementations/StateAccessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StatePulse.NET/Engine/Implementations/StateAccessor.cs b/src/StatePulse.NET/Engine/Implementations/StateAccessor.cs index 09f0131..9172129 100644 --- a/src/StatePulse.NET/Engine/Implementations/StateAccessor.cs +++ b/src/StatePulse.NET/Engine/Implementations/StateAccessor.cs @@ -28,7 +28,7 @@ public TState State public event OnChangeEventHandler? OnStateChanged; public event EventHandler? OnStateChangedNoDetails; - public readonly static Object _lock = new object(); + public readonly Object _lock = new object(); public bool ChangeState(TState state, Type originType, long version, Guid dispatchWriter) { lock (_lock) From 8d9186f1d0b5f330f8b98ef3e242e52a4ec31a3e Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Wed, 28 Jan 2026 09:07:36 +0200 Subject: [PATCH 24/27] - Made Configure Option - Updated Readme.md --- README.md | 132 +++++++++++++++++++---- doc/docs/0.Versions.md | 1 + src/StatePulse.NET/ServiceRegisterExt.cs | 5 +- tests/StatPulse.NET.Tests/TestBase.cs | 5 +- 4 files changed, 119 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index ddd385b..04cf521 100644 --- a/README.md +++ b/README.md @@ -8,18 +8,42 @@ # StatePulse.NET ### [Official Documentation](https://statepulse.net/) -StatePulse.NET is a precision-tuned state and action management system that balances high-performance fire-and-forget operations with optional, internally controlled execution order when explicitly required. -It enables anti-duplication chaining for critical flows, preventing race conditions and ensuring consistent outcomes even under rapid user input or concurrent triggers. -Its internal tracking infrastructure provides near-zero overhead cancellation and dispatch control, drastically reducing inconsistency. -At the same time, it preserves the flexibility of traditional untracked state management, letting developers selectively enforce order and reliability without compromising overall responsiveness or introducing global locks. +StatePulse.NET is a precision‑engineered state and action management system designed for high‑performance fire‑and‑yield workflows. It supports optional, internally controlled execution ordering when deterministic sequencing is explicitly required. +Its multi‑layer anti‑duplication pipeline eliminates redundant dispatches, prevents race conditions, and maintains consistent outcomes even under rapid input or concurrent triggers. +A lightweight internal tracking core provides near‑zero‑overhead cancellation and dispatch control, minimizing inconsistency without sacrificing throughput. +Despite these guarantees, StatePulse.NET preserves the flexibility of traditional untracked state management, allowing developers to selectively enforce ordering and reliability without introducing global locks or compromising responsiveness. -## ✨ Features -- ⚑ **Fast Fire-and-Forget** β€” Executes actions immediately even tracked action are fire-and-forget. -- πŸ›‘ **Anti-Duplicate Dispatching** β€” Prevents redundant or overlapping actions that can cause race condition state inconsistency. -- πŸ” **Effect Validator System** β€” Supports multiple effect validators for modular and reusable rule enforcement. -- πŸ§ͺ **Synchronous Debug Mode** β€” Optional lockstep mode for testing, diagnostics, and `Task.WhenAll` pipelines. -- 🧡 **DispatchTracker** β€” High-performance cancellation and deduplication logic via optimized concurrent tracking. +## Features + +**Fast Fire-and-Yield** +Executes actions immediately, including tracked actions, while preserving fire-and-yield semantics. + +**Multi-Layer Anti-Duplicate Dispatching** +Layer 1: Cancels previously dispatched duplicates before effects, between effects, or after effects, ensuring no redundant action progresses through the pipeline. +Layer 2: Uses a global state-change ticker enforcing a strict β€œlatest action wins” rule so outdated or superseded actions cannot update state. + +**Effect Validator System** +Supports multiple, composable validators for modular and reusable rule enforcement. + +**Synchronous Debug Mode** +Provides an optional lockstep execution mode ideal for testing, diagnostics, and `Task.WhenAll` based pipelines. + +**DispatchTracker** +Offers high-performance cancellation, deduplication, and concurrency control through an optimized tracking mechanism. + +**Short-Lived Middlewares** +Provides lightweight, disposable middleware hooks that run only during the lifetime of a single dispatch cycle. + +**Dispatch Middlewares** +Runs Before, After, and WhenDispatchFails. In asynchronous dispatch modes, failures are silently discarded unless handled internally, so DEC logic should manage its own errors; a logging middleware can also capture unhandled pipeline failures. + +**Effect Middlewares** +Runs Before, After, WhenValidationFails, and WhenValidationSucceed, allowing fine‑grained control and instrumentation around effect execution and validation flow. + +**Reducer Middlewares** +Runs Before and After the reducer, enabling patterns such as event dispatch on state changes, logging, instrumentation, or enforcing reducer‑level invariants. + ### πŸš€ **State Management with Zero Boilerplate and Zero Compromises** @@ -40,9 +64,7 @@ At the same time, it preserves the flexibility of traditional untracked state ma | StatePulse_FireYield_SequentialEffectsDispatch | 3.326 ΞΌs | 0.0661 ΞΌs | 0.0969 ΞΌs | 3.303 ΞΌs | | StatePulse_AwaitedDispatch | 4.420 ΞΌs | 0.6850 ΞΌs | 2.0196 ΞΌs | 3.165 ΞΌs | -StatePulse is very fast considering it's features but it should be avoided in tight loops which is not its intended use anyway. -I will be working to improve the performances over the long run, there are many areas which can be improved but at the moment, -i will be focusing on stable system, settings and features. +StatePulse delivers strong performance given its feature set, but it’s not designed for tight, high‑frequency loops. Long‑term performance improvements are planned, as there are several areas with optimization potential. For now, the priority remains system stability, configuration robustness, and feature completeness. ## πŸ“¦ Installation & Setup @@ -55,11 +77,85 @@ dotnet add package StatePulse.Net ``` +### 3 Ways to Register Services + +**Method 1** +The most deterministic and explicit registration approach. This method avoids β€œmagic” and one‑liners by requiring you to manually add all Reducers, Effects, Middlewares, Validators, and Actions. It provides full clarity and control over what the system loads. + ```csharp -services.AddStatePulseServices(o => - { - o.ScanAssemblies = new Type[] { typeof(Program) }; - }); + ServiceCollection.AddStatePulseServices(o => + { + o.AutoRegisterTypes = [ + typeof(MainMenuLoaderStartAction), + typeof(MainMenuLoaderStopAction), + typeof(MainMenuLoadNavigationItemsAction), + typeof(MainMenuLoadNavigationItemsResultAction), + typeof(MainMenuOpenAction), + typeof(ProfileCardDefineAction), + typeof(ProfileCardDefineResultAction), + typeof(ProfileCardLoaderStartAction), + typeof(ProfileCardLoaderStopAction), + typeof(UpdateCounterAction), + typeof(ProfileCardDefineEffect), + typeof(ProfileCardDefineResultAction), + typeof(MainMenuLoadNavigationItemsEffect), + typeof(MainMenuOpenEffect), + typeof(MainMenuOpenEffectValidation), + typeof(ProfileCardDefineActionValidator), + typeof(MainMenuLoaderStartReducer), + typeof(MainMenuLoaderStopReducer), + typeof(MainMenuLoadNavigationItemsResultReducer), + typeof(MainMenuOpenReducer), + typeof(ProfileCardDefineResultReducer), + typeof(UpdateCounterReducer), + typeof(ProfileCardState), + typeof(MainMenuState), + typeof(CounterState), + ]; + }); +``` + +**Method 2** +This is also very explicit since v2+ we have a single entry `AddStatePulseService` for all statepulse types (Reducers, Effects, Middlewares, Validators, and Actions). + +```csharp + ServiceCollection.AddStatePulseServices(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + + ServiceCollection.AddStatePulseService(); +``` + +**Method 3** +The assembly-scan approach. Convenient but not recommended for most scenarios. While useful for rapid setup, it can introduce problems as system grows. + +```csharp + ServiceCollection.AddStatePulseServices(o => { + o.ScanAssemblies = [typeof(TestBase).Assembly]; + }); ``` ## 🧭 How It Works @@ -181,7 +277,7 @@ await dispatcher.Prepare().With(p => p.TestData, name) ### Important Notes - Rule of thumb is always await dispatch calls, avoiding to do so can cause inconsistency for safe dispatch mode.. -- ISafeAction implementations are always dispatched safely, ignoring unsafe flags. +- ISafeAction implementations are always dispatched safely, ignoring unsafe flag. - synchronous is an anti-pattern of statemanement use it sparingly; it is primarily for debugging or specific scenarios requiring full completion before continuation. ### **Access State**: diff --git a/doc/docs/0.Versions.md b/doc/docs/0.Versions.md index 5761164..f05e2c2 100644 --- a/doc/docs/0.Versions.md +++ b/doc/docs/0.Versions.md @@ -90,6 +90,7 @@ sidebar_position: 0 - Fixed major issue where all race condition elements where cancelled leading to full chain cancellation including the last action. - Fixed inconsistence with race conditions. - Fixed `StateOf()` throwing inability to cast to `IStateAccessor`. +- Fixed AddStatePulseServices() configuration not optional. ## v1.1.0 ### Minor Change diff --git a/src/StatePulse.NET/ServiceRegisterExt.cs b/src/StatePulse.NET/ServiceRegisterExt.cs index 65e19bf..1bccc5d 100644 --- a/src/StatePulse.NET/ServiceRegisterExt.cs +++ b/src/StatePulse.NET/ServiceRegisterExt.cs @@ -15,11 +15,12 @@ public static class ServiceRegisterExt private static StatePulseRegistry Registry = new StatePulseRegistry(); - public static IServiceCollection AddStatePulseServices(this IServiceCollection services, Action configure) + public static IServiceCollection AddStatePulseServices(this IServiceCollection services, Action? configure = default) { services.AddScoped(); services.AddScoped(); - configure(ConfigureOptions); + if (configure != default) + configure(ConfigureOptions); bool isSingleThreadModel = ConfigureOptions.PulseTrackingPerformance == PulseTrackingModel.SingleThreadFast || ConfigureOptions.PulseTrackingPerformance == PulseTrackingModel.BlazorWebAssemblyFast; if (isSingleThreadModel) diff --git a/tests/StatPulse.NET.Tests/TestBase.cs b/tests/StatPulse.NET.Tests/TestBase.cs index 8e7e459..325c3ec 100644 --- a/tests/StatPulse.NET.Tests/TestBase.cs +++ b/tests/StatPulse.NET.Tests/TestBase.cs @@ -25,10 +25,7 @@ protected TestBase() ServiceCollection = new ServiceCollection(); // TOOD: Remove Scan Add Manual for Tests which is best policy would most lekily avoid inconsistent // service exceptions du to thread safe on bulk testing. - ServiceCollection.AddStatePulseServices(o => - { - - }); + ServiceCollection.AddStatePulseServices(); ServiceCollection.AddStatePulseService(); ServiceCollection.AddStatePulseService(); ServiceCollection.AddStatePulseService(); From ffbd42de97f211bda9c1dcadf5e10962c75112e7 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Wed, 28 Jan 2026 09:49:34 +0200 Subject: [PATCH 25/27] - Updated Documentation --- doc/docs/1. Setup Blazor Project.md | 41 ++-- doc/docs/3.Create State.md | 25 +-- doc/docs/4 Create Effects.md | 41 ++++ doc/docs/5.Create Reducer.md | 34 ++++ ...ject Dispatcher.md => 6.The Dispatcher.md} | 0 doc/docs/Getting Started.md | 185 ++++++++++++++---- 6 files changed, 262 insertions(+), 64 deletions(-) rename doc/docs/{6.Inject Dispatcher.md => 6.The Dispatcher.md} (100%) diff --git a/doc/docs/1. Setup Blazor Project.md b/doc/docs/1. Setup Blazor Project.md index 2741924..073adae 100644 --- a/doc/docs/1. Setup Blazor Project.md +++ b/doc/docs/1. Setup Blazor Project.md @@ -17,7 +17,7 @@ dotnet add package StatePulse.Net Add to ```Program.cs```: ```cs -builder.Services.AddStatePulseServices(o => {}); +builder.Services.AddStatePulseServices(); ``` Create StatePulse common folder structure. @@ -34,27 +34,32 @@ Create StatePulse common folder structure. This structure is complete and very common pattern. ## Add Services +**Method 1** +The most deterministic and explicit registration approach. This method avoids β€œmagic” and one‑liners by requiring you to manually add all Reducers, Effects, Middlewares, Validators, and Actions. It provides full clarity and control over what the system loads. -There are 2 ways to add services for StatePulse. +```csharp + ServiceCollection.AddStatePulseServices(o => + { + o.AutoRegisterTypes = [ + typeof(WHATEVER_STATEPULSE_TYPE), + ]; + }); +``` -### Scan Assmblies -The easiest way is to scan whatever assembly you have pulses in. +**Method 2** +This is also very explicit since v2+ we have a single entry `AddStatePulseService` for all statepulse types (Reducers, Effects, Middlewares, Validators, and Actions). -```cs title="program.cs" -builder.Services.AddStatePulseServices(o => -{ - o.ScanAssemblies = new Type[] { typeof(Program) }; -}); +```csharp + ServiceCollection.AddStatePulseServices(); // Register Base Services + ServiceCollection.AddStatePulseService(); ``` -### Manual Registering -StatePulse provide extension methods to add type of services and you **MUST** use them otherwise you face issues. +**Method 3** +The assembly-scan approach. Convenient but not recommended for most scenarios. While useful for rapid setup, it can introduce problems as system grows. -```cs title="program.cs" -builder.Services.AddStatePulseAction(); -builder.Services.AddStatePulseEffect(); -builder.Services.AddStatePulseEffectValidator(); -builder.Services.AddStatePulseReducer(); -builder.Services.AddStatePulseStateFeature(); +```csharp + ServiceCollection.AddStatePulseServices(o => { + o.ScanAssemblies = [typeof(TestBase).Assembly]; + }); ``` -*Note: you must manually register all services during unit test... the assembly scan doesn't get along well with unit testing.* \ No newline at end of file +*Note: The assembly scan doesn't get along well with unit testing.* diff --git a/doc/docs/3.Create State.md b/doc/docs/3.Create State.md index cf3d295..0e47f67 100644 --- a/doc/docs/3.Create State.md +++ b/doc/docs/3.Create State.md @@ -97,30 +97,33 @@ public partial class Counter : ComponentBase { [Inject] IStatePulse Pulse { get; set; } private CounterState State => Pulse.StateOf(() => this, ShouldUpdate); - [Inject] private IDispatcher Dispatcher { get; set; } public Task ShouldUpdate() => InvokeAsync(StateHasChanged); private async Task Increment() { - await Dispatcher.Prepare() + await Pulse.Dispatcher.Prepare() .With(p => p.Delay, 1) .DispatchAsync(); } } ``` +*Note: when injecting `IStatePulse`, you do not need to inject `IDispatcher`.* + > πŸ“ **Note on `StateOf()` Usage** You might notice that `Pulse.StateOf(() => this, ShouldUpdate)` is called during every render. -At first glance, this may seem inefficient β€” but it’s actually intentional and necessary. - -This method guarantees that the component is correctly bound to the state and always get latest state. -Without using this shorthand, you’d be forced to call `StateOf(...).Property` directly in your Razor markup, which becomes less readable and harder to maintain. +At first glance, this may seem inefficient or even odd syntax but it’s actually intentional, efficient and necessary. When `StateOf()` is called: - StatePulse checks whether the component (identified by `()=> this`) is already being tracked. -- If not, it sets up the binding and associates the provided `ShouldUpdate` method as a re-render callback. -- If it is already tracked, the call becomes a fast property access with near-zero overhead. +- If not, it sets up the binding and associates the provided `ShouldUpdate` method as a re-render callback (Slow first hit). +- If it is already tracked, the call becomes a fast property access with near-zero overhead (subsequent accesses are fast). + +**Mandatory Syntax** +As of v2.0+ compiler will generate an error when `()=> this` is not exactly that and when `ShouldUpdate` is a lambda which is forbidden and has to be named method to avoid runtime issues. + + +**The only cost is during the initial setup.** +All future calls are optimized, cached and safe to run on every render, on every line. -⚑ **The only cost is during the initial setup.** -All future calls are optimized and safe to run on every render. +This design ensures you always have **up-to-date, reactive state** with **no boilerplate** and **minimal performance impact**. -This design ensures you always have **up-to-date, reactive state** with **no boilerplate** and **minimal performance impact**. \ No newline at end of file diff --git a/doc/docs/4 Create Effects.md b/doc/docs/4 Create Effects.md index c5f2e02..bc80652 100644 --- a/doc/docs/4 Create Effects.md +++ b/doc/docs/4 Create Effects.md @@ -89,3 +89,44 @@ internal class IncrementEffectValidator : IEffectValidator ❗ Middleware is observational only β€” do not use it to change logic or outcomes. + +`IEffectMiddleware` allows you to hook into the execution of any effect. + +### Available Hooks + +- `BeforeEffect(object action)` – called **before** the effects run +- `AfterEffect(object action)` – called **after** the effects completed +- `WhenEffectValidationFailed(object action, object effectValidator)` – called when a validator fails. +- `WhenEffectValidationSucceed(object action, object effectValidator)` – called when a validator passes + +### Example: Effect Middleware + +```csharp title="LoggingMiddleware.cs" +internal class LoggingMiddleware : IEffectMiddleware +{ + private readonly ILogger _logger; + + public LoggingMiddleware(ILogger logger) + { + _logger = logger; + } + public Task AfterEffect(object action) + { + string message = $"{action.GetType()} finished execution."; + _logger.LogDebug(message); + return Task.CompletedTask; + } + public Task BeforeEffect(object action) => Task.CompletedTask; + public Task WhenEffectValidationFailed(object action, object effectValidator) => Task.CompletedTask; + public Task WhenEffectValidationSucceed(object action, object effectValidator) => Task.CompletedTask; +} + +``` \ No newline at end of file diff --git a/doc/docs/5.Create Reducer.md b/doc/docs/5.Create Reducer.md index f3e4d8e..7843ca4 100644 --- a/doc/docs/5.Create Reducer.md +++ b/doc/docs/5.Create Reducer.md @@ -32,4 +32,38 @@ internal class IncrementReducer : IReducer ❗ Middleware is observational only β€” do not use it to change logic or outcomes. + +`IReducerMiddleware` allows you to hook into the execution of any effect. + +### Available Hooks + +- `BeforeReducing(object state, object action)` – called **before** the reducer runs +- `AfterReducing(object state, object action)` – called **after** the reducer runs + +### Example: Reducer Middleware + +```csharp title="LoggingReducerMiddleware.cs" +internal class LoggingReducerMiddleware : IReducerMiddleware +{ + public Task AfterReducing(object state, object action) + { + Console.WriteLine($"{action.GetType().Name} Executed."); + return Task.CompletedTask; + } + + public Task BeforeReducing(object state, object action) + { + Console.WriteLine($"{state.GetType().Name} {action.GetType().Name} Executed."); + return Task.CompletedTask; + } +} ``` \ No newline at end of file diff --git a/doc/docs/6.Inject Dispatcher.md b/doc/docs/6.The Dispatcher.md similarity index 100% rename from doc/docs/6.Inject Dispatcher.md rename to doc/docs/6.The Dispatcher.md diff --git a/doc/docs/Getting Started.md b/doc/docs/Getting Started.md index 46bd8ec..3a108b3 100644 --- a/doc/docs/Getting Started.md +++ b/doc/docs/Getting Started.md @@ -7,23 +7,48 @@ sidebar_position: 1 [![License: MIT](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT) [![NuGet Version](https://img.shields.io/nuget/v/StatePulse.Net)](https://www.nuget.org/packages/StatePulse.NET) [![](https://img.shields.io/nuget/dt/StatePulse.NET?label=Downloads)](https://www.nuget.org/packages/StatePulse.NET) - - +[![Build](https://github.com/mshimshon/StatePulse.NET/actions/workflows/ci.yml/badge.svg)](https://github.com/mshimshon/StatePulse.NET/actions/workflows/ci.yml) +[![Deploy](https://github.com/mshimshon/StatePulse.NET/actions/workflows/deploy.yml/badge.svg)](https://github.com/mshimshon/StatePulse.NET/actions/workflows/deploy.yml) # StatePulse.NET ### [Official Documentation](https://statepulse.net/) -StatePulse.NET is a precision-tuned state and action management system that balances high-performance fire-and-forget operations with optional, internally controlled execution order when explicitly required. -It enables anti-duplication chaining for critical flows, preventing race conditions and ensuring consistent outcomes even under rapid user input or concurrent triggers. -Its internal tracking infrastructure provides near-zero overhead cancellation and dispatch control, drastically reducing inconsistency. -At the same time, it preserves the flexibility of traditional untracked state management, letting developers selectively enforce order and reliability without compromising overall responsiveness or introducing global locks. +StatePulse.NET is a precision‑engineered state and action management system designed for high‑performance fire‑and‑yield workflows. It supports optional, internally controlled execution ordering when deterministic sequencing is explicitly required. +Its multi‑layer anti‑duplication pipeline eliminates redundant dispatches, prevents race conditions, and maintains consistent outcomes even under rapid input or concurrent triggers. +A lightweight internal tracking core provides near‑zero‑overhead cancellation and dispatch control, minimizing inconsistency without sacrificing throughput. +Despite these guarantees, StatePulse.NET preserves the flexibility of traditional untracked state management, allowing developers to selectively enforce ordering and reliability without introducing global locks or compromising responsiveness. + + +## Features + +**Fast Fire-and-Yield** +Executes actions immediately, including tracked actions, while preserving fire-and-yield semantics. + +**Multi-Layer Anti-Duplicate Dispatching** +Layer 1: Cancels previously dispatched duplicates before effects, between effects, or after effects, ensuring no redundant action progresses through the pipeline. +Layer 2: Uses a global state-change ticker enforcing a strict β€œlatest action wins” rule so outdated or superseded actions cannot update state. + +**Effect Validator System** +Supports multiple, composable validators for modular and reusable rule enforcement. + +**Synchronous Debug Mode** +Provides an optional lockstep execution mode ideal for testing, diagnostics, and `Task.WhenAll` based pipelines. + +**DispatchTracker** +Offers high-performance cancellation, deduplication, and concurrency control through an optimized tracking mechanism. + +**Short-Lived Middlewares** +Provides lightweight, disposable middleware hooks that run only during the lifetime of a single dispatch cycle. + +**Dispatch Middlewares** +Runs Before, After, and WhenDispatchFails. In asynchronous dispatch modes, failures are silently discarded unless handled internally, so DEC logic should manage its own errors; a logging middleware can also capture unhandled pipeline failures. + +**Effect Middlewares** +Runs Before, After, WhenValidationFails, and WhenValidationSucceed, allowing fine‑grained control and instrumentation around effect execution and validation flow. + +**Reducer Middlewares** +Runs Before and After the reducer, enabling patterns such as event dispatch on state changes, logging, instrumentation, or enforcing reducer‑level invariants. -## ✨ Features -- ⚑ **Fast Fire-and-Forget** β€” Executes actions immediately even tracked action are fire-and-forget. -- πŸ›‘ **Anti-Duplicate Dispatching** β€” Prevents redundant or overlapping actions that can cause race condition state inconsistency. -- πŸ” **Effect Validator System** β€” Supports multiple effect validators for modular and reusable rule enforcement. -- πŸ§ͺ **Synchronous Debug Mode** β€” Optional lockstep mode for testing, diagnostics, and `Task.WhenAll` pipelines. -- 🧡 **DispatchTracker** β€” High-performance cancellation and deduplication logic via optimized concurrent tracking. ### πŸš€ **State Management with Zero Boilerplate and Zero Compromises** @@ -34,6 +59,19 @@ At the same time, it preserves the flexibility of traditional untracked state ma - **Transient `IStatePulse` Service:** Each component gets its own `IStatePulse` instance, isolating event subscriptions and making state updates scoped and efficient. +## Benchmark +| Method | Mean | Error | StdDev | Median | +|----------------------------------------------- |-----------:|----------:|----------:|-----------:| +| StatePulse_Dispatch | 2.458 ΞΌs | 0.0344 ΞΌs | 0.0322 ΞΌs | 2.455 ΞΌs | +| StatePulse_BusrtDispatch | 321.243 ΞΌs | 4.6181 ΞΌs | 4.3198 ΞΌs | 322.030 ΞΌs | +| StatePulse_BusrtSafeDispatch | 350.282 ΞΌs | 4.4814 ΞΌs | 4.1919 ΞΌs | 351.182 ΞΌs | +| StatePulse_FireYieldDispatch | 3.193 ΞΌs | 0.0631 ΞΌs | 0.0675 ΞΌs | 3.193 ΞΌs | +| StatePulse_FireYield_SequentialEffectsDispatch | 3.326 ΞΌs | 0.0661 ΞΌs | 0.0969 ΞΌs | 3.303 ΞΌs | +| StatePulse_AwaitedDispatch | 4.420 ΞΌs | 0.6850 ΞΌs | 2.0196 ΞΌs | 3.165 ΞΌs | + +StatePulse delivers strong performance given its feature set, but it’s not designed for tight, high‑frequency loops. Long‑term performance improvements are planned, as there are several areas with optimization potential. For now, the priority remains system stability, configuration robustness, and feature completeness. + + ## πŸ“¦ Installation & Setup @@ -44,11 +82,85 @@ dotnet add package StatePulse.Net ``` +### 3 Ways to Register Services + +**Method 1** +The most deterministic and explicit registration approach. This method avoids β€œmagic” and one‑liners by requiring you to manually add all Reducers, Effects, Middlewares, Validators, and Actions. It provides full clarity and control over what the system loads. + ```csharp -services.AddStatePulseServices(o => - { - o.ScanAssemblies = new Type[] { typeof(Program) }; - }); + ServiceCollection.AddStatePulseServices(o => + { + o.AutoRegisterTypes = [ + typeof(MainMenuLoaderStartAction), + typeof(MainMenuLoaderStopAction), + typeof(MainMenuLoadNavigationItemsAction), + typeof(MainMenuLoadNavigationItemsResultAction), + typeof(MainMenuOpenAction), + typeof(ProfileCardDefineAction), + typeof(ProfileCardDefineResultAction), + typeof(ProfileCardLoaderStartAction), + typeof(ProfileCardLoaderStopAction), + typeof(UpdateCounterAction), + typeof(ProfileCardDefineEffect), + typeof(ProfileCardDefineResultAction), + typeof(MainMenuLoadNavigationItemsEffect), + typeof(MainMenuOpenEffect), + typeof(MainMenuOpenEffectValidation), + typeof(ProfileCardDefineActionValidator), + typeof(MainMenuLoaderStartReducer), + typeof(MainMenuLoaderStopReducer), + typeof(MainMenuLoadNavigationItemsResultReducer), + typeof(MainMenuOpenReducer), + typeof(ProfileCardDefineResultReducer), + typeof(UpdateCounterReducer), + typeof(ProfileCardState), + typeof(MainMenuState), + typeof(CounterState), + ]; + }); +``` + +**Method 2** +This is also very explicit since v2+ we have a single entry `AddStatePulseService` for all statepulse types (Reducers, Effects, Middlewares, Validators, and Actions). + +```csharp + ServiceCollection.AddStatePulseServices(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + ServiceCollection.AddStatePulseService(); + + ServiceCollection.AddStatePulseService(); +``` + +**Method 3** +The assembly-scan approach. Convenient but not recommended for most scenarios. While useful for rapid setup, it can introduce problems as system grows. + +```csharp + ServiceCollection.AddStatePulseServices(o => { + o.ScanAssemblies = [typeof(TestBase).Assembly]; + }); ``` ## 🧭 How It Works @@ -69,22 +181,6 @@ public record ProfileCardDefineAction : IAction ``` -### **Define Actions Validator** (Optional): - -```csharp -/* -You are not required to create have an action validator but it is very useful when you have business logic that conditionally only contionally fires. -When validation fails it ignores the dispatch and move on. -*/ -internal class ProfileCardDefineActionValidator : IActionValidator -{ - public void Validate(ProfileCardDefineAction action, ref ValidationResult result) - { - if (action.TestData == "Error") - result.AddError("ErrorName", "Name Cannot be Error"); - } -} -``` ### **Define Effect**: @@ -109,6 +205,25 @@ internal class ProfileCardDefineEffect : IEffect } + +### **Define Effect Validator** (Optional): + +```csharp +/* +* This is the best way to define clean conditional effects, it either run or not... this is not meant for triggering errors. +* This is meant for optional/condition effects to either run or not base on the action settings... +*/ +internal class ProfileCardDefineActionValidator : IEffectValidator +{ + public Task Validate(ProfileCardDefineAction action) + { + if (action.TestData == "Error") + return Task.FromResult(false); + return Task.FromResult(true); + } +} +``` + ``` ### **Define Reducer**: @@ -167,7 +282,7 @@ await dispatcher.Prepare().With(p => p.TestData, name) ### Important Notes - Rule of thumb is always await dispatch calls, avoiding to do so can cause inconsistency for safe dispatch mode.. -- ISafeAction implementations are always dispatched safely, ignoring unsafe flags. +- ISafeAction implementations are always dispatched safely, ignoring unsafe flag. - synchronous is an anti-pattern of statemanement use it sparingly; it is primarily for debugging or specific scenarios requiring full completion before continuation. ### **Access State**: @@ -192,7 +307,7 @@ public partial class CounterView : ComponentBase // Never use lambda it will throw exception as WeakREference is fundamatally flawed and disposes of lambda even when its object is alive. private CounterState state => PulseState.StateOf(()=>this, OnUpdate); - private async Task OnUpdate() => await InvokeAsync(StateHasChanged); + private async Task OnUpdate() => await InvokeAsync(StateHadChanged); // METHOD 2: // Inject direct state but injecting the state directly requires you to handle onchanged events by sub/unsub in lifecycle @@ -201,4 +316,4 @@ public partial class CounterView : ComponentBase } -``` \ No newline at end of file +``` From e208d5792352296981610079ad8433f691d9a343 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Wed, 28 Jan 2026 16:00:17 +0200 Subject: [PATCH 26/27] - Compiled Doc --- doc/build/404.html | 6 +- doc/build/assets/js/02105171.5d7951a6.js | 1 - doc/build/assets/js/02105171.708f6e00.js | 1 + doc/build/assets/js/0bc25be7.282e267f.js | 1 - doc/build/assets/js/0bc25be7.d06e80e1.js | 1 + doc/build/assets/js/0d8668ed.85a2571d.js | 1 - doc/build/assets/js/0d8668ed.ed0000bf.js | 1 + doc/build/assets/js/22dd74f7.01add2a9.js | 1 - doc/build/assets/js/22dd74f7.15648589.js | 1 + doc/build/assets/js/2e6f86e1.0b70acfd.js | 1 - doc/build/assets/js/2e6f86e1.576f43bc.js | 1 + doc/build/assets/js/547f2087.028edb2a.js | 1 + doc/build/assets/js/547f2087.d07a2638.js | 1 - ...f61a6.9f2d00f9.js => 59af61a6.c252ee6f.js} | 2 +- doc/build/assets/js/742328d7.5ff212f5.js | 1 - doc/build/assets/js/742328d7.63a148bd.js | 1 + doc/build/assets/js/7691d1c3.1689ceb1.js | 1 - doc/build/assets/js/7691d1c3.4dd9f279.js | 1 + ...99b91.2c32870b.js => 79199b91.47c6e96b.js} | 2 +- doc/build/assets/js/8c3a5864.4dc1b980.js | 1 - doc/build/assets/js/8c3a5864.6935d223.js | 1 + doc/build/assets/js/8edd9378.05814efa.js | 1 + doc/build/assets/js/8edd9378.74846925.js | 1 - ...b9f1e.dfeb0090.js => 936b9f1e.4e0f17ee.js} | 2 +- doc/build/assets/js/94cf9043.2507e390.js | 1 - doc/build/assets/js/94cf9043.dc8ec61a.js | 1 + doc/build/assets/js/c5fd082d.0836ff42.js | 1 - doc/build/assets/js/c5fd082d.a9c7cd7d.js | 1 + doc/build/assets/js/ce33d687.1b2a2bfa.js | 1 + doc/build/assets/js/e4b9287f.17e09519.js | 1 - doc/build/assets/js/e4b9287f.be0d8a84.js | 1 + doc/build/assets/js/f2ace840.16526adf.js | 1 - doc/build/assets/js/f2ace840.9b65d131.js | 1 + doc/build/assets/js/f552f37d.15137b77.js | 1 - doc/build/assets/js/f552f37d.8dfeb3df.js | 1 + doc/build/assets/js/febfe999.614202d2.js | 1 - .../js/{main.1e4c436b.js => main.b1863699.js} | 4 +- ...CENSE.txt => main.b1863699.js.LICENSE.txt} | 0 ...n.c3a751da.js => runtime~main.94cdb742.js} | 2 +- doc/build/blog/archive/index.html | 6 +- doc/build/blog/authors/index.html | 6 +- doc/build/blog/authors/mshimshon/index.html | 6 +- doc/build/blog/first-blog-post/index.html | 6 +- doc/build/blog/index.html | 6 +- doc/build/blog/tags/docusaurus/index.html | 6 +- doc/build/blog/tags/hola/index.html | 6 +- doc/build/blog/tags/index.html | 6 +- doc/build/gs-state/index.html | 23 +-- doc/build/gs-the-action/index.html | 6 +- doc/build/gs-the-dispatcher/index.html | 8 +- doc/build/gs-the-effect/index.html | 22 ++- doc/build/gs-the-middlewares/index.html | 6 +- doc/build/gs-the-reducer/index.html | 20 ++- doc/build/index.html | 69 +++++--- doc/build/markdown-page/index.html | 6 +- doc/build/setup-blazor-project/index.html | 24 +-- doc/build/tags/actions/index.html | 6 +- doc/build/tags/async/index.html | 6 +- doc/build/tags/await/index.html | 6 +- doc/build/tags/blazor/index.html | 6 +- doc/build/tags/csharp/index.html | 6 +- .../tags/dependency-injection/index.html | 6 +- doc/build/tags/dispatcher/index.html | 6 +- doc/build/tags/effects/index.html | 6 +- doc/build/tags/immutable/index.html | 6 +- doc/build/tags/index.html | 6 +- doc/build/tags/installation/index.html | 6 +- doc/build/tags/isafeaction/index.html | 6 +- doc/build/tags/net/index.html | 6 +- doc/build/tags/performance/index.html | 6 +- doc/build/tags/pure-functions/index.html | 6 +- doc/build/tags/reducer/index.html | 6 +- doc/build/tags/redux/index.html | 6 +- doc/build/tags/safedispatch/index.html | 6 +- doc/build/tags/setup/index.html | 6 +- doc/build/tags/side-effects/index.html | 6 +- doc/build/tags/state-management/index.html | 6 +- doc/build/tags/state/index.html | 6 +- doc/build/tags/statepulse/index.html | 6 +- doc/build/versions/index.html | 161 +++++++++++++----- doc/docs/0.Versions.md | 4 +- .../Implementations/DispatcherPrepper.cs | 7 +- 82 files changed, 366 insertions(+), 226 deletions(-) delete mode 100644 doc/build/assets/js/02105171.5d7951a6.js create mode 100644 doc/build/assets/js/02105171.708f6e00.js delete mode 100644 doc/build/assets/js/0bc25be7.282e267f.js create mode 100644 doc/build/assets/js/0bc25be7.d06e80e1.js delete mode 100644 doc/build/assets/js/0d8668ed.85a2571d.js create mode 100644 doc/build/assets/js/0d8668ed.ed0000bf.js delete mode 100644 doc/build/assets/js/22dd74f7.01add2a9.js create mode 100644 doc/build/assets/js/22dd74f7.15648589.js delete mode 100644 doc/build/assets/js/2e6f86e1.0b70acfd.js create mode 100644 doc/build/assets/js/2e6f86e1.576f43bc.js create mode 100644 doc/build/assets/js/547f2087.028edb2a.js delete mode 100644 doc/build/assets/js/547f2087.d07a2638.js rename doc/build/assets/js/{59af61a6.9f2d00f9.js => 59af61a6.c252ee6f.js} (67%) delete mode 100644 doc/build/assets/js/742328d7.5ff212f5.js create mode 100644 doc/build/assets/js/742328d7.63a148bd.js delete mode 100644 doc/build/assets/js/7691d1c3.1689ceb1.js create mode 100644 doc/build/assets/js/7691d1c3.4dd9f279.js rename doc/build/assets/js/{79199b91.2c32870b.js => 79199b91.47c6e96b.js} (60%) delete mode 100644 doc/build/assets/js/8c3a5864.4dc1b980.js create mode 100644 doc/build/assets/js/8c3a5864.6935d223.js create mode 100644 doc/build/assets/js/8edd9378.05814efa.js delete mode 100644 doc/build/assets/js/8edd9378.74846925.js rename doc/build/assets/js/{936b9f1e.dfeb0090.js => 936b9f1e.4e0f17ee.js} (61%) delete mode 100644 doc/build/assets/js/94cf9043.2507e390.js create mode 100644 doc/build/assets/js/94cf9043.dc8ec61a.js delete mode 100644 doc/build/assets/js/c5fd082d.0836ff42.js create mode 100644 doc/build/assets/js/c5fd082d.a9c7cd7d.js create mode 100644 doc/build/assets/js/ce33d687.1b2a2bfa.js delete mode 100644 doc/build/assets/js/e4b9287f.17e09519.js create mode 100644 doc/build/assets/js/e4b9287f.be0d8a84.js delete mode 100644 doc/build/assets/js/f2ace840.16526adf.js create mode 100644 doc/build/assets/js/f2ace840.9b65d131.js delete mode 100644 doc/build/assets/js/f552f37d.15137b77.js create mode 100644 doc/build/assets/js/f552f37d.8dfeb3df.js delete mode 100644 doc/build/assets/js/febfe999.614202d2.js rename doc/build/assets/js/{main.1e4c436b.js => main.b1863699.js} (90%) rename doc/build/assets/js/{main.1e4c436b.js.LICENSE.txt => main.b1863699.js.LICENSE.txt} (100%) rename doc/build/assets/js/{runtime~main.c3a751da.js => runtime~main.94cdb742.js} (81%) diff --git a/doc/build/404.html b/doc/build/404.html index 746a7f7..3ae9b5c 100644 --- a/doc/build/404.html +++ b/doc/build/404.html @@ -5,13 +5,13 @@ StatePulse.NET - - + + -

    Page Not Found

    We could not find what you were looking for.

    Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

    +

    Page Not Found

    We could not find what you were looking for.

    Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

    \ No newline at end of file diff --git a/doc/build/assets/js/02105171.5d7951a6.js b/doc/build/assets/js/02105171.5d7951a6.js deleted file mode 100644 index d45dbb1..0000000 --- a/doc/build/assets/js/02105171.5d7951a6.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[972],{525:e=>{e.exports=JSON.parse('{"tag":{"label":"async","permalink":"/tags/async","allTagsPath":"/tags","count":4,"items":[{"id":"Inject Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"},{"id":"4 Create Effects","title":"The Effects","description":"What are Effects","permalink":"/gs-the-effect"},{"id":"Middlewares","title":"The Middlewares","description":"\u2699\ufe0f What are Middlewares?","permalink":"/gs-the-middlewares"},{"id":"Create Reducer","title":"The Reducers","description":"\ud83d\udd04 Reducers \u2013 Pure State Updates","permalink":"/gs-the-reducer"}],"unlisted":false}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/02105171.708f6e00.js b/doc/build/assets/js/02105171.708f6e00.js new file mode 100644 index 0000000..5683ffe --- /dev/null +++ b/doc/build/assets/js/02105171.708f6e00.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[972],{525:e=>{e.exports=JSON.parse('{"tag":{"label":"async","permalink":"/tags/async","allTagsPath":"/tags","count":4,"items":[{"id":"The Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"},{"id":"4 Create Effects","title":"The Effects","description":"What are Effects","permalink":"/gs-the-effect"},{"id":"Middlewares","title":"The Middlewares","description":"\u2699\ufe0f What are Middlewares?","permalink":"/gs-the-middlewares"},{"id":"Create Reducer","title":"The Reducers","description":"\ud83d\udd04 Reducers \u2013 Pure State Updates","permalink":"/gs-the-reducer"}],"unlisted":false}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/0bc25be7.282e267f.js b/doc/build/assets/js/0bc25be7.282e267f.js deleted file mode 100644 index 3b1848f..0000000 --- a/doc/build/assets/js/0bc25be7.282e267f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[8151],{1316:e=>{e.exports=JSON.parse('{"tag":{"label":"safedispatch","permalink":"/tags/safedispatch","allTagsPath":"/tags","count":1,"items":[{"id":"Inject Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"}],"unlisted":false}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/0bc25be7.d06e80e1.js b/doc/build/assets/js/0bc25be7.d06e80e1.js new file mode 100644 index 0000000..e7c5179 --- /dev/null +++ b/doc/build/assets/js/0bc25be7.d06e80e1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[8151],{1316:e=>{e.exports=JSON.parse('{"tag":{"label":"safedispatch","permalink":"/tags/safedispatch","allTagsPath":"/tags","count":1,"items":[{"id":"The Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"}],"unlisted":false}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/0d8668ed.85a2571d.js b/doc/build/assets/js/0d8668ed.85a2571d.js deleted file mode 100644 index d96a091..0000000 --- a/doc/build/assets/js/0d8668ed.85a2571d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[3944],{9788:e=>{e.exports=JSON.parse('{"tag":{"label":"blazor","permalink":"/tags/blazor","allTagsPath":"/tags","count":7,"items":[{"id":"Setup Blazor Project","title":"Setup Blazor Project","description":"\ud83d\udce6 Installation & Setup","permalink":"/setup-blazor-project"},{"id":"Creating Actions","title":"The Actions","description":"Type of Actions","permalink":"/gs-the-action"},{"id":"Inject Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"},{"id":"4 Create Effects","title":"The Effects","description":"What are Effects","permalink":"/gs-the-effect"},{"id":"Middlewares","title":"The Middlewares","description":"\u2699\ufe0f What are Middlewares?","permalink":"/gs-the-middlewares"},{"id":"Create Reducer","title":"The Reducers","description":"\ud83d\udd04 Reducers \u2013 Pure State Updates","permalink":"/gs-the-reducer"},{"id":"Create State","title":"The States","description":"Defining a State","permalink":"/gs-state"}],"unlisted":false}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/0d8668ed.ed0000bf.js b/doc/build/assets/js/0d8668ed.ed0000bf.js new file mode 100644 index 0000000..a974172 --- /dev/null +++ b/doc/build/assets/js/0d8668ed.ed0000bf.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[3944],{9788:e=>{e.exports=JSON.parse('{"tag":{"label":"blazor","permalink":"/tags/blazor","allTagsPath":"/tags","count":7,"items":[{"id":"Setup Blazor Project","title":"Setup Blazor Project","description":"\ud83d\udce6 Installation & Setup","permalink":"/setup-blazor-project"},{"id":"Creating Actions","title":"The Actions","description":"Type of Actions","permalink":"/gs-the-action"},{"id":"The Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"},{"id":"4 Create Effects","title":"The Effects","description":"What are Effects","permalink":"/gs-the-effect"},{"id":"Middlewares","title":"The Middlewares","description":"\u2699\ufe0f What are Middlewares?","permalink":"/gs-the-middlewares"},{"id":"Create Reducer","title":"The Reducers","description":"\ud83d\udd04 Reducers \u2013 Pure State Updates","permalink":"/gs-the-reducer"},{"id":"Create State","title":"The States","description":"Defining a State","permalink":"/gs-state"}],"unlisted":false}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/22dd74f7.01add2a9.js b/doc/build/assets/js/22dd74f7.01add2a9.js deleted file mode 100644 index b0a9362..0000000 --- a/doc/build/assets/js/22dd74f7.01add2a9.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[1567],{5226:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Updates","href":"/versions","docId":"Versions","unlisted":false},{"type":"link","label":"Get Started","href":"/","docId":"Getting Started","unlisted":false},{"type":"link","label":"Setup Blazor Project","href":"/setup-blazor-project","docId":"Setup Blazor Project","unlisted":false},{"type":"link","label":"The Actions","href":"/gs-the-action","docId":"Creating Actions","unlisted":false},{"type":"link","label":"The States","href":"/gs-state","docId":"Create State","unlisted":false},{"type":"link","label":"The Effects","href":"/gs-the-effect","docId":"4 Create Effects","unlisted":false},{"type":"link","label":"The Reducers","href":"/gs-the-reducer","docId":"Create Reducer","unlisted":false},{"type":"link","label":"The Dispatcher","href":"/gs-the-dispatcher","docId":"Inject Dispatcher","unlisted":false},{"type":"link","label":"The Middlewares","href":"/gs-the-middlewares","docId":"Middlewares","unlisted":false}]},"docs":{"4 Create Effects":{"id":"4 Create Effects","title":"The Effects","description":"What are Effects","sidebar":"tutorialSidebar"},"Create Reducer":{"id":"Create Reducer","title":"The Reducers","description":"\ud83d\udd04 Reducers \u2013 Pure State Updates","sidebar":"tutorialSidebar"},"Create State":{"id":"Create State","title":"The States","description":"Defining a State","sidebar":"tutorialSidebar"},"Creating Actions":{"id":"Creating Actions","title":"The Actions","description":"Type of Actions","sidebar":"tutorialSidebar"},"Getting Started":{"id":"Getting Started","title":"Get Started","description":"License: MIT","sidebar":"tutorialSidebar"},"Inject Dispatcher":{"id":"Inject Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","sidebar":"tutorialSidebar"},"Middlewares":{"id":"Middlewares","title":"The Middlewares","description":"\u2699\ufe0f What are Middlewares?","sidebar":"tutorialSidebar"},"Setup Blazor Project":{"id":"Setup Blazor Project","title":"Setup Blazor Project","description":"\ud83d\udce6 Installation & Setup","sidebar":"tutorialSidebar"},"Versions":{"id":"Versions","title":"Updates","description":"\ud83d\udce6 v2.0.0","sidebar":"tutorialSidebar"}}}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/22dd74f7.15648589.js b/doc/build/assets/js/22dd74f7.15648589.js new file mode 100644 index 0000000..43d43b8 --- /dev/null +++ b/doc/build/assets/js/22dd74f7.15648589.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[1567],{5226:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Updates","href":"/versions","docId":"Versions","unlisted":false},{"type":"link","label":"Get Started","href":"/","docId":"Getting Started","unlisted":false},{"type":"link","label":"Setup Blazor Project","href":"/setup-blazor-project","docId":"Setup Blazor Project","unlisted":false},{"type":"link","label":"The Actions","href":"/gs-the-action","docId":"Creating Actions","unlisted":false},{"type":"link","label":"The States","href":"/gs-state","docId":"Create State","unlisted":false},{"type":"link","label":"The Effects","href":"/gs-the-effect","docId":"4 Create Effects","unlisted":false},{"type":"link","label":"The Reducers","href":"/gs-the-reducer","docId":"Create Reducer","unlisted":false},{"type":"link","label":"The Dispatcher","href":"/gs-the-dispatcher","docId":"The Dispatcher","unlisted":false},{"type":"link","label":"The Middlewares","href":"/gs-the-middlewares","docId":"Middlewares","unlisted":false}]},"docs":{"4 Create Effects":{"id":"4 Create Effects","title":"The Effects","description":"What are Effects","sidebar":"tutorialSidebar"},"Create Reducer":{"id":"Create Reducer","title":"The Reducers","description":"\ud83d\udd04 Reducers \u2013 Pure State Updates","sidebar":"tutorialSidebar"},"Create State":{"id":"Create State","title":"The States","description":"Defining a State","sidebar":"tutorialSidebar"},"Creating Actions":{"id":"Creating Actions","title":"The Actions","description":"Type of Actions","sidebar":"tutorialSidebar"},"Getting Started":{"id":"Getting Started","title":"Get Started","description":"License: MIT","sidebar":"tutorialSidebar"},"Middlewares":{"id":"Middlewares","title":"The Middlewares","description":"\u2699\ufe0f What are Middlewares?","sidebar":"tutorialSidebar"},"Setup Blazor Project":{"id":"Setup Blazor Project","title":"Setup Blazor Project","description":"\ud83d\udce6 Installation & Setup","sidebar":"tutorialSidebar"},"The Dispatcher":{"id":"The Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","sidebar":"tutorialSidebar"},"Versions":{"id":"Versions","title":"Updates","description":"v2.0.0","sidebar":"tutorialSidebar"}}}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/2e6f86e1.0b70acfd.js b/doc/build/assets/js/2e6f86e1.0b70acfd.js deleted file mode 100644 index 9c09196..0000000 --- a/doc/build/assets/js/2e6f86e1.0b70acfd.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[8672],{7820:e=>{e.exports=JSON.parse('{"tag":{"label":"redux","permalink":"/tags/redux","allTagsPath":"/tags","count":1,"items":[{"id":"Inject Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"}],"unlisted":false}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/2e6f86e1.576f43bc.js b/doc/build/assets/js/2e6f86e1.576f43bc.js new file mode 100644 index 0000000..68b0409 --- /dev/null +++ b/doc/build/assets/js/2e6f86e1.576f43bc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[8672],{7820:e=>{e.exports=JSON.parse('{"tag":{"label":"redux","permalink":"/tags/redux","allTagsPath":"/tags","count":1,"items":[{"id":"The Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"}],"unlisted":false}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/547f2087.028edb2a.js b/doc/build/assets/js/547f2087.028edb2a.js new file mode 100644 index 0000000..1c18f56 --- /dev/null +++ b/doc/build/assets/js/547f2087.028edb2a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[7698],{7272:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>c,default:()=>f,frontMatter:()=>a,metadata:()=>s,toc:()=>o});const s=JSON.parse('{"id":"4 Create Effects","title":"The Effects","description":"What are Effects","source":"@site/docs/4 Create Effects.md","sourceDirName":".","slug":"/gs-the-effect","permalink":"/gs-the-effect","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/4 Create Effects.md","tags":[{"inline":true,"label":"blazor","permalink":"/tags/blazor"},{"inline":true,"label":"effects","permalink":"/tags/effects"},{"inline":true,"label":"state-management","permalink":"/tags/state-management"},{"inline":true,"label":"async","permalink":"/tags/async"},{"inline":true,"label":"side-effects","permalink":"/tags/side-effects"},{"inline":true,"label":"statepulse","permalink":"/tags/statepulse"},{"inline":true,"label":"csharp","permalink":"/tags/csharp"},{"inline":true,"label":".net","permalink":"/tags/net"}],"version":"current","sidebarPosition":5,"frontMatter":{"slug":"gs-the-effect","title":"The Effects","tags":["blazor","effects","state-management","async","side-effects","statepulse","csharp",".net"],"sidebar_position":5},"sidebar":"tutorialSidebar","previous":{"title":"The States","permalink":"/gs-state"},"next":{"title":"The Reducers","permalink":"/gs-the-reducer"}}');var r=t(4848),i=t(8453);const a={slug:"gs-the-effect",title:"The Effects",tags:["blazor","effects","state-management","async","side-effects","statepulse","csharp",".net"],sidebar_position:5},c=void 0,l={},o=[{value:"What are Effects",id:"what-are-effects",level:2},{value:"\ud83e\uddf1 Common Pattern: Request + Result",id:"-common-pattern-request--result",level:3},{value:"\ud83d\udcdb Naming Convention",id:"-naming-convention",level:3},{value:"Create The Effect",id:"create-the-effect",level:2},{value:"Effects Validators",id:"effects-validators",level:2},{value:"Real-World Scenario",id:"real-world-scenario",level:3},{value:"Benefits",id:"benefits",level:3},{value:"\u2699\ufe0f What are Effect Middlewares?",id:"\ufe0f-what-are-effect-middlewares",level:2},{value:"Available Hooks",id:"available-hooks",level:3},{value:"Example: Effect Middleware",id:"example-effect-middleware",level:3}];function d(e){const n={blockquote:"blockquote",br:"br",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h2,{id:"what-are-effects",children:"What are Effects"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Effects"})," are units of logic that run ",(0,r.jsx)(n.strong,{children:"in response to an action"}),", before any associated reducers are invoked."]}),"\n",(0,r.jsx)(n.p,{children:"They are commonly used for:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Performing ",(0,r.jsx)(n.strong,{children:"side effects"})," (e.g. API calls, logging, validation)"]}),"\n",(0,r.jsxs)(n.li,{children:["Dispatching ",(0,r.jsx)(n.strong,{children:"follow-up actions"})," based on results"]}),"\n",(0,r.jsxs)(n.li,{children:["Handling ",(0,r.jsx)(n.strong,{children:"asynchronous workflows"})]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"-common-pattern-request--result",children:"\ud83e\uddf1 Common Pattern: Request + Result"}),"\n",(0,r.jsx)(n.p,{children:"A typical pattern is to define:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"SomeAction"})," \u2013 the original trigger"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"SomeActionResult"})," \u2013 dispatched by the effect after the async work is done"]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["Reducers usually handle the ",(0,r.jsx)(n.code,{children:"Result"})," action to update the state."]}),"\n",(0,r.jsx)(n.h3,{id:"-naming-convention",children:"\ud83d\udcdb Naming Convention"}),"\n",(0,r.jsxs)(n.p,{children:["Effects are usually named using the action\u2019s name followed by the ",(0,r.jsx)(n.code,{children:"Effect"})," suffix."]}),"\n",(0,r.jsx)(n.h2,{id:"create-the-effect",children:"Create The Effect"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",metastring:'title="IncrementCounterEffect.cs"',children:"internal class IncrementCounterEffect : IEffect\r\n{\r\n readonly IStateAccessor _counterState;\r\n public IncrementCounterEffect(IStateAccessor counterState)\r\n {\r\n _counterState = counterState;\r\n }\r\n public async Task EffectAsync(IncrementCounterAction action, IDispatcher dispatcher)\r\n {\r\n // Recommendation: Always Await Dispatch to avoid safe execution issues, it won't block.\r\n await dispatcher.Prepare()\r\n .With(p => p.Count, _counterState.State.Count + 1)\r\n .DispatchAsync();\r\n }\r\n}\n"})}),"\n",(0,r.jsx)(n.h2,{id:"effects-validators",children:"Effects Validators"}),"\n",(0,r.jsxs)(n.p,{children:["Effect validators allow you to ",(0,r.jsx)(n.strong,{children:"run checks before an effect executes"}),", deciding whether the effect should run or be skipped."]}),"\n",(0,r.jsxs)(n.p,{children:["They receive both the ",(0,r.jsx)(n.strong,{children:"action"})," and the ",(0,r.jsx)(n.strong,{children:"effect instance"}),", since a single action can trigger ",(0,r.jsx)(n.strong,{children:"multiple effects"}),".",(0,r.jsx)(n.br,{}),"\n","By binding one or more validators to a specific effect, you can control its execution based on any logic you want."]}),"\n",(0,r.jsx)(n.h3,{id:"real-world-scenario",children:"Real-World Scenario"}),"\n",(0,r.jsxs)(n.p,{children:["Imagine you have an action, say ",(0,r.jsx)(n.code,{children:"RequestContentAction"}),", that is triggered by ",(0,r.jsx)(n.strong,{children:"all users"}),":"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["For ",(0,r.jsx)(n.strong,{children:"non-subscribed users"}),", you want an effect that returns a limited preview or redirects to a subscription page."]}),"\n",(0,r.jsxs)(n.li,{children:["For ",(0,r.jsx)(n.strong,{children:"subscribed members"}),", you want a different effect that fetches full content."]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Using effect validators, you can bind:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["A validator on the ",(0,r.jsx)(n.strong,{children:"non-member effect"})," that checks if the user is ",(0,r.jsx)(n.em,{children:"not"})," subscribed and only runs the effect in that case."]}),"\n",(0,r.jsxs)(n.li,{children:["A validator on the ",(0,r.jsx)(n.strong,{children:"member effect"})," that checks if the user ",(0,r.jsx)(n.em,{children:"is"})," subscribed."]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["This way, ",(0,r.jsx)(n.strong,{children:"both effects respond to the same action but run conditionally based on user status."})]}),"\n",(0,r.jsx)(n.h3,{id:"benefits",children:"Benefits"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Allows ",(0,r.jsx)(n.strong,{children:"clean separation"})," of logic for different user scenarios"]}),"\n",(0,r.jsxs)(n.li,{children:["Keeps action handling unified while supporting ",(0,r.jsx)(n.strong,{children:"multiple conditional outcomes"})]}),"\n",(0,r.jsx)(n.li,{children:"Avoids complex branching inside effects themselves"}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["Effect validators are a powerful way to ",(0,r.jsx)(n.strong,{children:"condition effect execution"})," by checking custom conditions involving the action and the current state,",(0,r.jsx)(n.br,{}),"\n","enabling flexible and maintainable multi-effect workflows based on business rules."]}),"\n",(0,r.jsx)(n.p,{children:"if any validator fails the effect is skipped."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",metastring:'title="IncrementEffectValidator.cs"',children:"internal class IncrementEffectValidator : IEffectValidator\r\n{\r\n public Task Validate(IncrementCounterAction action)\r\n {\r\n if (action.Delay > 1000) return Task.FromResult(false);\r\n return Task.FromResult(true);\r\n }\r\n}\r\n\n"})}),"\n",(0,r.jsx)(n.h2,{id:"\ufe0f-what-are-effect-middlewares",children:"\u2699\ufe0f What are Effect Middlewares?"}),"\n",(0,r.jsxs)(n.p,{children:["StatePulse uses ",(0,r.jsx)(n.strong,{children:"middleware interfaces"})," to tap into the lifecycle of ",(0,r.jsx)(n.strong,{children:"effects"}),", ",(0,r.jsx)(n.strong,{children:"reducers"}),", and ",(0,r.jsx)(n.strong,{children:"dispatches"}),".",(0,r.jsx)(n.br,{}),"\n","These middleware hooks are useful for ",(0,r.jsx)(n.strong,{children:"logging"}),", ",(0,r.jsx)(n.strong,{children:"metrics"}),", ",(0,r.jsx)(n.strong,{children:"analytics"}),", or ",(0,r.jsx)(n.strong,{children:"debugging"})," \u2014 but should ",(0,r.jsx)(n.strong,{children:"never alter behavior"})," or mutate state."]}),"\n",(0,r.jsxs)(n.blockquote,{children:["\n",(0,r.jsx)(n.p,{children:"\u2757 Middleware is observational only \u2014 do not use it to change logic or outcomes."}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"IEffectMiddleware"})," allows you to hook into the execution of any effect."]}),"\n",(0,r.jsx)(n.h3,{id:"available-hooks",children:"Available Hooks"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"BeforeEffect(object action)"})," \u2013 called ",(0,r.jsx)(n.strong,{children:"before"})," the effects run"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"AfterEffect(object action)"})," \u2013 called ",(0,r.jsx)(n.strong,{children:"after"})," the effects completed"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"WhenEffectValidationFailed(object action, object effectValidator)"})," \u2013 called when a validator fails."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"WhenEffectValidationSucceed(object action, object effectValidator)"})," \u2013 called when a validator passes"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"example-effect-middleware",children:"Example: Effect Middleware"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",metastring:'title="LoggingMiddleware.cs"',children:'internal class LoggingMiddleware : IEffectMiddleware\r\n{\r\n private readonly ILogger _logger;\r\n\r\n public LoggingMiddleware(ILogger logger)\r\n {\r\n _logger = logger;\r\n }\r\n public Task AfterEffect(object action)\r\n {\r\n string message = $"{action.GetType()} finished execution.";\r\n _logger.LogDebug(message);\r\n return Task.CompletedTask;\r\n }\r\n public Task BeforeEffect(object action) => Task.CompletedTask;\r\n public Task WhenEffectValidationFailed(object action, object effectValidator) => Task.CompletedTask;\r\n public Task WhenEffectValidationSucceed(object action, object effectValidator) => Task.CompletedTask;\r\n}\r\n\n'})})]})}function f(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>c});var s=t(6540);const r={},i=s.createContext(r);function a(e){const n=s.useContext(i);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/doc/build/assets/js/547f2087.d07a2638.js b/doc/build/assets/js/547f2087.d07a2638.js deleted file mode 100644 index 1ffa847..0000000 --- a/doc/build/assets/js/547f2087.d07a2638.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[7698],{7272:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>f,frontMatter:()=>c,metadata:()=>s,toc:()=>o});const s=JSON.parse('{"id":"4 Create Effects","title":"The Effects","description":"What are Effects","source":"@site/docs/4 Create Effects.md","sourceDirName":".","slug":"/gs-the-effect","permalink":"/gs-the-effect","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/4 Create Effects.md","tags":[{"inline":true,"label":"blazor","permalink":"/tags/blazor"},{"inline":true,"label":"effects","permalink":"/tags/effects"},{"inline":true,"label":"state-management","permalink":"/tags/state-management"},{"inline":true,"label":"async","permalink":"/tags/async"},{"inline":true,"label":"side-effects","permalink":"/tags/side-effects"},{"inline":true,"label":"statepulse","permalink":"/tags/statepulse"},{"inline":true,"label":"csharp","permalink":"/tags/csharp"},{"inline":true,"label":".net","permalink":"/tags/net"}],"version":"current","sidebarPosition":5,"frontMatter":{"slug":"gs-the-effect","title":"The Effects","tags":["blazor","effects","state-management","async","side-effects","statepulse","csharp",".net"],"sidebar_position":5},"sidebar":"tutorialSidebar","previous":{"title":"The States","permalink":"/gs-state"},"next":{"title":"The Reducers","permalink":"/gs-the-reducer"}}');var r=t(4848),i=t(8453);const c={slug:"gs-the-effect",title:"The Effects",tags:["blazor","effects","state-management","async","side-effects","statepulse","csharp",".net"],sidebar_position:5},a=void 0,l={},o=[{value:"What are Effects",id:"what-are-effects",level:2},{value:"\ud83e\uddf1 Common Pattern: Request + Result",id:"-common-pattern-request--result",level:3},{value:"\ud83d\udcdb Naming Convention",id:"-naming-convention",level:3},{value:"Create The Effect",id:"create-the-effect",level:2},{value:"Effects Validators",id:"effects-validators",level:2},{value:"Real-World Scenario",id:"real-world-scenario",level:3},{value:"Benefits",id:"benefits",level:3}];function d(e){const n={br:"br",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h2,{id:"what-are-effects",children:"What are Effects"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Effects"})," are units of logic that run ",(0,r.jsx)(n.strong,{children:"in response to an action"}),", before any associated reducers are invoked."]}),"\n",(0,r.jsx)(n.p,{children:"They are commonly used for:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Performing ",(0,r.jsx)(n.strong,{children:"side effects"})," (e.g. API calls, logging, validation)"]}),"\n",(0,r.jsxs)(n.li,{children:["Dispatching ",(0,r.jsx)(n.strong,{children:"follow-up actions"})," based on results"]}),"\n",(0,r.jsxs)(n.li,{children:["Handling ",(0,r.jsx)(n.strong,{children:"asynchronous workflows"})]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"-common-pattern-request--result",children:"\ud83e\uddf1 Common Pattern: Request + Result"}),"\n",(0,r.jsx)(n.p,{children:"A typical pattern is to define:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"SomeAction"})," \u2013 the original trigger"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"SomeActionResult"})," \u2013 dispatched by the effect after the async work is done"]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["Reducers usually handle the ",(0,r.jsx)(n.code,{children:"Result"})," action to update the state."]}),"\n",(0,r.jsx)(n.h3,{id:"-naming-convention",children:"\ud83d\udcdb Naming Convention"}),"\n",(0,r.jsxs)(n.p,{children:["Effects are usually named using the action\u2019s name followed by the ",(0,r.jsx)(n.code,{children:"Effect"})," suffix."]}),"\n",(0,r.jsx)(n.h2,{id:"create-the-effect",children:"Create The Effect"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",metastring:'title="IncrementCounterEffect.cs"',children:"internal class IncrementCounterEffect : IEffect\r\n{\r\n readonly IStateAccessor _counterState;\r\n public IncrementCounterEffect(IStateAccessor counterState)\r\n {\r\n _counterState = counterState;\r\n }\r\n public async Task EffectAsync(IncrementCounterAction action, IDispatcher dispatcher)\r\n {\r\n // Recommendation: Always Await Dispatch to avoid safe execution issues, it won't block.\r\n await dispatcher.Prepare()\r\n .With(p => p.Count, _counterState.State.Count + 1)\r\n .DispatchAsync();\r\n }\r\n}\n"})}),"\n",(0,r.jsx)(n.h2,{id:"effects-validators",children:"Effects Validators"}),"\n",(0,r.jsxs)(n.p,{children:["Effect validators allow you to ",(0,r.jsx)(n.strong,{children:"run checks before an effect executes"}),", deciding whether the effect should run or be skipped."]}),"\n",(0,r.jsxs)(n.p,{children:["They receive both the ",(0,r.jsx)(n.strong,{children:"action"})," and the ",(0,r.jsx)(n.strong,{children:"effect instance"}),", since a single action can trigger ",(0,r.jsx)(n.strong,{children:"multiple effects"}),".",(0,r.jsx)(n.br,{}),"\n","By binding one or more validators to a specific effect, you can control its execution based on any logic you want."]}),"\n",(0,r.jsx)(n.h3,{id:"real-world-scenario",children:"Real-World Scenario"}),"\n",(0,r.jsxs)(n.p,{children:["Imagine you have an action, say ",(0,r.jsx)(n.code,{children:"RequestContentAction"}),", that is triggered by ",(0,r.jsx)(n.strong,{children:"all users"}),":"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["For ",(0,r.jsx)(n.strong,{children:"non-subscribed users"}),", you want an effect that returns a limited preview or redirects to a subscription page."]}),"\n",(0,r.jsxs)(n.li,{children:["For ",(0,r.jsx)(n.strong,{children:"subscribed members"}),", you want a different effect that fetches full content."]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Using effect validators, you can bind:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["A validator on the ",(0,r.jsx)(n.strong,{children:"non-member effect"})," that checks if the user is ",(0,r.jsx)(n.em,{children:"not"})," subscribed and only runs the effect in that case."]}),"\n",(0,r.jsxs)(n.li,{children:["A validator on the ",(0,r.jsx)(n.strong,{children:"member effect"})," that checks if the user ",(0,r.jsx)(n.em,{children:"is"})," subscribed."]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["This way, ",(0,r.jsx)(n.strong,{children:"both effects respond to the same action but run conditionally based on user status."})]}),"\n",(0,r.jsx)(n.h3,{id:"benefits",children:"Benefits"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Allows ",(0,r.jsx)(n.strong,{children:"clean separation"})," of logic for different user scenarios"]}),"\n",(0,r.jsxs)(n.li,{children:["Keeps action handling unified while supporting ",(0,r.jsx)(n.strong,{children:"multiple conditional outcomes"})]}),"\n",(0,r.jsx)(n.li,{children:"Avoids complex branching inside effects themselves"}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["Effect validators are a powerful way to ",(0,r.jsx)(n.strong,{children:"condition effect execution"})," by checking custom conditions involving the action and the current state,",(0,r.jsx)(n.br,{}),"\n","enabling flexible and maintainable multi-effect workflows based on business rules."]}),"\n",(0,r.jsx)(n.p,{children:"if any validator fails the effect is skipped."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",metastring:'title="IncrementEffectValidator.cs"',children:"internal class IncrementEffectValidator : IEffectValidator\r\n{\r\n public Task Validate(IncrementCounterAction action)\r\n {\r\n if (action.Delay > 1000) return Task.FromResult(false);\r\n return Task.FromResult(true);\r\n }\r\n}\r\n\n"})})]})}function f(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>c,x:()=>a});var s=t(6540);const r={},i=s.createContext(r);function c(e){const n=s.useContext(i);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:c(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/doc/build/assets/js/59af61a6.9f2d00f9.js b/doc/build/assets/js/59af61a6.c252ee6f.js similarity index 67% rename from doc/build/assets/js/59af61a6.9f2d00f9.js rename to doc/build/assets/js/59af61a6.c252ee6f.js index e4b30c2..0e6da16 100644 --- a/doc/build/assets/js/59af61a6.9f2d00f9.js +++ b/doc/build/assets/js/59af61a6.c252ee6f.js @@ -1 +1 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[9174],{5332:a=>{a.exports=JSON.parse('{"tags":[{"label":"blazor","permalink":"/tags/blazor","count":7},{"label":"effects","permalink":"/tags/effects","count":1},{"label":"state-management","permalink":"/tags/state-management","count":6},{"label":"async","permalink":"/tags/async","count":4},{"label":"side-effects","permalink":"/tags/side-effects","count":1},{"label":"statepulse","permalink":"/tags/statepulse","count":7},{"label":"csharp","permalink":"/tags/csharp","count":6},{"label":".net","permalink":"/tags/net","count":6},{"label":"reducer","permalink":"/tags/reducer","count":2},{"label":"pure-functions","permalink":"/tags/pure-functions","count":2},{"label":"state","permalink":"/tags/state","count":1},{"label":"immutable","permalink":"/tags/immutable","count":1},{"label":"actions","permalink":"/tags/actions","count":2},{"label":"isafeaction","permalink":"/tags/isafeaction","count":1},{"label":"performance","permalink":"/tags/performance","count":2},{"label":"dispatcher","permalink":"/tags/dispatcher","count":1},{"label":"safedispatch","permalink":"/tags/safedispatch","count":1},{"label":"redux","permalink":"/tags/redux","count":1},{"label":"await","permalink":"/tags/await","count":1},{"label":"setup","permalink":"/tags/setup","count":1},{"label":"installation","permalink":"/tags/installation","count":1},{"label":"dependency-injection","permalink":"/tags/dependency-injection","count":1}]}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[9174],{5332:a=>{a.exports=JSON.parse('{"tags":[{"label":"blazor","permalink":"/tags/blazor","count":7},{"label":"effects","permalink":"/tags/effects","count":1},{"label":"state-management","permalink":"/tags/state-management","count":6},{"label":"async","permalink":"/tags/async","count":4},{"label":"side-effects","permalink":"/tags/side-effects","count":1},{"label":"statepulse","permalink":"/tags/statepulse","count":7},{"label":"csharp","permalink":"/tags/csharp","count":6},{"label":".net","permalink":"/tags/net","count":6},{"label":"reducer","permalink":"/tags/reducer","count":2},{"label":"pure-functions","permalink":"/tags/pure-functions","count":2},{"label":"state","permalink":"/tags/state","count":1},{"label":"immutable","permalink":"/tags/immutable","count":1},{"label":"actions","permalink":"/tags/actions","count":2},{"label":"isafeaction","permalink":"/tags/isafeaction","count":1},{"label":"performance","permalink":"/tags/performance","count":2},{"label":"setup","permalink":"/tags/setup","count":1},{"label":"installation","permalink":"/tags/installation","count":1},{"label":"dependency-injection","permalink":"/tags/dependency-injection","count":1},{"label":"dispatcher","permalink":"/tags/dispatcher","count":1},{"label":"safedispatch","permalink":"/tags/safedispatch","count":1},{"label":"redux","permalink":"/tags/redux","count":1},{"label":"await","permalink":"/tags/await","count":1}]}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/742328d7.5ff212f5.js b/doc/build/assets/js/742328d7.5ff212f5.js deleted file mode 100644 index 988558a..0000000 --- a/doc/build/assets/js/742328d7.5ff212f5.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[3318],{3647:e=>{e.exports=JSON.parse('{"tag":{"label":"dispatcher","permalink":"/tags/dispatcher","allTagsPath":"/tags","count":1,"items":[{"id":"Inject Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"}],"unlisted":false}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/742328d7.63a148bd.js b/doc/build/assets/js/742328d7.63a148bd.js new file mode 100644 index 0000000..1b8ab1f --- /dev/null +++ b/doc/build/assets/js/742328d7.63a148bd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[3318],{3647:e=>{e.exports=JSON.parse('{"tag":{"label":"dispatcher","permalink":"/tags/dispatcher","allTagsPath":"/tags","count":1,"items":[{"id":"The Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"}],"unlisted":false}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/7691d1c3.1689ceb1.js b/doc/build/assets/js/7691d1c3.1689ceb1.js deleted file mode 100644 index 6dbe385..0000000 --- a/doc/build/assets/js/7691d1c3.1689ceb1.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[177],{7292:e=>{e.exports=JSON.parse('{"tag":{"label":"state-management","permalink":"/tags/state-management","allTagsPath":"/tags","count":6,"items":[{"id":"Creating Actions","title":"The Actions","description":"Type of Actions","permalink":"/gs-the-action"},{"id":"Inject Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"},{"id":"4 Create Effects","title":"The Effects","description":"What are Effects","permalink":"/gs-the-effect"},{"id":"Middlewares","title":"The Middlewares","description":"\u2699\ufe0f What are Middlewares?","permalink":"/gs-the-middlewares"},{"id":"Create Reducer","title":"The Reducers","description":"\ud83d\udd04 Reducers \u2013 Pure State Updates","permalink":"/gs-the-reducer"},{"id":"Create State","title":"The States","description":"Defining a State","permalink":"/gs-state"}],"unlisted":false}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/7691d1c3.4dd9f279.js b/doc/build/assets/js/7691d1c3.4dd9f279.js new file mode 100644 index 0000000..2ef48cc --- /dev/null +++ b/doc/build/assets/js/7691d1c3.4dd9f279.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[177],{7292:e=>{e.exports=JSON.parse('{"tag":{"label":"state-management","permalink":"/tags/state-management","allTagsPath":"/tags","count":6,"items":[{"id":"Creating Actions","title":"The Actions","description":"Type of Actions","permalink":"/gs-the-action"},{"id":"The Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"},{"id":"4 Create Effects","title":"The Effects","description":"What are Effects","permalink":"/gs-the-effect"},{"id":"Middlewares","title":"The Middlewares","description":"\u2699\ufe0f What are Middlewares?","permalink":"/gs-the-middlewares"},{"id":"Create Reducer","title":"The Reducers","description":"\ud83d\udd04 Reducers \u2013 Pure State Updates","permalink":"/gs-the-reducer"},{"id":"Create State","title":"The States","description":"Defining a State","permalink":"/gs-state"}],"unlisted":false}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/79199b91.2c32870b.js b/doc/build/assets/js/79199b91.47c6e96b.js similarity index 60% rename from doc/build/assets/js/79199b91.2c32870b.js rename to doc/build/assets/js/79199b91.47c6e96b.js index 9b4fa02..8be282f 100644 --- a/doc/build/assets/js/79199b91.2c32870b.js +++ b/doc/build/assets/js/79199b91.47c6e96b.js @@ -1 +1 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[4850],{6798:e=>{e.exports=JSON.parse('{"tag":{"label":"performance","permalink":"/tags/performance","allTagsPath":"/tags","count":2,"items":[{"id":"Creating Actions","title":"The Actions","description":"Type of Actions","permalink":"/gs-the-action"},{"id":"Inject Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"}],"unlisted":false}}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[4850],{6798:e=>{e.exports=JSON.parse('{"tag":{"label":"performance","permalink":"/tags/performance","allTagsPath":"/tags","count":2,"items":[{"id":"Creating Actions","title":"The Actions","description":"Type of Actions","permalink":"/gs-the-action"},{"id":"The Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"}],"unlisted":false}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/8c3a5864.4dc1b980.js b/doc/build/assets/js/8c3a5864.4dc1b980.js deleted file mode 100644 index 0544b27..0000000 --- a/doc/build/assets/js/8c3a5864.4dc1b980.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[841],{7400:e=>{e.exports=JSON.parse('{"tag":{"label":"await","permalink":"/tags/await","allTagsPath":"/tags","count":1,"items":[{"id":"Inject Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"}],"unlisted":false}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/8c3a5864.6935d223.js b/doc/build/assets/js/8c3a5864.6935d223.js new file mode 100644 index 0000000..dd94a42 --- /dev/null +++ b/doc/build/assets/js/8c3a5864.6935d223.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[841],{7400:e=>{e.exports=JSON.parse('{"tag":{"label":"await","permalink":"/tags/await","allTagsPath":"/tags","count":1,"items":[{"id":"The Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"}],"unlisted":false}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/8edd9378.05814efa.js b/doc/build/assets/js/8edd9378.05814efa.js new file mode 100644 index 0000000..cbbe62f --- /dev/null +++ b/doc/build/assets/js/8edd9378.05814efa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[855],{4801:e=>{e.exports=JSON.parse('{"tag":{"label":"statepulse","permalink":"/tags/statepulse","allTagsPath":"/tags","count":7,"items":[{"id":"Setup Blazor Project","title":"Setup Blazor Project","description":"\ud83d\udce6 Installation & Setup","permalink":"/setup-blazor-project"},{"id":"Creating Actions","title":"The Actions","description":"Type of Actions","permalink":"/gs-the-action"},{"id":"The Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"},{"id":"4 Create Effects","title":"The Effects","description":"What are Effects","permalink":"/gs-the-effect"},{"id":"Middlewares","title":"The Middlewares","description":"\u2699\ufe0f What are Middlewares?","permalink":"/gs-the-middlewares"},{"id":"Create Reducer","title":"The Reducers","description":"\ud83d\udd04 Reducers \u2013 Pure State Updates","permalink":"/gs-the-reducer"},{"id":"Create State","title":"The States","description":"Defining a State","permalink":"/gs-state"}],"unlisted":false}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/8edd9378.74846925.js b/doc/build/assets/js/8edd9378.74846925.js deleted file mode 100644 index f718175..0000000 --- a/doc/build/assets/js/8edd9378.74846925.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[855],{4801:e=>{e.exports=JSON.parse('{"tag":{"label":"statepulse","permalink":"/tags/statepulse","allTagsPath":"/tags","count":7,"items":[{"id":"Setup Blazor Project","title":"Setup Blazor Project","description":"\ud83d\udce6 Installation & Setup","permalink":"/setup-blazor-project"},{"id":"Creating Actions","title":"The Actions","description":"Type of Actions","permalink":"/gs-the-action"},{"id":"Inject Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"},{"id":"4 Create Effects","title":"The Effects","description":"What are Effects","permalink":"/gs-the-effect"},{"id":"Middlewares","title":"The Middlewares","description":"\u2699\ufe0f What are Middlewares?","permalink":"/gs-the-middlewares"},{"id":"Create Reducer","title":"The Reducers","description":"\ud83d\udd04 Reducers \u2013 Pure State Updates","permalink":"/gs-the-reducer"},{"id":"Create State","title":"The States","description":"Defining a State","permalink":"/gs-state"}],"unlisted":false}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/936b9f1e.dfeb0090.js b/doc/build/assets/js/936b9f1e.4e0f17ee.js similarity index 61% rename from doc/build/assets/js/936b9f1e.dfeb0090.js rename to doc/build/assets/js/936b9f1e.4e0f17ee.js index 490df72..0919298 100644 --- a/doc/build/assets/js/936b9f1e.dfeb0090.js +++ b/doc/build/assets/js/936b9f1e.4e0f17ee.js @@ -1 +1 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[6980],{464:t=>{t.exports=JSON.parse('{"tag":{"label":"actions","permalink":"/tags/actions","allTagsPath":"/tags","count":2,"items":[{"id":"Creating Actions","title":"The Actions","description":"Type of Actions","permalink":"/gs-the-action"},{"id":"Inject Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"}],"unlisted":false}}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[6980],{464:t=>{t.exports=JSON.parse('{"tag":{"label":"actions","permalink":"/tags/actions","allTagsPath":"/tags","count":2,"items":[{"id":"Creating Actions","title":"The Actions","description":"Type of Actions","permalink":"/gs-the-action"},{"id":"The Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","permalink":"/gs-the-dispatcher"}],"unlisted":false}}')}}]); \ No newline at end of file diff --git a/doc/build/assets/js/94cf9043.2507e390.js b/doc/build/assets/js/94cf9043.2507e390.js deleted file mode 100644 index 0c30909..0000000 --- a/doc/build/assets/js/94cf9043.2507e390.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[6683],{8453:(e,n,i)=>{i.d(n,{R:()=>t,x:()=>d});var s=i(6540);const r={},l=s.createContext(r);function t(e){const n=s.useContext(l);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:t(e.components),s.createElement(l.Provider,{value:n},e.children)}},8886:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>d,default:()=>h,frontMatter:()=>t,metadata:()=>s,toc:()=>o});const s=JSON.parse('{"id":"Versions","title":"Updates","description":"\ud83d\udce6 v2.0.0","source":"@site/docs/0.Versions.md","sourceDirName":".","slug":"/versions","permalink":"/versions","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/0.Versions.md","tags":[],"version":"current","sidebarPosition":0,"frontMatter":{"slug":"versions","title":"Updates","sidebar_position":0},"sidebar":"tutorialSidebar","next":{"title":"Get Started","permalink":"/"}}');var r=i(4848),l=i(8453);const t={slug:"versions",title:"Updates",sidebar_position:0},d=void 0,c={},o=[{value:"\ud83d\udce6 v2.0.0",id:"-v200",level:2},{value:"\u2728 BREAKING CHANGES",id:"-breaking-changes",level:3},{value:"\u2728 New Features",id:"-new-features",level:3},{value:"\ud83d\udce6 v1.1.0",id:"-v110",level:2},{value:"\u2728 Minor Change",id:"-minor-change",level:3},{value:"\ud83d\udce6 v1.0.2",id:"-v102",level:2},{value:"\ud83d\udc1e Fixes",id:"-fixes",level:3},{value:"\ud83d\udce6 v1.0.1",id:"-v101",level:2},{value:"\u2728 Minor Change",id:"-minor-change-1",level:3},{value:"\ud83d\udce6 v1.0.0",id:"-v100",level:2},{value:"\u2728 New Features",id:"-new-features-1",level:3},{value:"\ud83d\udca5 Breaking Changes",id:"-breaking-changes-1",level:3},{value:"\ud83d\ude80 Performance Improvements",id:"-performance-improvements",level:3},{value:"\ud83e\uddfc Clean Code Improvements",id:"-clean-code-improvements",level:3},{value:"\ud83d\udc1e Fixes",id:"-fixes-1",level:3},{value:"v0.9.41",id:"v0941",level:2},{value:"v0.9.4",id:"v094",level:2},{value:"v0.9.21",id:"v0921",level:2},{value:"v0.9.2 (Blazor Packages)",id:"v092-blazor-packages",level:2}];function a(e){const n={code:"code",h2:"h2",h3:"h3",li:"li",strong:"strong",ul:"ul",...(0,l.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h2,{id:"-v200",children:"\ud83d\udce6 v2.0.0"}),"\n",(0,r.jsx)(n.h3,{id:"-breaking-changes",children:"\u2728 BREAKING CHANGES"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"The signature of interfaces changed so any plugin-based system could potentially break if core updates and plugins don't unless plugin isolation is respected."}),"\n",(0,r.jsxs)(n.li,{children:["The REDUCERS now run before the effects! so any pipelines relying on post-effect reducers should configure StatePulse to execute reducers post effect (simple config flip) ",(0,r.jsx)(n.code,{children:"Configure.DispatchOrderBehavior = DispatchOrdering.EffectsFirst;"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"-new-features",children:"\u2728 New Features"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"\u2699\ufe0f Enhanced Configuration Options"})," - New global configuration properties:","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"DispatchOrderBehavior"})," - Set default ordering (EffectsFirst/ReducersFirst)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"DispatchEffectExecutionBehavior"})," - Set default execution mode (YieldAndFire/FireAndForget)"]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"\ud83c\udf9b\ufe0f Configurable Dispatch Ordering"})," - Choose between ",(0,r.jsx)(n.code,{children:"EffectsFirst"})," (default) or ",(0,r.jsx)(n.code,{children:"ReducersFirst"})," execution order globally or per-dispatch"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"\u26a1 True Fire-and-Forget Execution Mode"})," - New ",(0,r.jsx)(n.code,{children:"DispatchEffectExecutionBehavior.FireAndForget"})," for true background execution without yielding and awaiting effects"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"\ud83d\udd27 Per-Dispatch Execution Control"})," - Override global settings per dispatch with fluent API:","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:".ExecFireAndForget()"})," - Fully detached background execution"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:".ExecYieldAndFire()"})," - Yield to caller but await until all effects are done to move down the pipeline"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:".EffectsFirst()"})," - Run effects before reducers"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:".ReducersFirst()"})," - Run reducers before effects"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:".SequentialEffects()"})," - Force effects to run in sequence"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:".ParallelEffects()"})," - Force effects to run in parallel"]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"\ud83d\udee1\ufe0f Invalid Configuration Detection"})," - New ",(0,r.jsx)(n.code,{children:"InvalidDispatchCombinationException"})," thrown at dispatch time for incompatible configuration combinations (Plan to generate compiler errors later)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"\u267b\ufe0f Recursive Dispatch Support"})," - Fire-and-forget mode enables safe recursive dispatch patterns without deadlocks"]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"-v110",children:"\ud83d\udce6 v1.1.0"}),"\n",(0,r.jsx)(n.h3,{id:"-minor-change",children:"\u2728 Minor Change"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Upgraded to .NET 10"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"-v102",children:"\ud83d\udce6 v1.0.2"}),"\n",(0,r.jsx)(n.h3,{id:"-fixes",children:"\ud83d\udc1e Fixes"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Added StatePulse.Net.Abstractions package reference instead of project reference to fix IL trimming issues."}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"-v101",children:"\ud83d\udce6 v1.0.1"}),"\n",(0,r.jsx)(n.h3,{id:"-minor-change-1",children:"\u2728 Minor Change"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Splited Abstractions into StatePulse.Net.Abstractions (Will not break anything Namespace is the same)"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"-v100",children:"\ud83d\udce6 v1.0.0"}),"\n",(0,r.jsx)(n.h3,{id:"-new-features-1",children:"\u2728 New Features"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\u2705 ",(0,r.jsx)(n.strong,{children:"Action Effect Validator"}),": Allows effects to run conditionally by validating them before execution."]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83e\udde9 ",(0,r.jsx)(n.strong,{children:"Middleware Support"}),":","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"IEffectMiddleware"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"IReducerMiddleware"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"IDispatchMiddleware"})}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\u2699\ufe0f ",(0,r.jsx)(n.strong,{children:"Behavior Configuration"}),": You can configure execution behaviors via:","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"DispatchEffectBehavior"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"MiddlewareEffectBehavior"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"MiddlewareTaskBehavior"})}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83d\udee0\ufe0f ",(0,r.jsx)(n.strong,{children:"Strict Manual Registration"}),": Manual service registration ",(0,r.jsx)(n.strong,{children:"must use"})," extension methods:","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"AddStatePulse()"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"AddStatePulseEffect<>()"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"AddStatePulseAction<>()"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"AddStatePulseReducer<>()"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"AddStatePulseStateFeature<>()"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"AddStatePulseEffectValidator<>()"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"-breaking-changes-1",children:"\ud83d\udca5 Breaking Changes"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\u274c Removed ",(0,r.jsx)(n.strong,{children:"Action Validator"})," \u2013 validating action data is not the responsibility of the state management layer."]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83d\udd04 Renamed:","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"IStateAccessor<>.StateChanged"})," \u2192 ",(0,r.jsx)(n.code,{children:"OnStateChanged"})]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"UsingSynchronousMode"})," \u2192 ",(0,r.jsx)(n.strong,{children:"Removed"})]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"Sync()"})," \u2192 ",(0,r.jsx)(n.code,{children:"Await()"})," for clarity and accuracy"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"-performance-improvements",children:"\ud83d\ude80 Performance Improvements"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\ud83e\udde0 Improved ",(0,r.jsx)(n.strong,{children:"dispatcher caching"})]}),"\n",(0,r.jsxs)(n.li,{children:["\u26a1 Enhanced ",(0,r.jsx)(n.strong,{children:"type cache"})," in ",(0,r.jsx)(n.code,{children:"StatePulseRegistry"})]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83e\uddec Replaced reflection with ",(0,r.jsx)(n.strong,{children:"dynamic method caching"})," for faster dispatching"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"-clean-code-improvements",children:"\ud83e\uddfc Clean Code Improvements"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\ud83e\uddf9 Refactored ",(0,r.jsx)(n.code,{children:"DispatchPrepper"})," for cleaner and lighter internal logic"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"-fixes-1",children:"\ud83d\udc1e Fixes"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\ud83d\udee0\ufe0f Resolved several ",(0,r.jsx)(n.strong,{children:"null reference warnings"})]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83e\uddfd Removed leftover ",(0,r.jsx)(n.strong,{children:"internal artifacts"})]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"v0941",children:"v0.9.41"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Fix: Added Anti-Service duplication to avoid double triggers."}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"v094",children:"v0.9.4"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Breaking Change, StateOf no longer accept lambda will throw exception you must define a Task directly... this was necessary due to Garbage Collector and tracking behavior."}),"\n",(0,r.jsx)(n.li,{children:"Deprecated UsingSynchronousMode() instead use Sync()."}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"v0921",children:"v0.9.21"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Implement the Blazor Package and removed dependencies to Blazor ComponentBase which is no longer required..."}),"\n",(0,r.jsx)(n.li,{children:"Any objects within .NET can now use IStatePulse and benefit from state management without extra implementations."}),"\n",(0,r.jsx)(n.li,{children:"Renamed IPulse to IStatePulse"}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"using IStatePulse.StateOf(()=>this, () => InvokeAsync(StateHasChanged));"})}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"v092-blazor-packages",children:"v0.9.2 (Blazor Packages)"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Deprecated now part of StatePulse regular since we have removed the dependencies to blazor component.\r\n... that was quick!"}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,l.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(a,{...e})}):a(e)}}}]); \ No newline at end of file diff --git a/doc/build/assets/js/94cf9043.dc8ec61a.js b/doc/build/assets/js/94cf9043.dc8ec61a.js new file mode 100644 index 0000000..eb04b1e --- /dev/null +++ b/doc/build/assets/js/94cf9043.dc8ec61a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[6683],{8453:(e,n,i)=>{i.d(n,{R:()=>t,x:()=>c});var s=i(6540);const r={},l=s.createContext(r);function t(e){const n=s.useContext(l);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:t(e.components),s.createElement(l.Provider,{value:n},e.children)}},8886:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>d,contentTitle:()=>c,default:()=>h,frontMatter:()=>t,metadata:()=>s,toc:()=>o});const s=JSON.parse('{"id":"Versions","title":"Updates","description":"v2.0.0","source":"@site/docs/0.Versions.md","sourceDirName":".","slug":"/versions","permalink":"/versions","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/0.Versions.md","tags":[],"version":"current","sidebarPosition":0,"frontMatter":{"slug":"versions","title":"Updates","sidebar_position":0},"sidebar":"tutorialSidebar","next":{"title":"Get Started","permalink":"/"}}');var r=i(4848),l=i(8453);const t={slug:"versions",title:"Updates",sidebar_position:0},c=void 0,d={},o=[{value:"v2.0.0",id:"v200",level:2},{value:"BREAKING CHANGES",id:"breaking-changes",level:3},{value:"New Features",id:"new-features",level:3},{value:"Security",id:"security",level:3},{value:"Fixes",id:"fixes",level:3},{value:"v1.1.0",id:"v110",level:2},{value:"Minor Change",id:"minor-change",level:3},{value:"v1.0.2",id:"v102",level:2},{value:"Fixes",id:"fixes-1",level:3},{value:"v1.0.1",id:"v101",level:2},{value:"Minor Change",id:"minor-change-1",level:3},{value:"v1.0.0",id:"v100",level:2},{value:"New Features",id:"new-features-1",level:3},{value:"\ud83d\udca5 Breaking Changes",id:"-breaking-changes",level:3},{value:"\ud83d\ude80 Performance Improvements",id:"-performance-improvements",level:3},{value:"\ud83e\uddfc Clean Code Improvements",id:"-clean-code-improvements",level:3},{value:"\ud83d\udc1e Fixes",id:"-fixes",level:3},{value:"v0.9.41",id:"v0941",level:2},{value:"v0.9.4",id:"v094",level:2},{value:"v0.9.21",id:"v0921",level:2},{value:"v0.9.2 (Blazor Packages)",id:"v092-blazor-packages",level:2}];function a(e){const n={br:"br",code:"code",h2:"h2",h3:"h3",li:"li",p:"p",strong:"strong",ul:"ul",...(0,l.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h2,{id:"v200",children:"v2.0.0"}),"\n",(0,r.jsx)(n.h3,{id:"breaking-changes",children:"BREAKING CHANGES"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Interface signatures have changed."}),(0,r.jsx)(n.br,{}),"\n","Core interface updates may break plugin\u2011based systems if the core updates while plugins do not.",(0,r.jsx)(n.br,{}),"\n","This is only safe when proper plugin isolation is respected."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Reducers now run before effects."}),(0,r.jsx)(n.br,{}),"\n","The default dispatch order has changed.",(0,r.jsx)(n.br,{}),"\n","Pipelines that rely on reducers running after effects must update their configuration to restore the previous behavior."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Middleware between individual effects has been removed."}),(0,r.jsx)(n.br,{}),"\n","Per\u2011effect middleware proved unreliable and is no longer supported.",(0,r.jsx)(n.br,{}),"\n","All effects now run as a batch, followed by a single AfterEffect phase.",(0,r.jsx)(n.br,{}),"\n","Middleware can still be awaited before the BeforeEffect phase and after the AfterEffect phase.\r\nMiddlewares for effects if not awaited they are still ganrantueed to be running sequentially BeforeEffect Parallel with Effects then AfterEffects."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Actions can never be singleton."}),(0,r.jsx)(n.br,{}),"\n","Action are essentially data contract and should remain at the scope level which in blazor server case is circuit bound."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Effects, Reducers, Middleware, EffectValidators no long transient"}),(0,r.jsx)(n.br,{}),"\n","Transient lifetime for those is unecessary as none of them should ever hold state of their own therefore they act like static method filled with logic alone... let's eliminate transient overhead and put scoped as default and singleton with the singleton interfaces."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Configuration Scan Assembly Type Changed"}),(0,r.jsx)(n.br,{}),"\n","The property ",(0,r.jsx)(n.code,{children:"ConfigureOptions.ScanAssemblies"})," is now taking a ",(0,r.jsx)(n.code,{children:"Assembly[]"})," instead of ",(0,r.jsx)(n.code,{children:"Type[]"}),"."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"IPulseGlobalTracker registration changed"}),(0,r.jsx)(n.br,{}),"\n","The IPulseGlobalTracker is now registered as Scoped instead of singleton... issues were occuring with some blazor server projects."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsxs)(n.strong,{children:["Removed ",(0,r.jsx)(n.code,{children:".AddStatePulse"})]}),(0,r.jsx)(n.br,{}),"\n","the extension method were removed from public access... now you use ",(0,r.jsx)(n.code,{children:".AddStatePulseService()"})," which will auto detect from action to effect to reducers to middlewares.\r\nReason: Better dev experience less confusing and annoying when having to register stuff manually instead of by scanning.\r\nAlternative: You can also add types into ",(0,r.jsx)(n.code,{children:".AddStatePulseServices(o=>{ o.AutoRegisterTypes = [typeof(AAA)];});"})," which will perform manual registration automatically without scanning assemblies."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Added to IDispatchMiddleware"}),"\r\n",(0,r.jsx)(n.code,{children:"OnDispatchFailure(Exception exception, object action)"})," is now available to middleware hit is receive on any dispatch failure..."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Removed Throw for Dispatch Failure"}),"\r\nRe-Throw only occurs when using Synchronous ",(0,r.jsx)(n.code,{children:"Await()"})," otherwise dispatch will swallow any uncaught exception thrown at it."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Reducers are no longer Tasks"}),"\r\nWith the full introduction of middlewares it is no longer justifiable to have reducers as Task... nothing should be in the reducers to the exception of generating a new state."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"ReducerExt is removed"}),"\r\nReducerExt is no longer available as it was used as helper for Task return."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsxs)(n.strong,{children:[(0,r.jsx)(n.code,{children:"IDispatcherPrepper Prepare(Func createInstance)"})," deprecated"]}),"\r\nUse Prepared(instance).DispatchAsync() instead;"]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"new-features",children:"New Features"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Enhanced Configuration Options"})," - New global configuration properties:","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"DispatchOrderBehavior"})," - Set default ordering (EffectsFirst/ReducersFirst)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"DispatchEffectExecutionBehavior"})," - Set default execution mode (YieldAndFire/FireAndForget)"]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Configurable Dispatch Ordering"})," - Choose between ",(0,r.jsx)(n.code,{children:"EffectsFirst"})," (default) or ",(0,r.jsx)(n.code,{children:"ReducersFirst"})," execution order globally or per-dispatch"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Configurable Dispatch Ordering"})," - The Middleware BeforeReducers will run before the AfterReducer as garantueed..."]}),"\n",(0,r.jsx)(n.li,{children:"The reducer will however run in parallel with BeforeReducing if settings is to not await for middlewares."}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"True Fire-and-Forget Execution Mode"})," - New ",(0,r.jsx)(n.code,{children:"DispatchEffectExecutionBehavior.FireAndForget"})," for true background execution without yielding and awaiting effects"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Per-Dispatch Execution Control"})," - Override global settings per dispatch with fluent API:","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:".EffectsFirst()"})," - Run effects before reducers"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:".ReducersFirst()"})," - Run reducers before effects"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:".SequentialEffects()"})," - Force effects to run in sequence"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:".ParallelEffects()"})," - Force effects to run in parallel"]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Invalid Configuration Detection"})," - New ",(0,r.jsx)(n.code,{children:"InvalidDispatchCombinationException"})," thrown at dispatch time for incompatible configuration combinations (Plan to generate compiler errors later)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Recursive Dispatch Support"})," - Fire-and-forget mode enables safe recursive dispatch patterns without deadlocks"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"PulseTrackingModel"})," - Clear option for the tracking model! Either Thread-Safe (",(0,r.jsx)(n.code,{children:"Default"}),") or Single Threaded Fast Application... WASM/Blazor Server."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"GlobalTrackerLifetime"})," - Define clearly lifetime scope for the Global Tracker singleton or scoped. ",(0,r.jsx)(n.code,{children:"BlazorServer"}),", ",(0,r.jsx)(n.code,{children:"WASM"}),", ",(0,r.jsx)(n.code,{children:"Scoped"})," (Default) or ",(0,r.jsx)(n.code,{children:"Singleton"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"IStateFeatureSingleton"})," - Define a singleton state across your app... not useful in WASM but very useful in Blazor Server... where one can share the state across client each client run their own action but the state update spread across all circuits."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"IReducer"}),", ",(0,r.jsx)(n.code,{children:"IEffect"}),", ",(0,r.jsx)(n.code,{children:"IEffectValidation"}),", ",(0,r.jsx)(n.code,{children:"IEffectMiddleware"}),", ",(0,r.jsx)(n.code,{children:"IReducerMiddleware"})," - Are ALWAYS transient from now on."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"StateVersioning"})," long global ticker used to calculate version of a state... this will help prevent further race conditions related to multi-threading (blazor server singleton)."]}),"\n",(0,r.jsxs)(n.li,{children:["State update will automatically discard stale states. you can also acces the information using ",(0,r.jsx)(n.code,{children:"IStateAccessor"})]}),"\n",(0,r.jsxs)(n.li,{children:["Roslyn Analyzer will now trigger error ",(0,r.jsx)(n.code,{children:".Prepare(entity)"})," if constructor object does not match the underlying object's constructor type and it supports overload."]}),"\n",(0,r.jsxs)(n.li,{children:["Roslyn Analyzer will now trigger error ",(0,r.jsx)(n.code,{children:".Prepare().With(p => p.PROP, data)"})," when PROP is ",(0,r.jsx)(n.code,{children:"init;"})," or ",(0,r.jsx)(n.code,{children:"get;"})," only... this will eleminate runtime issues."]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"security",children:"Security"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Roslyn will now enforce ",(0,r.jsx)(n.code,{children:"_statePulse.StateOf(() => this, OnUpdate);"})," on the two arguments this will avoid runtime errors and potential memory leaks."]}),"\n",(0,r.jsx)(n.li,{children:"Fixed All Configure Internal..."}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"fixes",children:"Fixes"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Fixed Various Warnings"}),"\n",(0,r.jsx)(n.li,{children:"Fixed All Configure Internal..."}),"\n",(0,r.jsx)(n.li,{children:"Fixed Middleware are now added via Scanned Assemblies."}),"\n",(0,r.jsxs)(n.li,{children:["Fixed some issues where ",(0,r.jsx)(n.code,{children:"Await()"})," was not respected."]}),"\n",(0,r.jsx)(n.li,{children:"Fixed major issue where all race condition elements where cancelled leading to full chain cancellation including the last action."}),"\n",(0,r.jsx)(n.li,{children:"Fixed inconsistence with race conditions."}),"\n",(0,r.jsxs)(n.li,{children:["Fixed\t",(0,r.jsx)(n.code,{children:"StateOf()"})," throwing inability to cast to ",(0,r.jsx)(n.code,{children:"IStateAccessor"}),"."]}),"\n",(0,r.jsx)(n.li,{children:"Fixed AddStatePulseServices() configuration not optional."}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"v110",children:"v1.1.0"}),"\n",(0,r.jsx)(n.h3,{id:"minor-change",children:"Minor Change"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Upgraded to .NET 10"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"v102",children:"v1.0.2"}),"\n",(0,r.jsx)(n.h3,{id:"fixes-1",children:"Fixes"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Added StatePulse.Net.Abstractions package reference instead of project reference to fix IL trimming issues."}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"v101",children:"v1.0.1"}),"\n",(0,r.jsx)(n.h3,{id:"minor-change-1",children:"Minor Change"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Splited Abstractions into StatePulse.Net.Abstractions (Will not break anything Namespace is the same)"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"v100",children:"v1.0.0"}),"\n",(0,r.jsx)(n.h3,{id:"new-features-1",children:"New Features"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Action Effect Validator"}),": Allows effects to run conditionally by validating them before execution."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Middleware Support"}),":","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"IEffectMiddleware"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"IReducerMiddleware"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"IDispatchMiddleware"})}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Behavior Configuration"}),": You can configure execution behaviors via:","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"DispatchEffectBehavior"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"MiddlewareEffectBehavior"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"MiddlewareTaskBehavior"})}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Strict Manual Registration"}),": Manual service registration ",(0,r.jsx)(n.strong,{children:"must use"})," extension methods:","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"AddStatePulse()"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"AddStatePulseEffect<>()"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"AddStatePulseAction<>()"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"AddStatePulseReducer<>()"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"AddStatePulseStateFeature<>()"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"AddStatePulseEffectValidator<>()"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"-breaking-changes",children:"\ud83d\udca5 Breaking Changes"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Removed ",(0,r.jsx)(n.strong,{children:"Action Validator"})," \u2013 validating action data is not the responsibility of the state management layer."]}),"\n",(0,r.jsxs)(n.li,{children:["Renamed:","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"IStateAccessor<>.StateChanged"})," \u2192 ",(0,r.jsx)(n.code,{children:"OnStateChanged"})]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"UsingSynchronousMode"})," \u2192 ",(0,r.jsx)(n.strong,{children:"Removed"})]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"Sync()"})," \u2192 ",(0,r.jsx)(n.code,{children:"Await()"})," for clarity and accuracy"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"-performance-improvements",children:"\ud83d\ude80 Performance Improvements"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Improved ",(0,r.jsx)(n.strong,{children:"dispatcher caching"})]}),"\n",(0,r.jsxs)(n.li,{children:["Enhanced ",(0,r.jsx)(n.strong,{children:"type cache"})," in ",(0,r.jsx)(n.code,{children:"StatePulseRegistry"})]}),"\n",(0,r.jsxs)(n.li,{children:["Replaced reflection with ",(0,r.jsx)(n.strong,{children:"dynamic method caching"})," for faster dispatching"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"-clean-code-improvements",children:"\ud83e\uddfc Clean Code Improvements"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Refactored ",(0,r.jsx)(n.code,{children:"DispatchPrepper"})," for cleaner and lighter internal logic"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"-fixes",children:"\ud83d\udc1e Fixes"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Resolved several ",(0,r.jsx)(n.strong,{children:"null reference warnings"})]}),"\n",(0,r.jsxs)(n.li,{children:["Removed leftover ",(0,r.jsx)(n.strong,{children:"internal artifacts"})]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"v0941",children:"v0.9.41"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Fix: Added Anti-Service duplication to avoid double triggers."}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"v094",children:"v0.9.4"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Breaking Change, StateOf no longer accept lambda will throw exception you must define a Task directly... this was necessary due to Garbage Collector and tracking behavior."}),"\n",(0,r.jsx)(n.li,{children:"Deprecated UsingSynchronousMode() instead use Sync()."}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"v0921",children:"v0.9.21"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Implement the Blazor Package and removed dependencies to Blazor ComponentBase which is no longer required..."}),"\n",(0,r.jsx)(n.li,{children:"Any objects within .NET can now use IStatePulse and benefit from state management without extra implementations."}),"\n",(0,r.jsx)(n.li,{children:"Renamed IPulse to IStatePulse"}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"using IStatePulse.StateOf(()=>this, () => InvokeAsync(StateHasChanged));"})}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"v092-blazor-packages",children:"v0.9.2 (Blazor Packages)"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Deprecated now part of StatePulse regular since we have removed the dependencies to blazor component.\r\n... that was quick!"}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,l.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(a,{...e})}):a(e)}}}]); \ No newline at end of file diff --git a/doc/build/assets/js/c5fd082d.0836ff42.js b/doc/build/assets/js/c5fd082d.0836ff42.js deleted file mode 100644 index 0274f64..0000000 --- a/doc/build/assets/js/c5fd082d.0836ff42.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[6403],{4093:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>o,contentTitle:()=>i,default:()=>d,frontMatter:()=>l,metadata:()=>n,toc:()=>c});const n=JSON.parse('{"id":"Setup Blazor Project","title":"Setup Blazor Project","description":"\ud83d\udce6 Installation & Setup","source":"@site/docs/1. Setup Blazor Project.md","sourceDirName":".","slug":"/setup-blazor-project","permalink":"/setup-blazor-project","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/1. Setup Blazor Project.md","tags":[{"inline":true,"label":"blazor","permalink":"/tags/blazor"},{"inline":true,"label":"setup","permalink":"/tags/setup"},{"inline":true,"label":"installation","permalink":"/tags/installation"},{"inline":true,"label":"statepulse","permalink":"/tags/statepulse"},{"inline":true,"label":"dependency-injection","permalink":"/tags/dependency-injection"},{"inline":true,"label":"csharp","permalink":"/tags/csharp"},{"inline":true,"label":".net","permalink":"/tags/net"}],"version":"current","sidebarPosition":2,"frontMatter":{"slug":"setup-blazor-project","title":"Setup Blazor Project","tags":["blazor","setup","installation","statepulse","dependency-injection","csharp",".net"],"sidebar_position":2},"sidebar":"tutorialSidebar","previous":{"title":"Get Started","permalink":"/"},"next":{"title":"The Actions","permalink":"/gs-the-action"}}');var r=s(4848),a=s(8453);const l={slug:"setup-blazor-project",title:"Setup Blazor Project",tags:["blazor","setup","installation","statepulse","dependency-injection","csharp",".net"],sidebar_position:2},i=void 0,o={},c=[{value:"\ud83d\udce6 Installation & Setup",id:"-installation--setup",level:2},{value:"Add Services",id:"add-services",level:2},{value:"Scan Assmblies",id:"scan-assmblies",level:3},{value:"Manual Registering",id:"manual-registering",level:3}];function u(e){const t={code:"code",em:"em",h2:"h2",h3:"h3",p:"p",pre:"pre",strong:"strong",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h2,{id:"-installation--setup",children:"\ud83d\udce6 Installation & Setup"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-bash",children:"Install-Package StatePulse.Net\r\n\r\ndotnet add package StatePulse.Net\r\n\n"})}),"\n",(0,r.jsxs)(t.p,{children:["Add to ",(0,r.jsx)(t.code,{children:"Program.cs"}),":"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-cs",children:"builder.Services.AddStatePulseServices(o => {});\n"})}),"\n",(0,r.jsx)(t.p,{children:"Create StatePulse common folder structure."}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{children:"/Pulses/\r\n/Pulses/Counter <- Feature\r\n/Pulses/Counter/Actions\r\n/Pulses/Counter/Effects\r\n/Pulses/Counter/Effects/Validators\r\n/Pulses/Counter/Reducers\r\n/Pulses/Counter/Stores\n"})}),"\n",(0,r.jsx)(t.p,{children:"This structure is complete and very common pattern."}),"\n",(0,r.jsx)(t.h2,{id:"add-services",children:"Add Services"}),"\n",(0,r.jsx)(t.p,{children:"There are 2 ways to add services for StatePulse."}),"\n",(0,r.jsx)(t.h3,{id:"scan-assmblies",children:"Scan Assmblies"}),"\n",(0,r.jsx)(t.p,{children:"The easiest way is to scan whatever assembly you have pulses in."}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-cs",metastring:'title="program.cs"',children:"builder.Services.AddStatePulseServices(o =>\r\n{\r\n o.ScanAssemblies = new Type[] { typeof(Program) };\r\n});\n"})}),"\n",(0,r.jsx)(t.h3,{id:"manual-registering",children:"Manual Registering"}),"\n",(0,r.jsxs)(t.p,{children:["StatePulse provide extension methods to add type of services and you ",(0,r.jsx)(t.strong,{children:"MUST"})," use them otherwise you face issues."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-cs",metastring:'title="program.cs"',children:"builder.Services.AddStatePulseAction();\r\nbuilder.Services.AddStatePulseEffect();\r\nbuilder.Services.AddStatePulseEffectValidator();\r\nbuilder.Services.AddStatePulseReducer();\r\nbuilder.Services.AddStatePulseStateFeature();\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.em,{children:"Note: you must manually register all services during unit test... the assembly scan doesn't get along well with unit testing."})})]})}function d(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(u,{...e})}):u(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>l,x:()=>i});var n=s(6540);const r={},a=n.createContext(r);function l(e){const t=n.useContext(a);return n.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:l(e.components),n.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/doc/build/assets/js/c5fd082d.a9c7cd7d.js b/doc/build/assets/js/c5fd082d.a9c7cd7d.js new file mode 100644 index 0000000..c11cf1a --- /dev/null +++ b/doc/build/assets/js/c5fd082d.a9c7cd7d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[6403],{4093:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>o,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>n,toc:()=>c});const n=JSON.parse('{"id":"Setup Blazor Project","title":"Setup Blazor Project","description":"\ud83d\udce6 Installation & Setup","source":"@site/docs/1. Setup Blazor Project.md","sourceDirName":".","slug":"/setup-blazor-project","permalink":"/setup-blazor-project","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/1. Setup Blazor Project.md","tags":[{"inline":true,"label":"blazor","permalink":"/tags/blazor"},{"inline":true,"label":"setup","permalink":"/tags/setup"},{"inline":true,"label":"installation","permalink":"/tags/installation"},{"inline":true,"label":"statepulse","permalink":"/tags/statepulse"},{"inline":true,"label":"dependency-injection","permalink":"/tags/dependency-injection"},{"inline":true,"label":"csharp","permalink":"/tags/csharp"},{"inline":true,"label":".net","permalink":"/tags/net"}],"version":"current","sidebarPosition":2,"frontMatter":{"slug":"setup-blazor-project","title":"Setup Blazor Project","tags":["blazor","setup","installation","statepulse","dependency-injection","csharp",".net"],"sidebar_position":2},"sidebar":"tutorialSidebar","previous":{"title":"Get Started","permalink":"/"},"next":{"title":"The Actions","permalink":"/gs-the-action"}}');var r=s(4848),l=s(8453);const a={slug:"setup-blazor-project",title:"Setup Blazor Project",tags:["blazor","setup","installation","statepulse","dependency-injection","csharp",".net"],sidebar_position:2},i=void 0,o={},c=[{value:"\ud83d\udce6 Installation & Setup",id:"-installation--setup",level:2},{value:"Add Services",id:"add-services",level:2}];function d(e){const t={br:"br",code:"code",em:"em",h2:"h2",p:"p",pre:"pre",strong:"strong",...(0,l.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h2,{id:"-installation--setup",children:"\ud83d\udce6 Installation & Setup"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-bash",children:"Install-Package StatePulse.Net\r\n\r\ndotnet add package StatePulse.Net\r\n\n"})}),"\n",(0,r.jsxs)(t.p,{children:["Add to ",(0,r.jsx)(t.code,{children:"Program.cs"}),":"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-cs",children:"builder.Services.AddStatePulseServices();\n"})}),"\n",(0,r.jsx)(t.p,{children:"Create StatePulse common folder structure."}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{children:"/Pulses/\r\n/Pulses/Counter <- Feature\r\n/Pulses/Counter/Actions\r\n/Pulses/Counter/Effects\r\n/Pulses/Counter/Effects/Validators\r\n/Pulses/Counter/Reducers\r\n/Pulses/Counter/Stores\n"})}),"\n",(0,r.jsx)(t.p,{children:"This structure is complete and very common pattern."}),"\n",(0,r.jsx)(t.h2,{id:"add-services",children:"Add Services"}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Method 1"}),(0,r.jsx)(t.br,{}),"\n","The most deterministic and explicit registration approach. This method avoids \u201cmagic\u201d and one\u2011liners by requiring you to manually add all Reducers, Effects, Middlewares, Validators, and Actions. It provides full clarity and control over what the system loads."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-csharp",children:" ServiceCollection.AddStatePulseServices(o =>\r\n {\r\n o.AutoRegisterTypes = [\r\n typeof(WHATEVER_STATEPULSE_TYPE),\r\n ];\r\n });\n"})}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Method 2"}),(0,r.jsx)(t.br,{}),"\n","This is also very explicit since v2+ we have a single entry ",(0,r.jsx)(t.code,{children:"AddStatePulseService"})," for all statepulse types (Reducers, Effects, Middlewares, Validators, and Actions)."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-csharp",children:" ServiceCollection.AddStatePulseServices(); // Register Base Services\r\n ServiceCollection.AddStatePulseService();\n"})}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Method 3"}),"\r\nThe assembly-scan approach. Convenient but not recommended for most scenarios. While useful for rapid setup, it can introduce problems as system grows."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-csharp",children:" ServiceCollection.AddStatePulseServices(o => {\r\n o.ScanAssemblies = [typeof(TestBase).Assembly];\r\n });\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.em,{children:"Note: The assembly scan doesn't get along well with unit testing."})})]})}function u(e={}){const{wrapper:t}={...(0,l.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>a,x:()=>i});var n=s(6540);const r={},l=n.createContext(r);function a(e){const t=n.useContext(l);return n.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),n.createElement(l.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/doc/build/assets/js/ce33d687.1b2a2bfa.js b/doc/build/assets/js/ce33d687.1b2a2bfa.js new file mode 100644 index 0000000..41eb2cf --- /dev/null +++ b/doc/build/assets/js/ce33d687.1b2a2bfa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[6996],{4978:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>c,default:()=>d,frontMatter:()=>a,metadata:()=>s,toc:()=>o});const s=JSON.parse('{"id":"The Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","source":"@site/docs/6.The Dispatcher.md","sourceDirName":".","slug":"/gs-the-dispatcher","permalink":"/gs-the-dispatcher","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/6.The Dispatcher.md","tags":[{"inline":true,"label":"blazor","permalink":"/tags/blazor"},{"inline":true,"label":"state-management","permalink":"/tags/state-management"},{"inline":true,"label":"dispatcher","permalink":"/tags/dispatcher"},{"inline":true,"label":"actions","permalink":"/tags/actions"},{"inline":true,"label":"safedispatch","permalink":"/tags/safedispatch"},{"inline":true,"label":"redux","permalink":"/tags/redux"},{"inline":true,"label":"statepulse","permalink":"/tags/statepulse"},{"inline":true,"label":"async","permalink":"/tags/async"},{"inline":true,"label":"await","permalink":"/tags/await"},{"inline":true,"label":"performance","permalink":"/tags/performance"}],"version":"current","sidebarPosition":6,"frontMatter":{"slug":"gs-the-dispatcher","title":"The Dispatcher","tags":["blazor","state-management","dispatcher","actions","safedispatch","redux","statepulse","async","await","performance"],"sidebar_position":6},"sidebar":"tutorialSidebar","previous":{"title":"The Reducers","permalink":"/gs-the-reducer"},"next":{"title":"The Middlewares","permalink":"/gs-the-middlewares"}}');var i=t(4848),r=t(8453);const a={slug:"gs-the-dispatcher",title:"The Dispatcher",tags:["blazor","state-management","dispatcher","actions","safedispatch","redux","statepulse","async","await","performance"],sidebar_position:6},c=void 0,l={},o=[{value:"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse",id:"-dispatcher--executing-actions-in-statepulse",level:2},{value:"\ud83e\udded Dispatch Flow",id:"-dispatch-flow",level:3},{value:"\u26a0\ufe0f About Constructors",id:"\ufe0f-about-constructors",level:3},{value:"Inject into Component",id:"inject-into-component",level:3},{value:"\ud83d\udee0\ufe0f Pre-initializing Actions (Optional)",id:"\ufe0f-pre-initializing-actions-optional",level:3},{value:"\ud83e\uddf5 Safe Execution On-the-Fly",id:"-safe-execution-on-the-fly",level:3},{value:"\u26a0\ufe0f Use Safe Actions Selectively",id:"\ufe0f-use-safe-actions-selectively",level:3},{value:"\u23f3 Await Pipeline",id:"-await-pipeline",level:3},{value:"Why Awaiting Matters in .NET / StatePulse",id:"why-awaiting-matters-in-net--statepulse",level:4}];function h(e){const n={blockquote:"blockquote",br:"br",code:"code",h2:"h2",h3:"h3",h4:"h4",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h2,{id:"-dispatcher--executing-actions-in-statepulse",children:"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.strong,{children:"dispatcher"})," in StatePulse is responsible for preparing and executing actions in a clean and fluent way.",(0,i.jsx)(n.br,{}),"\n","Unlike some traditional systems, the dispatch pattern here is more structured:"]}),"\n",(0,i.jsx)(n.h3,{id:"-dispatch-flow",children:"\ud83e\udded Dispatch Flow"}),"\n",(0,i.jsx)(n.p,{children:"The standard flow for dispatching an action is:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"Prepare()"})," \u2013 creates the action instance"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:".With(...)"})," \u2013 sets properties on the action"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:".DispatchAsync()"})," \u2013 executes the action"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"This approach promotes immutability, clear intent, and safe updates."}),"\n",(0,i.jsx)(n.h3,{id:"\ufe0f-about-constructors",children:"\u26a0\ufe0f About Constructors"}),"\n",(0,i.jsxs)(n.p,{children:["You ",(0,i.jsx)(n.strong,{children:"can"})," pass constructor arguments in ",(0,i.jsx)(n.code,{children:"Prepare()"}),", like this:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-csharp",children:"Dispatcher.Prepare(arg1, arg2);\n"})}),"\n",(0,i.jsxs)(n.p,{children:["But this is ",(0,i.jsx)(n.strong,{children:"strongly discouraged"}),", and ideally avoided completely."]}),"\n",(0,i.jsxs)(n.p,{children:["\u2757 ",(0,i.jsx)(n.strong,{children:"Why avoid it?"}),(0,i.jsx)(n.br,{}),"\n","If the constructor changes later (e.g., parameter added, removed, or reordered),",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.strong,{children:"the compiler won\u2019t warn you"}),", and your dispatch logic may ",(0,i.jsx)(n.strong,{children:"break silently at runtime"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"This can lead to:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Incorrect action initialization"}),"\n",(0,i.jsx)(n.li,{children:"Subtle bugs"}),"\n",(0,i.jsx)(n.li,{children:"Hard-to-trace state issues"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"inject-into-component",children:"Inject into Component"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-csharp",metastring:'title="Counter.razor.cs"',children:"public partial class Counter : ComponentBase\r\n{\r\n [Inject] private IDispatcher Dispatcher { get; set; }\r\n private async Task Increment()\r\n {\r\n await Dispatcher.Prepare()\r\n .With(p => p.Delay, 1)\r\n .DispatchAsync();\r\n }\r\n}\n"})}),"\n",(0,i.jsx)(n.h3,{id:"\ufe0f-pre-initializing-actions-optional",children:"\ud83d\udee0\ufe0f Pre-initializing Actions (Optional)"}),"\n",(0,i.jsxs)(n.p,{children:["You can also ",(0,i.jsx)(n.strong,{children:"pre-initialize an action"})," manually \u2014 similar to how it's done in conventional state management systems."]}),"\n",(0,i.jsx)(n.p,{children:"This approach is useful when:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["You're using ",(0,i.jsx)(n.strong,{children:"constructor-based action records"})]}),"\n",(0,i.jsxs)(n.li,{children:["You're ",(0,i.jsx)(n.strong,{children:"dispatching actions in a loop"}),", where minimizing per-dispatch overhead matters"]}),"\n"]}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsxs)(n.p,{children:["\u26a0\ufe0f ",(0,i.jsxs)(n.strong,{children:["While the reflection overhead of ",(0,i.jsx)(n.code,{children:"Prepare()"})," is small, it does exist."]})," In performance-critical scenarios (like loops or tight UI updates), ",(0,i.jsx)(n.strong,{children:"pre-initializing the action"})," can offer a slight efficiency gain."]}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-csharp",metastring:'title="Counter.razor.cs"',children:"public partial class Counter : ComponentBase\r\n{\r\n [Inject] private IDispatcher Dispatcher { get; set; }\r\n private async Task Increment()\r\n {\r\n await Dispatcher.Prepare(()=> new IncrementCounterAction(){\r\n Delay = 1\r\n }).DispatchAsync();\r\n }\r\n}\n"})}),"\n",(0,i.jsx)(n.h3,{id:"-safe-execution-on-the-fly",children:"\ud83e\uddf5 Safe Execution On-the-Fly"}),"\n",(0,i.jsxs)(n.p,{children:["Every action in StatePulse can be executed ",(0,i.jsx)(n.strong,{children:"on-the-fly as a safe action"}),",",(0,i.jsx)(n.br,{}),"\n","meaning any ",(0,i.jsx)(n.strong,{children:"subsequent execution cancels the previous one"}),".",(0,i.jsx)(n.br,{}),"\n","This significantly reduces the risk of race conditions in async workflows."]}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsx)(n.p,{children:"\u2705 This is especially helpful for API calls, debounced interactions, or long-running processes."}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"\ufe0f-use-safe-actions-selectively",children:"\u26a0\ufe0f Use Safe Actions Selectively"}),"\n",(0,i.jsxs)(n.p,{children:["While powerful, ",(0,i.jsx)(n.strong,{children:"safe actions come with a small overhead footprint"}),".",(0,i.jsx)(n.br,{}),"\n","You should ",(0,i.jsx)(n.strong,{children:"avoid using them"})," for:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Reducer-only actions (e.g., local counter updates)"}),"\n",(0,i.jsx)(n.li,{children:"Instantaneous operations where no async delay exists"}),"\n"]}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsxs)(n.p,{children:["\u26a0\ufe0f ",(0,i.jsxs)(n.strong,{children:["Overusing ",(0,i.jsx)(n.code,{children:"ISafeAction"})," can lead to performance degradation in large or complex UIs."]}),(0,i.jsx)(n.br,{}),"\n","While it's unlikely you'll encounter direct issues in most apps,",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.strong,{children:"why not save performance when it's that easy to do?"})]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["Use ",(0,i.jsx)(n.code,{children:"ISafeAction"})," only when the benefits \u2014 like cancellation, deduplication, or race condition protection \u2014 are necessary."]}),"\n",(0,i.jsx)(n.h3,{id:"-await-pipeline",children:"\u23f3 Await Pipeline"}),"\n",(0,i.jsxs)(n.p,{children:["You can ",(0,i.jsx)(n.strong,{children:"await the dispatch pipeline"}),", which means your code will ",(0,i.jsx)(n.strong,{children:"block execution until the entire pipeline completes"}),":"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["All ",(0,i.jsx)(n.strong,{children:"effects"})," (including cascading effects) finish"]}),"\n",(0,i.jsxs)(n.li,{children:["All ",(0,i.jsx)(n.strong,{children:"reducers"})," have executed"]}),"\n",(0,i.jsx)(n.li,{children:"The full state update cycle is done"}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["This feature is ",(0,i.jsx)(n.strong,{children:"not common in traditional Redux-style state management"}),",",(0,i.jsx)(n.br,{}),"\n","which often relies on external tools (like Redux DevTools) to observe state changes asynchronously."]}),"\n",(0,i.jsx)(n.h4,{id:"why-awaiting-matters-in-net--statepulse",children:"Why Awaiting Matters in .NET / StatePulse"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["The .NET environment encourages ",(0,i.jsx)(n.strong,{children:"step-by-step debugging"}),", which is often the most effective way to diagnose issues."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:".Await()"})," enables this by making the dispatch synchronous from the caller\u2019s perspective."]}),"\n",(0,i.jsxs)(n.li,{children:["This is why it\u2019s ",(0,i.jsx)(n.strong,{children:"important to always await dispatches"})," \u2014 it ensures predictable, debuggable code flow."]}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-csharp",metastring:'title="Counter.razor.cs"',children:"public partial class Counter : ComponentBase\r\n{\r\n [Inject] private IDispatcher Dispatcher { get; set; }\r\n private async Task Increment()\r\n {\r\n await Dispatcher.Prepare()\r\n .With(p => p.Delay, 1)\r\n .Await() // <- Block Execution until all tasks are done.\r\n .DispatchAsync();\r\n }\r\n}\n"})})]})}function d(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>c});var s=t(6540);const i={},r=s.createContext(i);function a(e){const n=s.useContext(r);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/doc/build/assets/js/e4b9287f.17e09519.js b/doc/build/assets/js/e4b9287f.17e09519.js deleted file mode 100644 index c749f5e..0000000 --- a/doc/build/assets/js/e4b9287f.17e09519.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[7778],{4661:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>s,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"Getting Started","title":"Get Started","description":"License: MIT","source":"@site/docs/Getting Started.md","sourceDirName":".","slug":"/","permalink":"/","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/Getting Started.md","tags":[],"version":"current","sidebarPosition":1,"frontMatter":{"slug":"/","title":"Get Started","sidebar_position":1},"sidebar":"tutorialSidebar","previous":{"title":"Updates","permalink":"/versions"},"next":{"title":"Setup Blazor Project","permalink":"/setup-blazor-project"}}');var r=t(4848),a=t(8453);const s={slug:"/",title:"Get Started",sidebar_position:1},o="StatePulse.NET",l={},c=[{value:"Official Documentation",id:"official-documentation",level:3},{value:"\u2728 Features",id:"-features",level:2},{value:"\ud83d\ude80 State Management with Zero Boilerplate and Zero Compromises",id:"-state-management-with-zero-boilerplate-and-zero-compromises",level:3},{value:"\ud83d\udce6 Installation & Setup",id:"-installation--setup",level:2},{value:"\ud83e\udded How It Works",id:"-how-it-works",level:2},{value:"Define Actions:",id:"define-actions",level:3},{value:"Define Actions Validator (Optional):",id:"define-actions-validator-optional",level:3},{value:"Define Effect:",id:"define-effect",level:3},{value:"Define Reducer:",id:"define-reducer",level:3},{value:"Define StateFeature:",id:"define-statefeature",level:3},{value:"Trigger Dispatch:",id:"trigger-dispatch",level:3},{value:"Important Notes",id:"important-notes",level:3},{value:"Access State:",id:"access-state",level:3},{value:"Blazor Example Usage",id:"blazor-example-usage",level:3}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.a,{href:"https://opensource.org/licenses/MIT",children:(0,r.jsx)(n.img,{src:"https://img.shields.io/badge/License-MIT-brightgreen.svg",alt:"License: MIT"})}),"\r\n",(0,r.jsx)(n.a,{href:"https://www.nuget.org/packages/StatePulse.NET",children:(0,r.jsx)(n.img,{src:"https://img.shields.io/nuget/v/StatePulse.Net",alt:"NuGet Version"})}),"\r\n",(0,r.jsx)(n.a,{href:"https://www.nuget.org/packages/StatePulse.NET",children:(0,r.jsx)(n.img,{src:"https://img.shields.io/nuget/dt/StatePulse.NET?label=Downloads",alt:""})})]}),"\n",(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"statepulsenet",children:"StatePulse.NET"})}),"\n",(0,r.jsx)(n.h3,{id:"official-documentation",children:(0,r.jsx)(n.a,{href:"https://statepulse.net/",children:"Official Documentation"})}),"\n",(0,r.jsx)(n.p,{children:"StatePulse.NET is a precision-tuned state and action management system that balances high-performance fire-and-forget operations with optional, internally controlled execution order when explicitly required.\r\nIt enables anti-duplication chaining for critical flows, preventing race conditions and ensuring consistent outcomes even under rapid user input or concurrent triggers.\r\nIts internal tracking infrastructure provides near-zero overhead cancellation and dispatch control, drastically reducing inconsistency.\r\nAt the same time, it preserves the flexibility of traditional untracked state management, letting developers selectively enforce order and reliability without compromising overall responsiveness or introducing global locks."}),"\n",(0,r.jsx)(n.h2,{id:"-features",children:"\u2728 Features"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\u26a1 ",(0,r.jsx)(n.strong,{children:"Fast Fire-and-Forget"})," \u2014 Executes actions immediately even tracked action are fire-and-forget."]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83d\udee1 ",(0,r.jsx)(n.strong,{children:"Anti-Duplicate Dispatching"})," \u2014 Prevents redundant or overlapping actions that can cause race condition state inconsistency."]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83d\udd0d ",(0,r.jsx)(n.strong,{children:"Effect Validator System"})," \u2014 Supports multiple effect validators for modular and reusable rule enforcement."]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83e\uddea ",(0,r.jsx)(n.strong,{children:"Synchronous Debug Mode"})," \u2014 Optional lockstep mode for testing, diagnostics, and ",(0,r.jsx)(n.code,{children:"Task.WhenAll"})," pipelines."]}),"\n",(0,r.jsxs)(n.li,{children:["\ud83e\uddf5 ",(0,r.jsx)(n.strong,{children:"DispatchTracker"})," \u2014 High-performance cancellation and deduplication logic via optimized concurrent tracking."]}),"\n"]}),"\n",(0,r.jsxs)(n.h3,{id:"-state-management-with-zero-boilerplate-and-zero-compromises",children:["\ud83d\ude80 ",(0,r.jsx)(n.strong,{children:"State Management with Zero Boilerplate and Zero Compromises"})]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Lazy State Access Model:"})," Inject ",(0,r.jsx)(n.code,{children:"IStatePulse"})," directly into your Blazor component and call ",(0,r.jsx)(n.code,{children:"StateOf(()=>this, TaskMethod)"})," to get scoped state access."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Component-Scoped Event Listening:"})," Automatically registers event listeners only for that component, ensuring ",(0,r.jsx)(n.code,{children:"StateHasChanged()"})," is called exclusively on components subscribed to state changes."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"No Base Classes or Global Event Listeners:"})," Avoids global re-renders and boilerplate base class inheritance, giving you fine-grained control over component rendering and event subscription without forcing you into base classes."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Automatic Listener Disposal:"})," Event listeners are automatically tracked and disposed with the component lifecycle, preventing memory leaks and dangling references."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsxs)(n.strong,{children:["Transient ",(0,r.jsx)(n.code,{children:"IStatePulse"})," Service:"]})," Each component gets its own ",(0,r.jsx)(n.code,{children:"IStatePulse"})," instance, isolating event subscriptions and making state updates scoped and efficient."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"-installation--setup",children:"\ud83d\udce6 Installation & Setup"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"Install-Package StatePulse.Net\r\n\r\ndotnet add package StatePulse.Net\r\n\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"services.AddStatePulseServices(o =>\r\n {\r\n o.ScanAssemblies = new Type[] { typeof(Program) };\r\n });\n"})}),"\n",(0,r.jsx)(n.h2,{id:"-how-it-works",children:"\ud83e\udded How It Works"}),"\n",(0,r.jsxs)(n.h3,{id:"define-actions",children:[(0,r.jsx)(n.strong,{children:"Define Actions"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"\r\n// IAction { }\r\n// ISafeAction { } // Cannot be dispatched unsafely\r\n\r\npublic record ProfileCardDefineAction : IAction\r\n{\r\n public string? TestData { get; set; }\r\n}\r\n\n"})}),"\n",(0,r.jsxs)(n.h3,{id:"define-actions-validator-optional",children:[(0,r.jsx)(n.strong,{children:"Define Actions Validator"})," (Optional):"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:'/*\r\nYou are not required to create have an action validator but it is very useful when you have business logic that conditionally only contionally fires.\r\nWhen validation fails it ignores the dispatch and move on.\r\n*/\r\ninternal class ProfileCardDefineActionValidator : IActionValidator\r\n{\r\n public void Validate(ProfileCardDefineAction action, ref ValidationResult result)\r\n {\r\n if (action.TestData == "Error")\r\n result.AddError("ErrorName", "Name Cannot be Error");\r\n }\r\n}\n'})}),"\n",(0,r.jsxs)(n.h3,{id:"define-effect",children:[(0,r.jsx)(n.strong,{children:"Define Effect"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"\r\ninternal class ProfileCardDefineEffect : IEffect\r\n{\r\n\r\n public ProfileCardDefineEffect()\r\n {\r\n }\r\n public async Task EffectAsync(ProfileCardDefineAction action, IDispatcher dispatcher)\r\n {\r\n var random = new Random();\r\n int value = random.Next(100, 1001); // Upper bound is exclusive, so use 1001\r\n await Task.Delay(value);\r\n var myProfile = new UserResponse();\r\n await dispatcher.Prepare(() => new ProfileCardDefineResultAction(action.TestData ?? myProfile.Name, myProfile.Picture, myProfile.Id))\r\n .DispatchAsync();\r\n }\r\n\r\n}\r\n\r\n\n"})}),"\n",(0,r.jsxs)(n.h3,{id:"define-reducer",children:[(0,r.jsx)(n.strong,{children:"Define Reducer"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"internal class ProfileCardDefineResultReducer : IReducer\r\n{\r\n public Task ReduceAsync(ProfileCardState state, ProfileCardDefineResultAction action)\r\n => Task.FromResult(state with\r\n {\r\n LastUpdate = DateTime.UtcNow,\r\n ProfileId = action.Id,\r\n ProfileName = action.Name,\r\n ProfilePicture = action.Picture\r\n });\r\n}\n"})}),"\n",(0,r.jsxs)(n.h3,{id:"define-statefeature",children:[(0,r.jsx)(n.strong,{children:"Define StateFeature"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"public record ProfileCardState : IStateFeature\r\n{\r\n public string? ProfileName { get; set; }\r\n public string? ProfilePicture { get; set; }\r\n public string? ProfileId { get; set; }\r\n public DateTime LastUpdate { get; set; } = DateTime.UtcNow;\r\n}\n"})}),"\n",(0,r.jsxs)(n.h3,{id:"trigger-dispatch",children:[(0,r.jsx)(n.strong,{children:"Trigger Dispatch"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"var dispatcher = ServiceProvider.GetRequiredService();\r\nvar stateAccessor = ServiceProvider.GetRequiredService>();\r\nawait dispatcher.Prepare().With(p => p.TestData, name)\r\n .DispatchAsync();\r\n\r\n// You can Capture the validation in case of failure, only call if validators exist.\r\nValidationResult? validation = default;\r\nawait dispatcher.Prepare().With(p => p.TestData, name)\r\n .HandleActionValidation(p => validation = p)\r\n .DispatchAsync();\r\n\r\n// You can trigger synchronously... this will await the whole pipeline, otherwise you just await until action is send to dispatch pool.\r\nawait dispatcher.Prepare().With(p => p.TestData, name)\r\n .Sync()\r\n .DispatchAsync();\r\n\r\n// if the action is implementing ISafeState, the dispatch will always run asSafe=true but an action not implementing ISafeAction will\r\n// have the option to run asSafe or not...\r\nawait dispatcher.Prepare().With(p => p.TestData, name)\r\n .DispatchAsync(true);\n"})}),"\n",(0,r.jsx)(n.h3,{id:"important-notes",children:"Important Notes"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Rule of thumb is always await dispatch calls, avoiding to do so can cause inconsistency for safe dispatch mode.."}),"\n",(0,r.jsx)(n.li,{children:"ISafeAction implementations are always dispatched safely, ignoring unsafe flags."}),"\n",(0,r.jsx)(n.li,{children:"synchronous is an anti-pattern of statemanement use it sparingly; it is primarily for debugging or specific scenarios requiring full completion before continuation."}),"\n"]}),"\n",(0,r.jsxs)(n.h3,{id:"access-state",children:[(0,r.jsx)(n.strong,{children:"Access State"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"var stateAccessor = ServiceProvider.GetRequiredService>();\n"})}),"\n",(0,r.jsx)(n.h3,{id:"blazor-example-usage",children:"Blazor Example Usage"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-csharp",children:"using StatePulse.Net;\r\n\r\npublic partial class CounterView : ComponentBase\r\n{\r\n\r\n // METHOD 1:\r\n [Inject] public IStatePulse PulseState { get; set; } = default!; // Handles State Accessor\r\n\r\n // This is for convienience always use this method or directly PulseState.StateOf(this).Value\r\n // Never assign State Instance variable as it will not update... \r\n // Never use lambda it will throw exception as WeakREference is fundamatally flawed and disposes of lambda even when its object is alive.\r\n private CounterState state => PulseState.StateOf(()=>this, OnUpdate);\r\n \r\n private async Task OnUpdate() => await InvokeAsync(StateHasChanged);\r\n\r\n // METHOD 2: \r\n // Inject direct state but injecting the state directly requires you to handle onchanged events by sub/unsub in lifecycle\r\n // Or to create a basecomponent system similar to other state management systems.\r\n [Inject] public IStateAccessor State { get; set; } = default!; \r\n\r\n \r\n}\n"})})]})}function u(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>s,x:()=>o});var i=t(6540);const r={},a=i.createContext(r);function s(e){const n=i.useContext(a);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),i.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/doc/build/assets/js/e4b9287f.be0d8a84.js b/doc/build/assets/js/e4b9287f.be0d8a84.js new file mode 100644 index 0000000..469c532 --- /dev/null +++ b/doc/build/assets/js/e4b9287f.be0d8a84.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[7778],{4661:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>o,contentTitle:()=>l,default:()=>h,frontMatter:()=>a,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"Getting Started","title":"Get Started","description":"License: MIT","source":"@site/docs/Getting Started.md","sourceDirName":".","slug":"/","permalink":"/","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/Getting Started.md","tags":[],"version":"current","sidebarPosition":1,"frontMatter":{"slug":"/","title":"Get Started","sidebar_position":1},"sidebar":"tutorialSidebar","previous":{"title":"Updates","permalink":"/versions"},"next":{"title":"Setup Blazor Project","permalink":"/setup-blazor-project"}}');var r=n(4848),s=n(8453);const a={slug:"/",title:"Get Started",sidebar_position:1},l="StatePulse.NET",o={},c=[{value:"Official Documentation",id:"official-documentation",level:3},{value:"Features",id:"features",level:2},{value:"\ud83d\ude80 State Management with Zero Boilerplate and Zero Compromises",id:"-state-management-with-zero-boilerplate-and-zero-compromises",level:3},{value:"Benchmark",id:"benchmark",level:2},{value:"\ud83d\udce6 Installation & Setup",id:"-installation--setup",level:2},{value:"3 Ways to Register Services",id:"3-ways-to-register-services",level:3},{value:"\ud83e\udded How It Works",id:"-how-it-works",level:2},{value:"Define Actions:",id:"define-actions",level:3},{value:"Define Effect:",id:"define-effect",level:3},{value:"Define StateFeature:",id:"define-statefeature",level:3},{value:"Trigger Dispatch:",id:"trigger-dispatch",level:3},{value:"Important Notes",id:"important-notes",level:3},{value:"Access State:",id:"access-state",level:3},{value:"Blazor Example Usage",id:"blazor-example-usage",level:3}];function d(e){const t={a:"a",br:"br",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.a,{href:"https://opensource.org/licenses/MIT",children:(0,r.jsx)(t.img,{src:"https://img.shields.io/badge/License-MIT-brightgreen.svg",alt:"License: MIT"})}),"\r\n",(0,r.jsx)(t.a,{href:"https://www.nuget.org/packages/StatePulse.NET",children:(0,r.jsx)(t.img,{src:"https://img.shields.io/nuget/v/StatePulse.Net",alt:"NuGet Version"})}),"\r\n",(0,r.jsx)(t.a,{href:"https://www.nuget.org/packages/StatePulse.NET",children:(0,r.jsx)(t.img,{src:"https://img.shields.io/nuget/dt/StatePulse.NET?label=Downloads",alt:""})}),"\r\n",(0,r.jsx)(t.a,{href:"https://github.com/mshimshon/StatePulse.NET/actions/workflows/ci.yml",children:(0,r.jsx)(t.img,{src:"https://github.com/mshimshon/StatePulse.NET/actions/workflows/ci.yml/badge.svg",alt:"Build"})}),"\r\n",(0,r.jsx)(t.a,{href:"https://github.com/mshimshon/StatePulse.NET/actions/workflows/deploy.yml",children:(0,r.jsx)(t.img,{src:"https://github.com/mshimshon/StatePulse.NET/actions/workflows/deploy.yml/badge.svg",alt:"Deploy"})})]}),"\n",(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"statepulsenet",children:"StatePulse.NET"})}),"\n",(0,r.jsx)(t.h3,{id:"official-documentation",children:(0,r.jsx)(t.a,{href:"https://statepulse.net/",children:"Official Documentation"})}),"\n",(0,r.jsx)(t.p,{children:"StatePulse.NET is a precision\u2011engineered state and action management system designed for high\u2011performance fire\u2011and\u2011yield workflows. It supports optional, internally controlled execution ordering when deterministic sequencing is explicitly required.\r\nIts multi\u2011layer anti\u2011duplication pipeline eliminates redundant dispatches, prevents race conditions, and maintains consistent outcomes even under rapid input or concurrent triggers.\r\nA lightweight internal tracking core provides near\u2011zero\u2011overhead cancellation and dispatch control, minimizing inconsistency without sacrificing throughput.\r\nDespite these guarantees, StatePulse.NET preserves the flexibility of traditional untracked state management, allowing developers to selectively enforce ordering and reliability without introducing global locks or compromising responsiveness."}),"\n",(0,r.jsx)(t.h2,{id:"features",children:"Features"}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Fast Fire-and-Yield"}),(0,r.jsx)(t.br,{}),"\n","Executes actions immediately, including tracked actions, while preserving fire-and-yield semantics."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Multi-Layer Anti-Duplicate Dispatching"}),"\r\nLayer 1: Cancels previously dispatched duplicates before effects, between effects, or after effects, ensuring no redundant action progresses through the pipeline.\r\nLayer 2: Uses a global state-change ticker enforcing a strict \u201clatest action wins\u201d rule so outdated or superseded actions cannot update state."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Effect Validator System"}),(0,r.jsx)(t.br,{}),"\n","Supports multiple, composable validators for modular and reusable rule enforcement."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Synchronous Debug Mode"}),(0,r.jsx)(t.br,{}),"\n","Provides an optional lockstep execution mode ideal for testing, diagnostics, and ",(0,r.jsx)(t.code,{children:"Task.WhenAll"})," based pipelines."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"DispatchTracker"}),(0,r.jsx)(t.br,{}),"\n","Offers high-performance cancellation, deduplication, and concurrency control through an optimized tracking mechanism."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Short-Lived Middlewares"}),"\r\nProvides lightweight, disposable middleware hooks that run only during the lifetime of a single dispatch cycle."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Dispatch Middlewares"}),"\r\nRuns Before, After, and WhenDispatchFails. In asynchronous dispatch modes, failures are silently discarded unless handled internally, so DEC logic should manage its own errors; a logging middleware can also capture unhandled pipeline failures."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Effect Middlewares"}),"\r\nRuns Before, After, WhenValidationFails, and WhenValidationSucceed, allowing fine\u2011grained control and instrumentation around effect execution and validation flow."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Reducer Middlewares"}),"\r\nRuns Before and After the reducer, enabling patterns such as event dispatch on state changes, logging, instrumentation, or enforcing reducer\u2011level invariants."]}),"\n",(0,r.jsxs)(t.h3,{id:"-state-management-with-zero-boilerplate-and-zero-compromises",children:["\ud83d\ude80 ",(0,r.jsx)(t.strong,{children:"State Management with Zero Boilerplate and Zero Compromises"})]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Lazy State Access Model:"})," Inject ",(0,r.jsx)(t.code,{children:"IStatePulse"})," directly into your Blazor component and call ",(0,r.jsx)(t.code,{children:"StateOf(()=>this, TaskMethod)"})," to get scoped state access."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Component-Scoped Event Listening:"})," Automatically registers event listeners only for that component, ensuring ",(0,r.jsx)(t.code,{children:"StateHasChanged()"})," is called exclusively on components subscribed to state changes."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"No Base Classes or Global Event Listeners:"})," Avoids global re-renders and boilerplate base class inheritance, giving you fine-grained control over component rendering and event subscription without forcing you into base classes."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Automatic Listener Disposal:"})," Event listeners are automatically tracked and disposed with the component lifecycle, preventing memory leaks and dangling references."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsxs)(t.strong,{children:["Transient ",(0,r.jsx)(t.code,{children:"IStatePulse"})," Service:"]})," Each component gets its own ",(0,r.jsx)(t.code,{children:"IStatePulse"})," instance, isolating event subscriptions and making state updates scoped and efficient."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"benchmark",children:"Benchmark"}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Method"}),(0,r.jsx)(t.th,{style:{textAlign:"right"},children:"Mean"}),(0,r.jsx)(t.th,{style:{textAlign:"right"},children:"Error"}),(0,r.jsx)(t.th,{style:{textAlign:"right"},children:"StdDev"}),(0,r.jsx)(t.th,{style:{textAlign:"right"},children:"Median"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"StatePulse_Dispatch"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"2.458 \u03bcs"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"0.0344 \u03bcs"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"0.0322 \u03bcs"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"2.455 \u03bcs"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"StatePulse_BusrtDispatch"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"321.243 \u03bcs"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"4.6181 \u03bcs"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"4.3198 \u03bcs"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"322.030 \u03bcs"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"StatePulse_BusrtSafeDispatch"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"350.282 \u03bcs"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"4.4814 \u03bcs"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"4.1919 \u03bcs"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"351.182 \u03bcs"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"StatePulse_FireYieldDispatch"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"3.193 \u03bcs"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"0.0631 \u03bcs"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"0.0675 \u03bcs"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"3.193 \u03bcs"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"StatePulse_FireYield_SequentialEffectsDispatch"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"3.326 \u03bcs"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"0.0661 \u03bcs"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"0.0969 \u03bcs"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"3.303 \u03bcs"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"StatePulse_AwaitedDispatch"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"4.420 \u03bcs"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"0.6850 \u03bcs"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"2.0196 \u03bcs"}),(0,r.jsx)(t.td,{style:{textAlign:"right"},children:"3.165 \u03bcs"})]})]})]}),"\n",(0,r.jsx)(t.p,{children:"StatePulse delivers strong performance given its feature set, but it\u2019s not designed for tight, high\u2011frequency loops. Long\u2011term performance improvements are planned, as there are several areas with optimization potential. For now, the priority remains system stability, configuration robustness, and feature completeness."}),"\n",(0,r.jsx)(t.h2,{id:"-installation--setup",children:"\ud83d\udce6 Installation & Setup"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{children:"Install-Package StatePulse.Net\r\n\r\ndotnet add package StatePulse.Net\r\n\n"})}),"\n",(0,r.jsx)(t.h3,{id:"3-ways-to-register-services",children:"3 Ways to Register Services"}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Method 1"}),(0,r.jsx)(t.br,{}),"\n","The most deterministic and explicit registration approach. This method avoids \u201cmagic\u201d and one\u2011liners by requiring you to manually add all Reducers, Effects, Middlewares, Validators, and Actions. It provides full clarity and control over what the system loads."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-csharp",children:" ServiceCollection.AddStatePulseServices(o =>\r\n {\r\n o.AutoRegisterTypes = [\r\n typeof(MainMenuLoaderStartAction),\r\n typeof(MainMenuLoaderStopAction),\r\n typeof(MainMenuLoadNavigationItemsAction),\r\n typeof(MainMenuLoadNavigationItemsResultAction),\r\n typeof(MainMenuOpenAction),\r\n typeof(ProfileCardDefineAction),\r\n typeof(ProfileCardDefineResultAction),\r\n typeof(ProfileCardLoaderStartAction),\r\n typeof(ProfileCardLoaderStopAction),\r\n typeof(UpdateCounterAction),\r\n typeof(ProfileCardDefineEffect),\r\n typeof(ProfileCardDefineResultAction),\r\n typeof(MainMenuLoadNavigationItemsEffect),\r\n typeof(MainMenuOpenEffect),\r\n typeof(MainMenuOpenEffectValidation),\r\n typeof(ProfileCardDefineActionValidator),\r\n typeof(MainMenuLoaderStartReducer),\r\n typeof(MainMenuLoaderStopReducer),\r\n typeof(MainMenuLoadNavigationItemsResultReducer),\r\n typeof(MainMenuOpenReducer),\r\n typeof(ProfileCardDefineResultReducer),\r\n typeof(UpdateCounterReducer),\r\n typeof(ProfileCardState),\r\n typeof(MainMenuState),\r\n typeof(CounterState),\r\n ];\r\n });\n"})}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Method 2"}),(0,r.jsx)(t.br,{}),"\n","This is also very explicit since v2+ we have a single entry ",(0,r.jsx)(t.code,{children:"AddStatePulseService"})," for all statepulse types (Reducers, Effects, Middlewares, Validators, and Actions)."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-csharp",children:" ServiceCollection.AddStatePulseServices();\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n ServiceCollection.AddStatePulseService();\r\n\r\n ServiceCollection.AddStatePulseService();\n"})}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Method 3"}),"\r\nThe assembly-scan approach. Convenient but not recommended for most scenarios. While useful for rapid setup, it can introduce problems as system grows."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-csharp",children:" ServiceCollection.AddStatePulseServices(o => {\r\n o.ScanAssemblies = [typeof(TestBase).Assembly];\r\n });\n"})}),"\n",(0,r.jsx)(t.h2,{id:"-how-it-works",children:"\ud83e\udded How It Works"}),"\n",(0,r.jsxs)(t.h3,{id:"define-actions",children:[(0,r.jsx)(t.strong,{children:"Define Actions"}),":"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-csharp",children:"\r\n// IAction { }\r\n// ISafeAction { } // Cannot be dispatched unsafely\r\n\r\npublic record ProfileCardDefineAction : IAction\r\n{\r\n public string? TestData { get; set; }\r\n}\r\n\n"})}),"\n",(0,r.jsxs)(t.h3,{id:"define-effect",children:[(0,r.jsx)(t.strong,{children:"Define Effect"}),":"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-csharp",children:'\r\ninternal class ProfileCardDefineEffect : IEffect\r\n{\r\n\r\n public ProfileCardDefineEffect()\r\n {\r\n }\r\n public async Task EffectAsync(ProfileCardDefineAction action, IDispatcher dispatcher)\r\n {\r\n var random = new Random();\r\n int value = random.Next(100, 1001); // Upper bound is exclusive, so use 1001\r\n await Task.Delay(value);\r\n var myProfile = new UserResponse();\r\n await dispatcher.Prepare(() => new ProfileCardDefineResultAction(action.TestData ?? myProfile.Name, myProfile.Picture, myProfile.Id))\r\n .DispatchAsync();\r\n }\r\n\r\n}\r\n\r\n\r\n\r\n### **Define Effect Validator** (Optional):\r\n\r\n```csharp\r\n/*\r\n* This is the best way to define clean conditional effects, it either run or not... this is not meant for triggering errors.\r\n* This is meant for optional/condition effects to either run or not base on the action settings...\r\n*/\r\ninternal class ProfileCardDefineActionValidator : IEffectValidator\r\n{\r\n public Task Validate(ProfileCardDefineAction action)\r\n {\r\n if (action.TestData == "Error")\r\n return Task.FromResult(false);\r\n return Task.FromResult(true);\r\n }\r\n}\n'})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{children:"\r\n### **Define Reducer**:\r\n\r\n```csharp\r\ninternal class ProfileCardDefineResultReducer : IReducer\r\n{\r\n public Task ReduceAsync(ProfileCardState state, ProfileCardDefineResultAction action)\r\n => Task.FromResult(state with\r\n {\r\n LastUpdate = DateTime.UtcNow,\r\n ProfileId = action.Id,\r\n ProfileName = action.Name,\r\n ProfilePicture = action.Picture\r\n });\r\n}\n"})}),"\n",(0,r.jsxs)(t.h3,{id:"define-statefeature",children:[(0,r.jsx)(t.strong,{children:"Define StateFeature"}),":"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-csharp",children:"public record ProfileCardState : IStateFeature\r\n{\r\n public string? ProfileName { get; set; }\r\n public string? ProfilePicture { get; set; }\r\n public string? ProfileId { get; set; }\r\n public DateTime LastUpdate { get; set; } = DateTime.UtcNow;\r\n}\n"})}),"\n",(0,r.jsxs)(t.h3,{id:"trigger-dispatch",children:[(0,r.jsx)(t.strong,{children:"Trigger Dispatch"}),":"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-csharp",children:"var dispatcher = ServiceProvider.GetRequiredService();\r\nvar stateAccessor = ServiceProvider.GetRequiredService>();\r\nawait dispatcher.Prepare().With(p => p.TestData, name)\r\n .DispatchAsync();\r\n\r\n// You can Capture the validation in case of failure, only call if validators exist.\r\nValidationResult? validation = default;\r\nawait dispatcher.Prepare().With(p => p.TestData, name)\r\n .HandleActionValidation(p => validation = p)\r\n .DispatchAsync();\r\n\r\n// You can trigger synchronously... this will await the whole pipeline, otherwise you just await until action is send to dispatch pool.\r\nawait dispatcher.Prepare().With(p => p.TestData, name)\r\n .Sync()\r\n .DispatchAsync();\r\n\r\n// if the action is implementing ISafeState, the dispatch will always run asSafe=true but an action not implementing ISafeAction will\r\n// have the option to run asSafe or not...\r\nawait dispatcher.Prepare().With(p => p.TestData, name)\r\n .DispatchAsync(true);\n"})}),"\n",(0,r.jsx)(t.h3,{id:"important-notes",children:"Important Notes"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Rule of thumb is always await dispatch calls, avoiding to do so can cause inconsistency for safe dispatch mode.."}),"\n",(0,r.jsx)(t.li,{children:"ISafeAction implementations are always dispatched safely, ignoring unsafe flag."}),"\n",(0,r.jsx)(t.li,{children:"synchronous is an anti-pattern of statemanement use it sparingly; it is primarily for debugging or specific scenarios requiring full completion before continuation."}),"\n"]}),"\n",(0,r.jsxs)(t.h3,{id:"access-state",children:[(0,r.jsx)(t.strong,{children:"Access State"}),":"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-csharp",children:"var stateAccessor = ServiceProvider.GetRequiredService>();\n"})}),"\n",(0,r.jsx)(t.h3,{id:"blazor-example-usage",children:"Blazor Example Usage"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-csharp",children:"using StatePulse.Net;\r\n\r\npublic partial class CounterView : ComponentBase\r\n{\r\n\r\n // METHOD 1:\r\n [Inject] public IStatePulse PulseState { get; set; } = default!; // Handles State Accessor\r\n\r\n // This is for convienience always use this method or directly PulseState.StateOf(this).Value\r\n // Never assign State Instance variable as it will not update... \r\n // Never use lambda it will throw exception as WeakREference is fundamatally flawed and disposes of lambda even when its object is alive.\r\n private CounterState state => PulseState.StateOf(()=>this, OnUpdate);\r\n \r\n private async Task OnUpdate() => await InvokeAsync(StateHadChanged);\r\n\r\n // METHOD 2: \r\n // Inject direct state but injecting the state directly requires you to handle onchanged events by sub/unsub in lifecycle\r\n // Or to create a basecomponent system similar to other state management systems.\r\n [Inject] public IStateAccessor State { get; set; } = default!; \r\n\r\n \r\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>l});var i=n(6540);const r={},s=i.createContext(r);function a(e){const t=i.useContext(s);return i.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),i.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/doc/build/assets/js/f2ace840.16526adf.js b/doc/build/assets/js/f2ace840.16526adf.js deleted file mode 100644 index 356c6f4..0000000 --- a/doc/build/assets/js/f2ace840.16526adf.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[688],{5853:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>c,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>u});const s=JSON.parse('{"id":"Create Reducer","title":"The Reducers","description":"\ud83d\udd04 Reducers \u2013 Pure State Updates","source":"@site/docs/5.Create Reducer.md","sourceDirName":".","slug":"/gs-the-reducer","permalink":"/gs-the-reducer","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/5.Create Reducer.md","tags":[{"inline":true,"label":"blazor","permalink":"/tags/blazor"},{"inline":true,"label":"reducer","permalink":"/tags/reducer"},{"inline":true,"label":"state-management","permalink":"/tags/state-management"},{"inline":true,"label":"pure-functions","permalink":"/tags/pure-functions"},{"inline":true,"label":"async","permalink":"/tags/async"},{"inline":true,"label":"statepulse","permalink":"/tags/statepulse"},{"inline":true,"label":"csharp","permalink":"/tags/csharp"},{"inline":true,"label":".net","permalink":"/tags/net"}],"version":"current","sidebarPosition":6,"frontMatter":{"slug":"gs-the-reducer","title":"The Reducers","tags":["blazor","reducer","state-management","pure-functions","async","statepulse","csharp",".net"],"sidebar_position":6},"sidebar":"tutorialSidebar","previous":{"title":"The Effects","permalink":"/gs-the-effect"},"next":{"title":"The Dispatcher","permalink":"/gs-the-dispatcher"}}');var r=n(4848),a=n(8453);const i={slug:"gs-the-reducer",title:"The Reducers",tags:["blazor","reducer","state-management","pure-functions","async","statepulse","csharp",".net"],sidebar_position:6},c=void 0,l={},u=[{value:"\ud83d\udd04 Reducers \u2013 Pure State Updates",id:"-reducers--pure-state-updates",level:2},{value:"\u2728 Key Principles",id:"-key-principles",level:3},{value:"\ud83d\udeab Async Tips",id:"-async-tips",level:3}];function o(e){const t={code:"code",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h2,{id:"-reducers--pure-state-updates",children:"\ud83d\udd04 Reducers \u2013 Pure State Updates"}),"\n",(0,r.jsxs)(t.p,{children:["A ",(0,r.jsx)(t.strong,{children:"reducer"})," is a pure function that updates a specific part of the state in response to an action."]}),"\n",(0,r.jsx)(t.h3,{id:"-key-principles",children:"\u2728 Key Principles"}),"\n",(0,r.jsx)(t.p,{children:"Reducers:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["Take the ",(0,r.jsx)(t.strong,{children:"current state"})," and an ",(0,r.jsx)(t.strong,{children:"action"})]}),"\n",(0,r.jsxs)(t.li,{children:["Return a ",(0,r.jsx)(t.strong,{children:"new state"})]}),"\n",(0,r.jsxs)(t.li,{children:["Must be ",(0,r.jsx)(t.strong,{children:"pure"})," \u2014 no side effects, service calls, or randomness"]}),"\n",(0,r.jsxs)(t.li,{children:["Are called ",(0,r.jsx)(t.strong,{children:"after effects"}),", if any exist"]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"-async-tips",children:"\ud83d\udeab Async Tips"}),"\n",(0,r.jsxs)(t.p,{children:["Reducers may return ",(0,r.jsx)(t.code,{children:"Task"}),", but should ",(0,r.jsxs)(t.strong,{children:["avoid unnecessary ",(0,r.jsx)(t.code,{children:"await"})]}),"."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-csharp",metastring:'title="IncrementReducer.cs"',children:"internal class IncrementReducer : IReducer\r\n{\r\n public Task ReduceAsync(CounterState state, IncrementCounterResultAction action)\r\n => Task.FromResult(state with\r\n {\r\n Count = action.Count\r\n });\r\n}\n"})})]})}function d(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(o,{...e})}):o(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>c});var s=n(6540);const r={},a=s.createContext(r);function i(e){const t=s.useContext(a);return s.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),s.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/doc/build/assets/js/f2ace840.9b65d131.js b/doc/build/assets/js/f2ace840.9b65d131.js new file mode 100644 index 0000000..0c3fa35 --- /dev/null +++ b/doc/build/assets/js/f2ace840.9b65d131.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[688],{5853:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>c,default:()=>u,frontMatter:()=>i,metadata:()=>n,toc:()=>d});const n=JSON.parse('{"id":"Create Reducer","title":"The Reducers","description":"\ud83d\udd04 Reducers \u2013 Pure State Updates","source":"@site/docs/5.Create Reducer.md","sourceDirName":".","slug":"/gs-the-reducer","permalink":"/gs-the-reducer","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/5.Create Reducer.md","tags":[{"inline":true,"label":"blazor","permalink":"/tags/blazor"},{"inline":true,"label":"reducer","permalink":"/tags/reducer"},{"inline":true,"label":"state-management","permalink":"/tags/state-management"},{"inline":true,"label":"pure-functions","permalink":"/tags/pure-functions"},{"inline":true,"label":"async","permalink":"/tags/async"},{"inline":true,"label":"statepulse","permalink":"/tags/statepulse"},{"inline":true,"label":"csharp","permalink":"/tags/csharp"},{"inline":true,"label":".net","permalink":"/tags/net"}],"version":"current","sidebarPosition":6,"frontMatter":{"slug":"gs-the-reducer","title":"The Reducers","tags":["blazor","reducer","state-management","pure-functions","async","statepulse","csharp",".net"],"sidebar_position":6},"sidebar":"tutorialSidebar","previous":{"title":"The Effects","permalink":"/gs-the-effect"},"next":{"title":"The Dispatcher","permalink":"/gs-the-dispatcher"}}');var s=r(4848),a=r(8453);const i={slug:"gs-the-reducer",title:"The Reducers",tags:["blazor","reducer","state-management","pure-functions","async","statepulse","csharp",".net"],sidebar_position:6},c=void 0,l={},d=[{value:"\ud83d\udd04 Reducers \u2013 Pure State Updates",id:"-reducers--pure-state-updates",level:2},{value:"\u2728 Key Principles",id:"-key-principles",level:3},{value:"\ud83d\udeab Async Tips",id:"-async-tips",level:3},{value:"\u2699\ufe0f What are Reducer Middlewares?",id:"\ufe0f-what-are-reducer-middlewares",level:2},{value:"Available Hooks",id:"available-hooks",level:3},{value:"Example: Reducer Middleware",id:"example-reducer-middleware",level:3}];function o(e){const t={blockquote:"blockquote",br:"br",code:"code",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h2,{id:"-reducers--pure-state-updates",children:"\ud83d\udd04 Reducers \u2013 Pure State Updates"}),"\n",(0,s.jsxs)(t.p,{children:["A ",(0,s.jsx)(t.strong,{children:"reducer"})," is a pure function that updates a specific part of the state in response to an action."]}),"\n",(0,s.jsx)(t.h3,{id:"-key-principles",children:"\u2728 Key Principles"}),"\n",(0,s.jsx)(t.p,{children:"Reducers:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["Take the ",(0,s.jsx)(t.strong,{children:"current state"})," and an ",(0,s.jsx)(t.strong,{children:"action"})]}),"\n",(0,s.jsxs)(t.li,{children:["Return a ",(0,s.jsx)(t.strong,{children:"new state"})]}),"\n",(0,s.jsxs)(t.li,{children:["Must be ",(0,s.jsx)(t.strong,{children:"pure"})," \u2014 no side effects, service calls, or randomness"]}),"\n",(0,s.jsxs)(t.li,{children:["Are called ",(0,s.jsx)(t.strong,{children:"after effects"}),", if any exist"]}),"\n"]}),"\n",(0,s.jsx)(t.h3,{id:"-async-tips",children:"\ud83d\udeab Async Tips"}),"\n",(0,s.jsxs)(t.p,{children:["Reducers may return ",(0,s.jsx)(t.code,{children:"Task"}),", but should ",(0,s.jsxs)(t.strong,{children:["avoid unnecessary ",(0,s.jsx)(t.code,{children:"await"})]}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-csharp",metastring:'title="IncrementReducer.cs"',children:"internal class IncrementReducer : IReducer\r\n{\r\n public Task ReduceAsync(CounterState state, IncrementCounterResultAction action)\r\n => Task.FromResult(state with\r\n {\r\n Count = action.Count\r\n });\r\n}\n"})}),"\n",(0,s.jsx)(t.h2,{id:"\ufe0f-what-are-reducer-middlewares",children:"\u2699\ufe0f What are Reducer Middlewares?"}),"\n",(0,s.jsxs)(t.p,{children:["StatePulse uses ",(0,s.jsx)(t.strong,{children:"middleware interfaces"})," to tap into the lifecycle of ",(0,s.jsx)(t.strong,{children:"effects"}),", ",(0,s.jsx)(t.strong,{children:"reducers"}),", and ",(0,s.jsx)(t.strong,{children:"dispatches"}),".",(0,s.jsx)(t.br,{}),"\n","These middleware hooks are useful for ",(0,s.jsx)(t.strong,{children:"logging"}),", ",(0,s.jsx)(t.strong,{children:"metrics"}),", ",(0,s.jsx)(t.strong,{children:"analytics"}),", or ",(0,s.jsx)(t.strong,{children:"debugging"})," \u2014 but should ",(0,s.jsx)(t.strong,{children:"never alter behavior"})," or mutate state."]}),"\n",(0,s.jsxs)(t.blockquote,{children:["\n",(0,s.jsx)(t.p,{children:"\u2757 Middleware is observational only \u2014 do not use it to change logic or outcomes."}),"\n"]}),"\n",(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.code,{children:"IReducerMiddleware"})," allows you to hook into the execution of any effect."]}),"\n",(0,s.jsx)(t.h3,{id:"available-hooks",children:"Available Hooks"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.code,{children:"BeforeReducing(object state, object action)"})," \u2013 called ",(0,s.jsx)(t.strong,{children:"before"})," the reducer runs"]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.code,{children:"AfterReducing(object state, object action)"})," \u2013 called ",(0,s.jsx)(t.strong,{children:"after"})," the reducer runs"]}),"\n"]}),"\n",(0,s.jsx)(t.h3,{id:"example-reducer-middleware",children:"Example: Reducer Middleware"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-csharp",metastring:'title="LoggingReducerMiddleware.cs"',children:'internal class LoggingReducerMiddleware : IReducerMiddleware\r\n{\r\n public Task AfterReducing(object state, object action)\r\n {\r\n Console.WriteLine($"{action.GetType().Name} Executed.");\r\n return Task.CompletedTask;\r\n }\r\n\r\n public Task BeforeReducing(object state, object action)\r\n {\r\n Console.WriteLine($"{state.GetType().Name} {action.GetType().Name} Executed.");\r\n return Task.CompletedTask;\r\n }\r\n}\n'})})]})}function u(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(o,{...e})}):o(e)}},8453:(e,t,r)=>{r.d(t,{R:()=>i,x:()=>c});var n=r(6540);const s={},a=n.createContext(s);function i(e){const t=n.useContext(a);return n.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:i(e.components),n.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/doc/build/assets/js/f552f37d.15137b77.js b/doc/build/assets/js/f552f37d.15137b77.js deleted file mode 100644 index fccd15a..0000000 --- a/doc/build/assets/js/f552f37d.15137b77.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[1653],{5679:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>o,contentTitle:()=>l,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"Create State","title":"The States","description":"Defining a State","source":"@site/docs/3.Create State.md","sourceDirName":".","slug":"/gs-state","permalink":"/gs-state","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/3.Create State.md","tags":[{"inline":true,"label":"blazor","permalink":"/tags/blazor"},{"inline":true,"label":"state","permalink":"/tags/state"},{"inline":true,"label":"state-management","permalink":"/tags/state-management"},{"inline":true,"label":"immutable","permalink":"/tags/immutable"},{"inline":true,"label":"csharp","permalink":"/tags/csharp"},{"inline":true,"label":".net","permalink":"/tags/net"},{"inline":true,"label":"statepulse","permalink":"/tags/statepulse"}],"version":"current","sidebarPosition":4,"frontMatter":{"slug":"gs-state","title":"The States","tags":["blazor","state","state-management","immutable","csharp",".net","statepulse"],"sidebar_position":4},"sidebar":"tutorialSidebar","previous":{"title":"The Actions","permalink":"/gs-the-action"},"next":{"title":"The Effects","permalink":"/gs-the-effect"}}');var a=n(4848),r=n(8453);const i={slug:"gs-state",title:"The States",tags:["blazor","state","state-management","immutable","csharp",".net","statepulse"],sidebar_position:4},l=void 0,o={},c=[{value:"Defining a State",id:"defining-a-state",level:2},{value:"Example: Counter State",id:"example-counter-state",level:3},{value:"\ud83c\udfaf Manual State Hooking",id:"-manual-state-hooking",level:2},{value:"\u2705 Why This Is Optimal",id:"-why-this-is-optimal",level:3},{value:"\ud83d\udee0\ufe0f Example: Manual State Hook",id:"\ufe0f-example-manual-state-hook",level:3},{value:"\ud83c\udf00 Zero-Boilerplate Without Compromise",id:"-zero-boilerplate-without-compromise",level:2},{value:"\ud83d\udee0\ufe0f Example: Zero-Boilerplate State Hook",id:"\ufe0f-example-zero-boilerplate-state-hook",level:3}];function d(e){const t={blockquote:"blockquote",br:"br",code:"code",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h2,{id:"defining-a-state",children:"Defining a State"}),"\n",(0,a.jsxs)(t.p,{children:["A ",(0,a.jsx)(t.strong,{children:"state"})," represents a slice of your application's data. It should be:"]}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:["Immutable (defined as a ",(0,a.jsx)(t.code,{children:"record"}),")"]}),"\n",(0,a.jsx)(t.li,{children:"Serializable (for debugging, testing, or persistence)"}),"\n",(0,a.jsx)(t.li,{children:"Focused (represents a single domain or feature)"}),"\n"]}),"\n",(0,a.jsx)(t.h3,{id:"example-counter-state",children:"Example: Counter State"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-csharp",metastring:'title="CounterState.cs"',children:"public record CounterState : IStateFeature\r\n{\r\n public int Count { get; init; }\r\n}\n"})}),"\n",(0,a.jsx)(t.h2,{id:"-manual-state-hooking",children:"\ud83c\udfaf Manual State Hooking"}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.strong,{children:"manual subscription approach"})," is the most ",(0,a.jsx)(t.strong,{children:"performant and reliable"})," way to handle state updates \u2014 in StatePulse or any other state management library."]}),"\n",(0,a.jsxs)(t.p,{children:["By ",(0,a.jsx)(t.strong,{children:"explicitly subscribing and unsubscribing"})," to a specific state, only the components that depend on that state are re-rendered.",(0,a.jsx)(t.br,{}),"\n","This avoids unnecessary rendering and offers precise control."]}),"\n",(0,a.jsx)(t.h3,{id:"-why-this-is-optimal",children:"\u2705 Why This Is Optimal"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"No overhead"})," from global tracking or base components"]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Fine-grained control"})," over component updates"]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Best performance"}),", especially in large apps"]}),"\n",(0,a.jsx)(t.li,{children:(0,a.jsx)(t.strong,{children:"Works without any framework-specific magic"})}),"\n"]}),"\n",(0,a.jsxs)(t.blockquote,{children:["\n",(0,a.jsxs)(t.p,{children:["\u26a0\ufe0f The downside? It requires more boilerplate.",(0,a.jsx)(t.br,{}),"\n","That's why many libraries introduce alternatives like global components, wrappers, or base components \u2014 but these come with trade-offs in flexibility or overhead."]}),"\n"]}),"\n",(0,a.jsx)(t.h3,{id:"\ufe0f-example-manual-state-hook",children:"\ud83d\udee0\ufe0f Example: Manual State Hook"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-csharp",metastring:'title="Counter.razor.cs"',children:"public partial class Counter : ComponentBase, IAsyncDisposable\r\n{\r\n [Inject] IStateAccessor State { get; set; }\r\n [Inject] private IDispatcher Dispatcher { get; set; }\r\n\r\n protected override void OnInitialized()\r\n {\r\n State.OnStateChangedNoDetails += ShouldUpdate;\r\n }\r\n\r\n private void ShouldUpdate(object? sender, EventArgs e)\r\n {\r\n _ = InvokeAsync(StateHasChanged);\r\n }\r\n\r\n private async Task Increment()\r\n {\r\n await Dispatcher.Prepare()\r\n .With(p => p.Delay, 1)\r\n .DispatchAsync();\r\n }\r\n\r\n public ValueTask DisposeAsync()\r\n {\r\n State.OnStateChangedNoDetails -= ShouldUpdate;\r\n return ValueTask.CompletedTask;\r\n }\r\n}\n"})}),"\n",(0,a.jsx)(t.h2,{id:"-zero-boilerplate-without-compromise",children:"\ud83c\udf00 Zero-Boilerplate Without Compromise"}),"\n",(0,a.jsxs)(t.p,{children:["StatePulse ",(0,a.jsx)(t.strong,{children:"does not force you"})," to inherit from a base component or use a global component to track state changes.",(0,a.jsx)(t.br,{}),"\n","Instead, StatePulse provides a ",(0,a.jsx)(t.strong,{children:"clever and efficient mechanism"})," to track components that request state,",(0,a.jsx)(t.br,{}),"\n","binding them automatically with:"]}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:["\u2705 ",(0,a.jsx)(t.strong,{children:"Memory leak protection"})]}),"\n",(0,a.jsxs)(t.li,{children:["\u26a1 ",(0,a.jsx)(t.strong,{children:"Optimized getters"})]}),"\n",(0,a.jsxs)(t.li,{children:["\ud83e\uddfc ",(0,a.jsx)(t.strong,{children:"Zero boilerplate on your side"})]}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["This ensures ",(0,a.jsx)(t.strong,{children:"no architectural compromises"})," burden placed on you."]}),"\n",(0,a.jsxs)(t.p,{children:["StatePulse offers a ",(0,a.jsx)(t.strong,{children:"zero-boilerplate"})," way to subscribe to and track component-bound state changes \u2014 using ",(0,a.jsx)(t.code,{children:"IStatePulse"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["This method requires ",(0,a.jsx)(t.strong,{children:"no manual subscription or disposal"}),", yet still tracks updates ",(0,a.jsx)(t.strong,{children:"per component"}),", safely and efficiently."]}),"\n",(0,a.jsx)(t.h3,{id:"\ufe0f-example-zero-boilerplate-state-hook",children:"\ud83d\udee0\ufe0f Example: Zero-Boilerplate State Hook"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-csharp",metastring:'title="Counter.razor.cs"',children:"public partial class Counter : ComponentBase\r\n{\r\n [Inject] IStatePulse Pulse { get; set; }\r\n private CounterState State => Pulse.StateOf(() => this, ShouldUpdate);\r\n [Inject] private IDispatcher Dispatcher { get; set; }\r\n public Task ShouldUpdate() => InvokeAsync(StateHasChanged);\r\n private async Task Increment()\r\n {\r\n await Dispatcher.Prepare()\r\n .With(p => p.Delay, 1)\r\n .DispatchAsync();\r\n }\r\n}\n"})}),"\n",(0,a.jsxs)(t.blockquote,{children:["\n",(0,a.jsxs)(t.p,{children:["\ud83d\udcdd ",(0,a.jsxs)(t.strong,{children:["Note on ",(0,a.jsx)(t.code,{children:"StateOf()"})," Usage"]})]}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["You might notice that ",(0,a.jsx)(t.code,{children:"Pulse.StateOf(() => this, ShouldUpdate)"})," is called during every render.",(0,a.jsx)(t.br,{}),"\n","At first glance, this may seem inefficient \u2014 but it\u2019s actually intentional and necessary."]}),"\n",(0,a.jsxs)(t.p,{children:["This method guarantees that the component is correctly bound to the state and always get latest state.",(0,a.jsx)(t.br,{}),"\n","Without using this shorthand, you\u2019d be forced to call ",(0,a.jsx)(t.code,{children:"StateOf(...).Property"})," directly in your Razor markup, which becomes less readable and harder to maintain."]}),"\n",(0,a.jsxs)(t.p,{children:["When ",(0,a.jsx)(t.code,{children:"StateOf()"})," is called:"]}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:["StatePulse checks whether the component (identified by ",(0,a.jsx)(t.code,{children:"()=> this"}),") is already being tracked."]}),"\n",(0,a.jsxs)(t.li,{children:["If not, it sets up the binding and associates the provided ",(0,a.jsx)(t.code,{children:"ShouldUpdate"})," method as a re-render callback."]}),"\n",(0,a.jsx)(t.li,{children:"If it is already tracked, the call becomes a fast property access with near-zero overhead."}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["\u26a1 ",(0,a.jsx)(t.strong,{children:"The only cost is during the initial setup."}),(0,a.jsx)(t.br,{}),"\n","All future calls are optimized and safe to run on every render."]}),"\n",(0,a.jsxs)(t.p,{children:["This design ensures you always have ",(0,a.jsx)(t.strong,{children:"up-to-date, reactive state"})," with ",(0,a.jsx)(t.strong,{children:"no boilerplate"})," and ",(0,a.jsx)(t.strong,{children:"minimal performance impact"}),"."]})]})}function h(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(d,{...e})}):d(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>l});var s=n(6540);const a={},r=s.createContext(a);function i(e){const t=s.useContext(r);return s.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:i(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/doc/build/assets/js/f552f37d.8dfeb3df.js b/doc/build/assets/js/f552f37d.8dfeb3df.js new file mode 100644 index 0000000..84917c8 --- /dev/null +++ b/doc/build/assets/js/f552f37d.8dfeb3df.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[1653],{5679:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>o,contentTitle:()=>l,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"Create State","title":"The States","description":"Defining a State","source":"@site/docs/3.Create State.md","sourceDirName":".","slug":"/gs-state","permalink":"/gs-state","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/3.Create State.md","tags":[{"inline":true,"label":"blazor","permalink":"/tags/blazor"},{"inline":true,"label":"state","permalink":"/tags/state"},{"inline":true,"label":"state-management","permalink":"/tags/state-management"},{"inline":true,"label":"immutable","permalink":"/tags/immutable"},{"inline":true,"label":"csharp","permalink":"/tags/csharp"},{"inline":true,"label":".net","permalink":"/tags/net"},{"inline":true,"label":"statepulse","permalink":"/tags/statepulse"}],"version":"current","sidebarPosition":4,"frontMatter":{"slug":"gs-state","title":"The States","tags":["blazor","state","state-management","immutable","csharp",".net","statepulse"],"sidebar_position":4},"sidebar":"tutorialSidebar","previous":{"title":"The Actions","permalink":"/gs-the-action"},"next":{"title":"The Effects","permalink":"/gs-the-effect"}}');var a=n(4848),r=n(8453);const i={slug:"gs-state",title:"The States",tags:["blazor","state","state-management","immutable","csharp",".net","statepulse"],sidebar_position:4},l=void 0,o={},c=[{value:"Defining a State",id:"defining-a-state",level:2},{value:"Example: Counter State",id:"example-counter-state",level:3},{value:"\ud83c\udfaf Manual State Hooking",id:"-manual-state-hooking",level:2},{value:"\u2705 Why This Is Optimal",id:"-why-this-is-optimal",level:3},{value:"\ud83d\udee0\ufe0f Example: Manual State Hook",id:"\ufe0f-example-manual-state-hook",level:3},{value:"\ud83c\udf00 Zero-Boilerplate Without Compromise",id:"-zero-boilerplate-without-compromise",level:2},{value:"\ud83d\udee0\ufe0f Example: Zero-Boilerplate State Hook",id:"\ufe0f-example-zero-boilerplate-state-hook",level:3}];function d(e){const t={blockquote:"blockquote",br:"br",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h2,{id:"defining-a-state",children:"Defining a State"}),"\n",(0,a.jsxs)(t.p,{children:["A ",(0,a.jsx)(t.strong,{children:"state"})," represents a slice of your application's data. It should be:"]}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:["Immutable (defined as a ",(0,a.jsx)(t.code,{children:"record"}),")"]}),"\n",(0,a.jsx)(t.li,{children:"Serializable (for debugging, testing, or persistence)"}),"\n",(0,a.jsx)(t.li,{children:"Focused (represents a single domain or feature)"}),"\n"]}),"\n",(0,a.jsx)(t.h3,{id:"example-counter-state",children:"Example: Counter State"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-csharp",metastring:'title="CounterState.cs"',children:"public record CounterState : IStateFeature\r\n{\r\n public int Count { get; init; }\r\n}\n"})}),"\n",(0,a.jsx)(t.h2,{id:"-manual-state-hooking",children:"\ud83c\udfaf Manual State Hooking"}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.strong,{children:"manual subscription approach"})," is the most ",(0,a.jsx)(t.strong,{children:"performant and reliable"})," way to handle state updates \u2014 in StatePulse or any other state management library."]}),"\n",(0,a.jsxs)(t.p,{children:["By ",(0,a.jsx)(t.strong,{children:"explicitly subscribing and unsubscribing"})," to a specific state, only the components that depend on that state are re-rendered.",(0,a.jsx)(t.br,{}),"\n","This avoids unnecessary rendering and offers precise control."]}),"\n",(0,a.jsx)(t.h3,{id:"-why-this-is-optimal",children:"\u2705 Why This Is Optimal"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"No overhead"})," from global tracking or base components"]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Fine-grained control"})," over component updates"]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.strong,{children:"Best performance"}),", especially in large apps"]}),"\n",(0,a.jsx)(t.li,{children:(0,a.jsx)(t.strong,{children:"Works without any framework-specific magic"})}),"\n"]}),"\n",(0,a.jsxs)(t.blockquote,{children:["\n",(0,a.jsxs)(t.p,{children:["\u26a0\ufe0f The downside? It requires more boilerplate.",(0,a.jsx)(t.br,{}),"\n","That's why many libraries introduce alternatives like global components, wrappers, or base components \u2014 but these come with trade-offs in flexibility or overhead."]}),"\n"]}),"\n",(0,a.jsx)(t.h3,{id:"\ufe0f-example-manual-state-hook",children:"\ud83d\udee0\ufe0f Example: Manual State Hook"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-csharp",metastring:'title="Counter.razor.cs"',children:"public partial class Counter : ComponentBase, IAsyncDisposable\r\n{\r\n [Inject] IStateAccessor State { get; set; }\r\n [Inject] private IDispatcher Dispatcher { get; set; }\r\n\r\n protected override void OnInitialized()\r\n {\r\n State.OnStateChangedNoDetails += ShouldUpdate;\r\n }\r\n\r\n private void ShouldUpdate(object? sender, EventArgs e)\r\n {\r\n _ = InvokeAsync(StateHasChanged);\r\n }\r\n\r\n private async Task Increment()\r\n {\r\n await Dispatcher.Prepare()\r\n .With(p => p.Delay, 1)\r\n .DispatchAsync();\r\n }\r\n\r\n public ValueTask DisposeAsync()\r\n {\r\n State.OnStateChangedNoDetails -= ShouldUpdate;\r\n return ValueTask.CompletedTask;\r\n }\r\n}\n"})}),"\n",(0,a.jsx)(t.h2,{id:"-zero-boilerplate-without-compromise",children:"\ud83c\udf00 Zero-Boilerplate Without Compromise"}),"\n",(0,a.jsxs)(t.p,{children:["StatePulse ",(0,a.jsx)(t.strong,{children:"does not force you"})," to inherit from a base component or use a global component to track state changes.",(0,a.jsx)(t.br,{}),"\n","Instead, StatePulse provides a ",(0,a.jsx)(t.strong,{children:"clever and efficient mechanism"})," to track components that request state,",(0,a.jsx)(t.br,{}),"\n","binding them automatically with:"]}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:["\u2705 ",(0,a.jsx)(t.strong,{children:"Memory leak protection"})]}),"\n",(0,a.jsxs)(t.li,{children:["\u26a1 ",(0,a.jsx)(t.strong,{children:"Optimized getters"})]}),"\n",(0,a.jsxs)(t.li,{children:["\ud83e\uddfc ",(0,a.jsx)(t.strong,{children:"Zero boilerplate on your side"})]}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["This ensures ",(0,a.jsx)(t.strong,{children:"no architectural compromises"})," burden placed on you."]}),"\n",(0,a.jsxs)(t.p,{children:["StatePulse offers a ",(0,a.jsx)(t.strong,{children:"zero-boilerplate"})," way to subscribe to and track component-bound state changes \u2014 using ",(0,a.jsx)(t.code,{children:"IStatePulse"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["This method requires ",(0,a.jsx)(t.strong,{children:"no manual subscription or disposal"}),", yet still tracks updates ",(0,a.jsx)(t.strong,{children:"per component"}),", safely and efficiently."]}),"\n",(0,a.jsx)(t.h3,{id:"\ufe0f-example-zero-boilerplate-state-hook",children:"\ud83d\udee0\ufe0f Example: Zero-Boilerplate State Hook"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-csharp",metastring:'title="Counter.razor.cs"',children:"public partial class Counter : ComponentBase\r\n{\r\n [Inject] IStatePulse Pulse { get; set; }\r\n private CounterState State => Pulse.StateOf(() => this, ShouldUpdate);\r\n public Task ShouldUpdate() => InvokeAsync(StateHasChanged);\r\n private async Task Increment()\r\n {\r\n await Pulse.Dispatcher.Prepare()\r\n .With(p => p.Delay, 1)\r\n .DispatchAsync();\r\n }\r\n}\n"})}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsxs)(t.em,{children:["Note: when injecting ",(0,a.jsx)(t.code,{children:"IStatePulse"}),", you do not need to inject ",(0,a.jsx)(t.code,{children:"IDispatcher"}),"."]})}),"\n",(0,a.jsxs)(t.blockquote,{children:["\n",(0,a.jsxs)(t.p,{children:["\ud83d\udcdd ",(0,a.jsxs)(t.strong,{children:["Note on ",(0,a.jsx)(t.code,{children:"StateOf()"})," Usage"]})]}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:["You might notice that ",(0,a.jsx)(t.code,{children:"Pulse.StateOf(() => this, ShouldUpdate)"})," is called during every render.",(0,a.jsx)(t.br,{}),"\n","At first glance, this may seem inefficient or even odd syntax but it\u2019s actually intentional, efficient and necessary."]}),"\n",(0,a.jsxs)(t.p,{children:["When ",(0,a.jsx)(t.code,{children:"StateOf()"})," is called:"]}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:["StatePulse checks whether the component (identified by ",(0,a.jsx)(t.code,{children:"()=> this"}),") is already being tracked."]}),"\n",(0,a.jsxs)(t.li,{children:["If not, it sets up the binding and associates the provided ",(0,a.jsx)(t.code,{children:"ShouldUpdate"})," method as a re-render callback (Slow first hit)."]}),"\n",(0,a.jsx)(t.li,{children:"If it is already tracked, the call becomes a fast property access with near-zero overhead (subsequent accesses are fast)."}),"\n"]}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(t.strong,{children:"Mandatory Syntax"}),"\r\nAs of v2.0+ compiler will generate an error when ",(0,a.jsx)(t.code,{children:"()=> this"})," is not exactly that and when ",(0,a.jsx)(t.code,{children:"ShouldUpdate"})," is a lambda which is forbidden and has to be named method to avoid runtime issues."]}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(t.strong,{children:"The only cost is during the initial setup."}),(0,a.jsx)(t.br,{}),"\n","All future calls are optimized, cached and safe to run on every render, on every line."]}),"\n",(0,a.jsxs)(t.p,{children:["This design ensures you always have ",(0,a.jsx)(t.strong,{children:"up-to-date, reactive state"})," with ",(0,a.jsx)(t.strong,{children:"no boilerplate"})," and ",(0,a.jsx)(t.strong,{children:"minimal performance impact"}),"."]})]})}function h(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(d,{...e})}):d(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>l});var s=n(6540);const a={},r=s.createContext(a);function i(e){const t=s.useContext(r);return s.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:i(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/doc/build/assets/js/febfe999.614202d2.js b/doc/build/assets/js/febfe999.614202d2.js deleted file mode 100644 index a448135..0000000 --- a/doc/build/assets/js/febfe999.614202d2.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[6452],{6298:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>c,default:()=>d,frontMatter:()=>a,metadata:()=>s,toc:()=>o});const s=JSON.parse('{"id":"Inject Dispatcher","title":"The Dispatcher","description":"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse","source":"@site/docs/6.Inject Dispatcher.md","sourceDirName":".","slug":"/gs-the-dispatcher","permalink":"/gs-the-dispatcher","draft":false,"unlisted":false,"editUrl":"https://github.com/mshimshon/StatePulse.NET/docs/6.Inject Dispatcher.md","tags":[{"inline":true,"label":"blazor","permalink":"/tags/blazor"},{"inline":true,"label":"state-management","permalink":"/tags/state-management"},{"inline":true,"label":"dispatcher","permalink":"/tags/dispatcher"},{"inline":true,"label":"actions","permalink":"/tags/actions"},{"inline":true,"label":"safedispatch","permalink":"/tags/safedispatch"},{"inline":true,"label":"redux","permalink":"/tags/redux"},{"inline":true,"label":"statepulse","permalink":"/tags/statepulse"},{"inline":true,"label":"async","permalink":"/tags/async"},{"inline":true,"label":"await","permalink":"/tags/await"},{"inline":true,"label":"performance","permalink":"/tags/performance"}],"version":"current","sidebarPosition":6,"frontMatter":{"slug":"gs-the-dispatcher","title":"The Dispatcher","tags":["blazor","state-management","dispatcher","actions","safedispatch","redux","statepulse","async","await","performance"],"sidebar_position":6},"sidebar":"tutorialSidebar","previous":{"title":"The Reducers","permalink":"/gs-the-reducer"},"next":{"title":"The Middlewares","permalink":"/gs-the-middlewares"}}');var i=t(4848),r=t(8453);const a={slug:"gs-the-dispatcher",title:"The Dispatcher",tags:["blazor","state-management","dispatcher","actions","safedispatch","redux","statepulse","async","await","performance"],sidebar_position:6},c=void 0,l={},o=[{value:"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse",id:"-dispatcher--executing-actions-in-statepulse",level:2},{value:"\ud83e\udded Dispatch Flow",id:"-dispatch-flow",level:3},{value:"\u26a0\ufe0f About Constructors",id:"\ufe0f-about-constructors",level:3},{value:"Inject into Component",id:"inject-into-component",level:3},{value:"\ud83d\udee0\ufe0f Pre-initializing Actions (Optional)",id:"\ufe0f-pre-initializing-actions-optional",level:3},{value:"\ud83e\uddf5 Safe Execution On-the-Fly",id:"-safe-execution-on-the-fly",level:3},{value:"\u26a0\ufe0f Use Safe Actions Selectively",id:"\ufe0f-use-safe-actions-selectively",level:3},{value:"\u23f3 Await Pipeline",id:"-await-pipeline",level:3},{value:"Why Awaiting Matters in .NET / StatePulse",id:"why-awaiting-matters-in-net--statepulse",level:4}];function h(e){const n={blockquote:"blockquote",br:"br",code:"code",h2:"h2",h3:"h3",h4:"h4",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h2,{id:"-dispatcher--executing-actions-in-statepulse",children:"\ud83d\ude80 Dispatcher \u2013 Executing Actions in StatePulse"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.strong,{children:"dispatcher"})," in StatePulse is responsible for preparing and executing actions in a clean and fluent way.",(0,i.jsx)(n.br,{}),"\n","Unlike some traditional systems, the dispatch pattern here is more structured:"]}),"\n",(0,i.jsx)(n.h3,{id:"-dispatch-flow",children:"\ud83e\udded Dispatch Flow"}),"\n",(0,i.jsx)(n.p,{children:"The standard flow for dispatching an action is:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"Prepare()"})," \u2013 creates the action instance"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:".With(...)"})," \u2013 sets properties on the action"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:".DispatchAsync()"})," \u2013 executes the action"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"This approach promotes immutability, clear intent, and safe updates."}),"\n",(0,i.jsx)(n.h3,{id:"\ufe0f-about-constructors",children:"\u26a0\ufe0f About Constructors"}),"\n",(0,i.jsxs)(n.p,{children:["You ",(0,i.jsx)(n.strong,{children:"can"})," pass constructor arguments in ",(0,i.jsx)(n.code,{children:"Prepare()"}),", like this:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-csharp",children:"Dispatcher.Prepare(arg1, arg2);\n"})}),"\n",(0,i.jsxs)(n.p,{children:["But this is ",(0,i.jsx)(n.strong,{children:"strongly discouraged"}),", and ideally avoided completely."]}),"\n",(0,i.jsxs)(n.p,{children:["\u2757 ",(0,i.jsx)(n.strong,{children:"Why avoid it?"}),(0,i.jsx)(n.br,{}),"\n","If the constructor changes later (e.g., parameter added, removed, or reordered),",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.strong,{children:"the compiler won\u2019t warn you"}),", and your dispatch logic may ",(0,i.jsx)(n.strong,{children:"break silently at runtime"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"This can lead to:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Incorrect action initialization"}),"\n",(0,i.jsx)(n.li,{children:"Subtle bugs"}),"\n",(0,i.jsx)(n.li,{children:"Hard-to-trace state issues"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"inject-into-component",children:"Inject into Component"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-csharp",metastring:'title="Counter.razor.cs"',children:"public partial class Counter : ComponentBase\r\n{\r\n [Inject] private IDispatcher Dispatcher { get; set; }\r\n private async Task Increment()\r\n {\r\n await Dispatcher.Prepare()\r\n .With(p => p.Delay, 1)\r\n .DispatchAsync();\r\n }\r\n}\n"})}),"\n",(0,i.jsx)(n.h3,{id:"\ufe0f-pre-initializing-actions-optional",children:"\ud83d\udee0\ufe0f Pre-initializing Actions (Optional)"}),"\n",(0,i.jsxs)(n.p,{children:["You can also ",(0,i.jsx)(n.strong,{children:"pre-initialize an action"})," manually \u2014 similar to how it's done in conventional state management systems."]}),"\n",(0,i.jsx)(n.p,{children:"This approach is useful when:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["You're using ",(0,i.jsx)(n.strong,{children:"constructor-based action records"})]}),"\n",(0,i.jsxs)(n.li,{children:["You're ",(0,i.jsx)(n.strong,{children:"dispatching actions in a loop"}),", where minimizing per-dispatch overhead matters"]}),"\n"]}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsxs)(n.p,{children:["\u26a0\ufe0f ",(0,i.jsxs)(n.strong,{children:["While the reflection overhead of ",(0,i.jsx)(n.code,{children:"Prepare()"})," is small, it does exist."]})," In performance-critical scenarios (like loops or tight UI updates), ",(0,i.jsx)(n.strong,{children:"pre-initializing the action"})," can offer a slight efficiency gain."]}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-csharp",metastring:'title="Counter.razor.cs"',children:"public partial class Counter : ComponentBase\r\n{\r\n [Inject] private IDispatcher Dispatcher { get; set; }\r\n private async Task Increment()\r\n {\r\n await Dispatcher.Prepare(()=> new IncrementCounterAction(){\r\n Delay = 1\r\n }).DispatchAsync();\r\n }\r\n}\n"})}),"\n",(0,i.jsx)(n.h3,{id:"-safe-execution-on-the-fly",children:"\ud83e\uddf5 Safe Execution On-the-Fly"}),"\n",(0,i.jsxs)(n.p,{children:["Every action in StatePulse can be executed ",(0,i.jsx)(n.strong,{children:"on-the-fly as a safe action"}),",",(0,i.jsx)(n.br,{}),"\n","meaning any ",(0,i.jsx)(n.strong,{children:"subsequent execution cancels the previous one"}),".",(0,i.jsx)(n.br,{}),"\n","This significantly reduces the risk of race conditions in async workflows."]}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsx)(n.p,{children:"\u2705 This is especially helpful for API calls, debounced interactions, or long-running processes."}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"\ufe0f-use-safe-actions-selectively",children:"\u26a0\ufe0f Use Safe Actions Selectively"}),"\n",(0,i.jsxs)(n.p,{children:["While powerful, ",(0,i.jsx)(n.strong,{children:"safe actions come with a small overhead footprint"}),".",(0,i.jsx)(n.br,{}),"\n","You should ",(0,i.jsx)(n.strong,{children:"avoid using them"})," for:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Reducer-only actions (e.g., local counter updates)"}),"\n",(0,i.jsx)(n.li,{children:"Instantaneous operations where no async delay exists"}),"\n"]}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsxs)(n.p,{children:["\u26a0\ufe0f ",(0,i.jsxs)(n.strong,{children:["Overusing ",(0,i.jsx)(n.code,{children:"ISafeAction"})," can lead to performance degradation in large or complex UIs."]}),(0,i.jsx)(n.br,{}),"\n","While it's unlikely you'll encounter direct issues in most apps,",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.strong,{children:"why not save performance when it's that easy to do?"})]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["Use ",(0,i.jsx)(n.code,{children:"ISafeAction"})," only when the benefits \u2014 like cancellation, deduplication, or race condition protection \u2014 are necessary."]}),"\n",(0,i.jsx)(n.h3,{id:"-await-pipeline",children:"\u23f3 Await Pipeline"}),"\n",(0,i.jsxs)(n.p,{children:["You can ",(0,i.jsx)(n.strong,{children:"await the dispatch pipeline"}),", which means your code will ",(0,i.jsx)(n.strong,{children:"block execution until the entire pipeline completes"}),":"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["All ",(0,i.jsx)(n.strong,{children:"effects"})," (including cascading effects) finish"]}),"\n",(0,i.jsxs)(n.li,{children:["All ",(0,i.jsx)(n.strong,{children:"reducers"})," have executed"]}),"\n",(0,i.jsx)(n.li,{children:"The full state update cycle is done"}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["This feature is ",(0,i.jsx)(n.strong,{children:"not common in traditional Redux-style state management"}),",",(0,i.jsx)(n.br,{}),"\n","which often relies on external tools (like Redux DevTools) to observe state changes asynchronously."]}),"\n",(0,i.jsx)(n.h4,{id:"why-awaiting-matters-in-net--statepulse",children:"Why Awaiting Matters in .NET / StatePulse"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["The .NET environment encourages ",(0,i.jsx)(n.strong,{children:"step-by-step debugging"}),", which is often the most effective way to diagnose issues."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:".Await()"})," enables this by making the dispatch synchronous from the caller\u2019s perspective."]}),"\n",(0,i.jsxs)(n.li,{children:["This is why it\u2019s ",(0,i.jsx)(n.strong,{children:"important to always await dispatches"})," \u2014 it ensures predictable, debuggable code flow."]}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-csharp",metastring:'title="Counter.razor.cs"',children:"public partial class Counter : ComponentBase\r\n{\r\n [Inject] private IDispatcher Dispatcher { get; set; }\r\n private async Task Increment()\r\n {\r\n await Dispatcher.Prepare()\r\n .With(p => p.Delay, 1)\r\n .Await() // <- Block Execution until all tasks are done.\r\n .DispatchAsync();\r\n }\r\n}\n"})})]})}function d(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>c});var s=t(6540);const i={},r=s.createContext(i);function a(e){const n=s.useContext(r);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/doc/build/assets/js/main.1e4c436b.js b/doc/build/assets/js/main.b1863699.js similarity index 90% rename from doc/build/assets/js/main.1e4c436b.js rename to doc/build/assets/js/main.b1863699.js index 20ddf94..1e28605 100644 --- a/doc/build/assets/js/main.1e4c436b.js +++ b/doc/build/assets/js/main.b1863699.js @@ -1,2 +1,2 @@ -/*! For license information please see main.1e4c436b.js.LICENSE.txt */ -(self.webpackChunkstatepulse_doc=self.webpackChunkstatepulse_doc||[]).push([[8792],{115:e=>{var t="undefined"!=typeof Element,n="function"==typeof Map,r="function"==typeof Set,a="function"==typeof ArrayBuffer&&!!ArrayBuffer.isView;function o(e,i){if(e===i)return!0;if(e&&i&&"object"==typeof e&&"object"==typeof i){if(e.constructor!==i.constructor)return!1;var l,s,u,c;if(Array.isArray(e)){if((l=e.length)!=i.length)return!1;for(s=l;0!==s--;)if(!o(e[s],i[s]))return!1;return!0}if(n&&e instanceof Map&&i instanceof Map){if(e.size!==i.size)return!1;for(c=e.entries();!(s=c.next()).done;)if(!i.has(s.value[0]))return!1;for(c=e.entries();!(s=c.next()).done;)if(!o(s.value[1],i.get(s.value[0])))return!1;return!0}if(r&&e instanceof Set&&i instanceof Set){if(e.size!==i.size)return!1;for(c=e.entries();!(s=c.next()).done;)if(!i.has(s.value[0]))return!1;return!0}if(a&&ArrayBuffer.isView(e)&&ArrayBuffer.isView(i)){if((l=e.length)!=i.length)return!1;for(s=l;0!==s--;)if(e[s]!==i[s])return!1;return!0}if(e.constructor===RegExp)return e.source===i.source&&e.flags===i.flags;if(e.valueOf!==Object.prototype.valueOf&&"function"==typeof e.valueOf&&"function"==typeof i.valueOf)return e.valueOf()===i.valueOf();if(e.toString!==Object.prototype.toString&&"function"==typeof e.toString&&"function"==typeof i.toString)return e.toString()===i.toString();if((l=(u=Object.keys(e)).length)!==Object.keys(i).length)return!1;for(s=l;0!==s--;)if(!Object.prototype.hasOwnProperty.call(i,u[s]))return!1;if(t&&e instanceof Element)return!1;for(s=l;0!==s--;)if(("_owner"!==u[s]&&"__v"!==u[s]&&"__o"!==u[s]||!e.$$typeof)&&!o(e[u[s]],i[u[s]]))return!1;return!0}return e!=e&&i!=i}e.exports=function(e,t){try{return o(e,t)}catch(n){if((n.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw n}}},119:(e,t,n)=>{"use strict";n.r(t)},205:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});var r=n(6540);const a=n(8193).A.canUseDOM?r.useLayoutEffect:r.useEffect},253:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=function e(t){if(t.cause)return[t,...e(t.cause)];return[t]}},311:e=>{"use strict";e.exports=function(e,t,n,r,a,o,i,l){if(!e){var s;if(void 0===t)s=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var u=[n,r,a,o,i,l],c=0;(s=new Error(t.replace(/%s/g,function(){return u[c++]}))).name="Invariant Violation"}throw s.framesToPop=1,s}}},418:(e,t,n)=>{"use strict";n.d(t,{A:()=>r});const r=()=>null},440:(e,t,n)=>{"use strict";t.rA=t.Ks=t.LU=void 0;const r=n(1635);t.LU="__blog-post-container";var a=n(2983);Object.defineProperty(t,"Ks",{enumerable:!0,get:function(){return r.__importDefault(a).default}});var o=n(2566);var i=n(253);Object.defineProperty(t,"rA",{enumerable:!0,get:function(){return i.getErrorCausalChain}})},545:(e,t,n)=>{"use strict";n.d(t,{mg:()=>J,vd:()=>W});var r=n(6540),a=n(5556),o=n.n(a),i=n(115),l=n.n(i),s=n(311),u=n.n(s),c=n(2833),d=n.n(c);function f(){return f=Object.assign||function(e){for(var t=1;t=0||(a[n]=e[n]);return a}var m={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title",FRAGMENT:"Symbol(react.fragment)"},y={rel:["amphtml","canonical","alternate"]},b={type:["application/ld+json"]},v={charset:"",name:["robots","description"],property:["og:type","og:title","og:url","og:image","og:image:alt","og:description","twitter:url","twitter:title","twitter:description","twitter:image","twitter:image:alt","twitter:card","twitter:site"]},w=Object.keys(m).map(function(e){return m[e]}),k={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"},x=Object.keys(k).reduce(function(e,t){return e[k[t]]=t,e},{}),S=function(e,t){for(var n=e.length-1;n>=0;n-=1){var r=e[n];if(Object.prototype.hasOwnProperty.call(r,t))return r[t]}return null},_=function(e){var t=S(e,m.TITLE),n=S(e,"titleTemplate");if(Array.isArray(t)&&(t=t.join("")),n&&t)return n.replace(/%s/g,function(){return t});var r=S(e,"defaultTitle");return t||r||void 0},E=function(e){return S(e,"onChangeClientState")||function(){}},C=function(e,t){return t.filter(function(t){return void 0!==t[e]}).map(function(t){return t[e]}).reduce(function(e,t){return f({},e,t)},{})},A=function(e,t){return t.filter(function(e){return void 0!==e[m.BASE]}).map(function(e){return e[m.BASE]}).reverse().reduce(function(t,n){if(!t.length)for(var r=Object.keys(n),a=0;a/g,">").replace(/"/g,""").replace(/'/g,"'")},F=function(e){return Object.keys(e).reduce(function(t,n){var r=void 0!==e[n]?n+'="'+e[n]+'"':""+n;return t?t+" "+r:r},"")},I=function(e,t){return void 0===t&&(t={}),Object.keys(e).reduce(function(t,n){return t[k[n]||n]=e[n],t},t)},D=function(e,t){return t.map(function(t,n){var a,o=((a={key:n})["data-rh"]=!0,a);return Object.keys(t).forEach(function(e){var n=k[e]||e;"innerHTML"===n||"cssText"===n?o.dangerouslySetInnerHTML={__html:t.innerHTML||t.cssText}:o[n]=t[e]}),r.createElement(e,o)})},M=function(e,t,n){switch(e){case m.TITLE:return{toComponent:function(){return n=t.titleAttributes,(a={key:e=t.title})["data-rh"]=!0,o=I(n,a),[r.createElement(m.TITLE,o,e)];var e,n,a,o},toString:function(){return function(e,t,n,r){var a=F(n),o=P(t);return a?"<"+e+' data-rh="true" '+a+">"+R(o,r)+"":"<"+e+' data-rh="true">'+R(o,r)+""}(e,t.title,t.titleAttributes,n)}};case"bodyAttributes":case"htmlAttributes":return{toComponent:function(){return I(t)},toString:function(){return F(t)}};default:return{toComponent:function(){return D(e,t)},toString:function(){return function(e,t,n){return t.reduce(function(t,r){var a=Object.keys(r).filter(function(e){return!("innerHTML"===e||"cssText"===e)}).reduce(function(e,t){var a=void 0===r[t]?t:t+'="'+R(r[t],n)+'"';return e?e+" "+a:a},""),o=r.innerHTML||r.cssText||"",i=-1===L.indexOf(e);return t+"<"+e+' data-rh="true" '+a+(i?"/>":">"+o+"")},"")}(e,t,n)}}}},z=function(e){var t=e.baseTag,n=e.bodyAttributes,r=e.encode,a=e.htmlAttributes,o=e.noscriptTags,i=e.styleTags,l=e.title,s=void 0===l?"":l,u=e.titleAttributes,c=e.linkTags,d=e.metaTags,f=e.scriptTags,p={toComponent:function(){},toString:function(){return""}};if(e.prioritizeSeoTags){var g=function(e){var t=e.linkTags,n=e.scriptTags,r=e.encode,a=N(e.metaTags,v),o=N(t,y),i=N(n,b);return{priorityMethods:{toComponent:function(){return[].concat(D(m.META,a.priority),D(m.LINK,o.priority),D(m.SCRIPT,i.priority))},toString:function(){return M(m.META,a.priority,r)+" "+M(m.LINK,o.priority,r)+" "+M(m.SCRIPT,i.priority,r)}},metaTags:a.default,linkTags:o.default,scriptTags:i.default}}(e);p=g.priorityMethods,c=g.linkTags,d=g.metaTags,f=g.scriptTags}return{priority:p,base:M(m.BASE,t,r),bodyAttributes:M("bodyAttributes",n,r),htmlAttributes:M("htmlAttributes",a,r),link:M(m.LINK,c,r),meta:M(m.META,d,r),noscript:M(m.NOSCRIPT,o,r),script:M(m.SCRIPT,f,r),style:M(m.STYLE,i,r),title:M(m.TITLE,{title:s,titleAttributes:u},r)}},B=[],$=function(e,t){var n=this;void 0===t&&(t="undefined"!=typeof document),this.instances=[],this.value={setHelmet:function(e){n.context.helmet=e},helmetInstances:{get:function(){return n.canUseDOM?B:n.instances},add:function(e){(n.canUseDOM?B:n.instances).push(e)},remove:function(e){var t=(n.canUseDOM?B:n.instances).indexOf(e);(n.canUseDOM?B:n.instances).splice(t,1)}}},this.context=e,this.canUseDOM=t,t||(e.helmet=z({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}}))},U=r.createContext({}),H=o().shape({setHelmet:o().func,helmetInstances:o().shape({get:o().func,add:o().func,remove:o().func})}),V="undefined"!=typeof document,W=function(e){function t(n){var r;return(r=e.call(this,n)||this).helmetData=new $(r.props.context,t.canUseDOM),r}return p(t,e),t.prototype.render=function(){return r.createElement(U.Provider,{value:this.helmetData.value},this.props.children)},t}(r.Component);W.canUseDOM=V,W.propTypes={context:o().shape({helmet:o().shape()}),children:o().node.isRequired},W.defaultProps={context:{}},W.displayName="HelmetProvider";var q=function(e,t){var n,r=document.head||document.querySelector(m.HEAD),a=r.querySelectorAll(e+"[data-rh]"),o=[].slice.call(a),i=[];return t&&t.length&&t.forEach(function(t){var r=document.createElement(e);for(var a in t)Object.prototype.hasOwnProperty.call(t,a)&&("innerHTML"===a?r.innerHTML=t.innerHTML:"cssText"===a?r.styleSheet?r.styleSheet.cssText=t.cssText:r.appendChild(document.createTextNode(t.cssText)):r.setAttribute(a,void 0===t[a]?"":t[a]));r.setAttribute("data-rh","true"),o.some(function(e,t){return n=t,r.isEqualNode(e)})?o.splice(n,1):i.push(r)}),o.forEach(function(e){return e.parentNode.removeChild(e)}),i.forEach(function(e){return r.appendChild(e)}),{oldTags:o,newTags:i}},G=function(e,t){var n=document.getElementsByTagName(e)[0];if(n){for(var r=n.getAttribute("data-rh"),a=r?r.split(","):[],o=[].concat(a),i=Object.keys(t),l=0;l=0;d-=1)n.removeAttribute(o[d]);a.length===o.length?n.removeAttribute("data-rh"):n.getAttribute("data-rh")!==i.join(",")&&n.setAttribute("data-rh",i.join(","))}},Y=function(e,t){var n=e.baseTag,r=e.htmlAttributes,a=e.linkTags,o=e.metaTags,i=e.noscriptTags,l=e.onChangeClientState,s=e.scriptTags,u=e.styleTags,c=e.title,d=e.titleAttributes;G(m.BODY,e.bodyAttributes),G(m.HTML,r),function(e,t){void 0!==e&&document.title!==e&&(document.title=P(e)),G(m.TITLE,t)}(c,d);var f={baseTag:q(m.BASE,n),linkTags:q(m.LINK,a),metaTags:q(m.META,o),noscriptTags:q(m.NOSCRIPT,i),scriptTags:q(m.SCRIPT,s),styleTags:q(m.STYLE,u)},p={},g={};Object.keys(f).forEach(function(e){var t=f[e],n=t.newTags,r=t.oldTags;n.length&&(p[e]=n),r.length&&(g[e]=f[e].oldTags)}),t&&t(),l(e,p,g)},K=null,Q=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),a=0;a elements are self-closing and can not contain children. Refer to our API for more information.")}},n.flattenArrayTypeChildren=function(e){var t,n=e.child,r=e.arrayTypeChildren;return f({},r,((t={})[n.type]=[].concat(r[n.type]||[],[f({},e.newChildProps,this.mapNestedChildrenToProps(n,e.nestedChildren))]),t))},n.mapObjectTypeChildren=function(e){var t,n,r=e.child,a=e.newProps,o=e.newChildProps,i=e.nestedChildren;switch(r.type){case m.TITLE:return f({},a,((t={})[r.type]=i,t.titleAttributes=f({},o),t));case m.BODY:return f({},a,{bodyAttributes:f({},o)});case m.HTML:return f({},a,{htmlAttributes:f({},o)});default:return f({},a,((n={})[r.type]=f({},o),n))}},n.mapArrayTypeChildrenToProps=function(e,t){var n=f({},t);return Object.keys(e).forEach(function(t){var r;n=f({},n,((r={})[t]=e[t],r))}),n},n.warnOnInvalidChildren=function(e,t){return u()(w.some(function(t){return e.type===t}),"function"==typeof e.type?"You may be attempting to nest components within each other, which is not allowed. Refer to our API for more information.":"Only elements types "+w.join(", ")+" are allowed. Helmet does not support rendering <"+e.type+"> elements. Refer to our API for more information."),u()(!t||"string"==typeof t||Array.isArray(t)&&!t.some(function(e){return"string"!=typeof e}),"Helmet expects a string as a child of <"+e.type+">. Did you forget to wrap your children in braces? ( <"+e.type+">{``} ) Refer to our API for more information."),!0},n.mapChildrenToProps=function(e,t){var n=this,a={};return r.Children.forEach(e,function(e){if(e&&e.props){var r=e.props,o=r.children,i=h(r,Z),l=Object.keys(i).reduce(function(e,t){return e[x[t]||t]=i[t],e},{}),s=e.type;switch("symbol"==typeof s?s=s.toString():n.warnOnInvalidChildren(e,o),s){case m.FRAGMENT:t=n.mapChildrenToProps(o,t);break;case m.LINK:case m.META:case m.NOSCRIPT:case m.SCRIPT:case m.STYLE:a=n.flattenArrayTypeChildren({child:e,arrayTypeChildren:a,newChildProps:l,nestedChildren:o});break;default:t=n.mapObjectTypeChildren({child:e,newProps:t,newChildProps:l,nestedChildren:o})}}}),this.mapArrayTypeChildrenToProps(a,t)},n.render=function(){var e=this.props,t=e.children,n=h(e,X),a=f({},n),o=n.helmetData;return t&&(a=this.mapChildrenToProps(t,a)),!o||o instanceof $||(o=new $(o.context,o.instances)),o?r.createElement(Q,f({},a,{context:o.value,helmetData:void 0})):r.createElement(U.Consumer,null,function(e){return r.createElement(Q,f({},a,{context:e}))})},t}(r.Component);J.propTypes={base:o().object,bodyAttributes:o().object,children:o().oneOfType([o().arrayOf(o().node),o().node]),defaultTitle:o().string,defer:o().bool,encodeSpecialCharacters:o().bool,htmlAttributes:o().object,link:o().arrayOf(o().object),meta:o().arrayOf(o().object),noscript:o().arrayOf(o().object),onChangeClientState:o().func,script:o().arrayOf(o().object),style:o().arrayOf(o().object),title:o().string,titleAttributes:o().object,titleTemplate:o().string,prioritizeSeoTags:o().bool,helmetData:o().object},J.defaultProps={defer:!0,encodeSpecialCharacters:!0,prioritizeSeoTags:!1},J.displayName="Helmet"},609:(e,t,n)=>{"use strict";n.d(t,{V:()=>s,t:()=>u});var r=n(6540),a=n(9532),o=n(4848);const i=Symbol("EmptyContext"),l=r.createContext(i);function s({children:e,name:t,items:n}){const a=(0,r.useMemo)(()=>t&&n?{name:t,items:n}:null,[t,n]);return(0,o.jsx)(l.Provider,{value:a,children:e})}function u(){const e=(0,r.useContext)(l);if(e===i)throw new a.dV("DocsSidebarProvider");return e}},679:(e,t,n)=>{"use strict";n.d(t,{Wf:()=>u});n(6540);const r=JSON.parse('{"N":"localStorage","M":""}'),a=r.N;function o({key:e,oldValue:t,newValue:n,storage:r}){if(t===n)return;const a=document.createEvent("StorageEvent");a.initStorageEvent("storage",!1,!1,e,t,n,window.location.href,r),window.dispatchEvent(a)}function i(e=a){if("undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,l||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),l=!0),null}var t}let l=!1;const s={get:()=>null,set:()=>{},del:()=>{},listen:()=>()=>{}};function u(e,t){const n=`${e}${r.M}`;if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t,listen:t}}(n);const a=i(t?.persistence);return null===a?s:{get:()=>{try{return a.getItem(n)}catch(e){return console.error(`Docusaurus storage error, can't get key=${n}`,e),null}},set:e=>{try{const t=a.getItem(n);a.setItem(n,e),o({key:n,oldValue:t,newValue:e,storage:a})}catch(t){console.error(`Docusaurus storage error, can't set ${n}=${e}`,t)}},del:()=>{try{const e=a.getItem(n);a.removeItem(n),o({key:n,oldValue:e,newValue:null,storage:a})}catch(e){console.error(`Docusaurus storage error, can't delete key=${n}`,e)}},listen:e=>{try{const t=t=>{t.storageArea===a&&t.key===n&&e(t)};return window.addEventListener("storage",t),()=>window.removeEventListener("storage",t)}catch(t){return console.error(`Docusaurus storage error, can't listen for changes of key=${n}`,t),()=>{}}}}}},961:(e,t,n)=>{"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}(),e.exports=n(6221)},1043:(e,t,n)=>{"use strict";n.r(t)},1107:(e,t,n)=>{"use strict";n.d(t,{A:()=>c});n(6540);var r=n(4164),a=n(1312),o=n(6342),i=n(8774),l=n(3427);const s={anchorWithStickyNavbar:"anchorWithStickyNavbar_LWe7",anchorWithHideOnScrollNavbar:"anchorWithHideOnScrollNavbar_WYt5"};var u=n(4848);function c({as:e,id:t,...n}){const c=(0,l.A)(),{navbar:{hideOnScroll:d}}=(0,o.p)();if("h1"===e||!t)return(0,u.jsx)(e,{...n,id:void 0});c.collectAnchor(t);const f=(0,a.T)({id:"theme.common.headingLinkTitle",message:"Direct link to {heading}",description:"Title for link to heading"},{heading:"string"==typeof n.children?n.children:t});return(0,u.jsxs)(e,{...n,className:(0,r.A)("anchor",d?s.anchorWithHideOnScrollNavbar:s.anchorWithStickyNavbar,n.className),id:t,children:[n.children,(0,u.jsx)(i.A,{className:"hash-link",to:`#${t}`,"aria-label":f,title:f,children:"\u200b"})]})}},1122:(e,t,n)=>{"use strict";n.d(t,{A:()=>c});var r=n(6540),a=n(4164),o=n(2303),i=n(5293);const l={themedComponent:"themedComponent_mlkZ","themedComponent--light":"themedComponent--light_NVdE","themedComponent--dark":"themedComponent--dark_xIcU"};var s=n(4848);function u({className:e,children:t}){const n=(0,o.A)(),{colorMode:u}=(0,i.G)();return(0,s.jsx)(s.Fragment,{children:(n?"dark"===u?["dark"]:["light"]:["light","dark"]).map(n=>{const o=t({theme:n,className:(0,a.A)(e,l.themedComponent,l[`themedComponent--${n}`])});return(0,s.jsx)(r.Fragment,{children:o},n)})})}function c(e){const{sources:t,className:n,alt:r,...a}=e;return(0,s.jsx)(u,{className:n,children:({theme:e,className:n})=>(0,s.jsx)("img",{src:t[e],alt:r,className:n,...a})})}},1247:(e,t,n)=>{"use strict";var r=n(9982),a=n(6540),o=n(961);function i(e){var t="https://react.dev/errors/"+e;if(1M||(e.current=D[M],D[M]=null,M--)}function $(e,t){M++,D[M]=e.current,e.current=t}var U=z(null),H=z(null),V=z(null),W=z(null);function q(e,t){switch($(V,t),$(H,e),$(U,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?ad(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)e=od(t=ad(t),e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}B(U),$(U,e)}function G(){B(U),B(H),B(V)}function Y(e){null!==e.memoizedState&&$(W,e);var t=U.current,n=od(t,e.type);t!==n&&($(H,e),$(U,n))}function K(e){H.current===e&&(B(U),B(H)),W.current===e&&(B(W),Yd._currentValue=I)}var Q=Object.prototype.hasOwnProperty,Z=r.unstable_scheduleCallback,X=r.unstable_cancelCallback,J=r.unstable_shouldYield,ee=r.unstable_requestPaint,te=r.unstable_now,ne=r.unstable_getCurrentPriorityLevel,re=r.unstable_ImmediatePriority,ae=r.unstable_UserBlockingPriority,oe=r.unstable_NormalPriority,ie=r.unstable_LowPriority,le=r.unstable_IdlePriority,se=r.log,ue=r.unstable_setDisableYieldValue,ce=null,de=null;function fe(e){if("function"==typeof se&&ue(e),de&&"function"==typeof de.setStrictMode)try{de.setStrictMode(ce,e)}catch(t){}}var pe=Math.clz32?Math.clz32:function(e){return 0===(e>>>=0)?32:31-(ge(e)/he|0)|0},ge=Math.log,he=Math.LN2;var me=256,ye=4194304;function be(e){var t=42&e;if(0!==t)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return 4194048&e;case 4194304:case 8388608:case 16777216:case 33554432:return 62914560&e;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function ve(e,t,n){var r=e.pendingLanes;if(0===r)return 0;var a=0,o=e.suspendedLanes,i=e.pingedLanes;e=e.warmLanes;var l=134217727&r;return 0!==l?0!==(r=l&~o)?a=be(r):0!==(i&=l)?a=be(i):n||0!==(n=l&~e)&&(a=be(n)):0!==(l=r&~o)?a=be(l):0!==i?a=be(i):n||0!==(n=r&~e)&&(a=be(n)),0===a?0:0!==t&&t!==a&&0===(t&o)&&((o=a&-a)>=(n=t&-t)||32===o&&4194048&n)?t:a}function we(e,t){return 0===(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)}function ke(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;default:return-1}}function xe(){var e=me;return!(4194048&(me<<=1))&&(me=256),e}function Se(){var e=ye;return!(62914560&(ye<<=1))&&(ye=4194304),e}function _e(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function Ee(e,t){e.pendingLanes|=t,268435456!==t&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Ce(e,t,n){e.pendingLanes|=t,e.suspendedLanes&=~t;var r=31-pe(t);e.entangledLanes|=t,e.entanglements[r]=1073741824|e.entanglements[r]|4194090&n}function Ae(e,t){var n=e.entangledLanes|=t;for(e=e.entanglements;n;){var r=31-pe(n),a=1<)":-1--a||s[r]!==u[a]){var c="\n"+s[r].replace(" at new "," at ");return e.displayName&&c.includes("")&&(c=c.replace("",e.displayName)),c}}while(1<=r&&0<=a);break}}}finally{ot=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:"")?at(n):""}function lt(e){switch(e.tag){case 26:case 27:case 5:return at(e.type);case 16:return at("Lazy");case 13:return at("Suspense");case 19:return at("SuspenseList");case 0:case 15:return it(e.type,!1);case 11:return it(e.type.render,!1);case 1:return it(e.type,!0);case 31:return at("Activity");default:return""}}function st(e){try{var t="";do{t+=lt(e),e=e.return}while(e);return t}catch(n){return"\nError generating stack: "+n.message+"\n"+n.stack}}function ut(e){switch(typeof e){case"bigint":case"boolean":case"number":case"string":case"undefined":case"object":return e;default:return""}}function ct(e){var t=e.type;return(e=e.nodeName)&&"input"===e.toLowerCase()&&("checkbox"===t||"radio"===t)}function dt(e){e._valueTracker||(e._valueTracker=function(e){var t=ct(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&void 0!==n&&"function"==typeof n.get&&"function"==typeof n.set){var a=n.get,o=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return a.call(this)},set:function(e){r=""+e,o.call(this,e)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(e){r=""+e},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}(e))}function ft(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=ct(e)?e.checked?"true":"false":e.value),(e=r)!==n&&(t.setValue(e),!0)}function pt(e){if(void 0===(e=e||("undefined"!=typeof document?document:void 0)))return null;try{return e.activeElement||e.body}catch(t){return e.body}}var gt=/[\n"\\]/g;function ht(e){return e.replace(gt,function(e){return"\\"+e.charCodeAt(0).toString(16)+" "})}function mt(e,t,n,r,a,o,i,l){e.name="",null!=i&&"function"!=typeof i&&"symbol"!=typeof i&&"boolean"!=typeof i?e.type=i:e.removeAttribute("type"),null!=t?"number"===i?(0===t&&""===e.value||e.value!=t)&&(e.value=""+ut(t)):e.value!==""+ut(t)&&(e.value=""+ut(t)):"submit"!==i&&"reset"!==i||e.removeAttribute("value"),null!=t?bt(e,i,ut(t)):null!=n?bt(e,i,ut(n)):null!=r&&e.removeAttribute("value"),null==a&&null!=o&&(e.defaultChecked=!!o),null!=a&&(e.checked=a&&"function"!=typeof a&&"symbol"!=typeof a),null!=l&&"function"!=typeof l&&"symbol"!=typeof l&&"boolean"!=typeof l?e.name=""+ut(l):e.removeAttribute("name")}function yt(e,t,n,r,a,o,i,l){if(null!=o&&"function"!=typeof o&&"symbol"!=typeof o&&"boolean"!=typeof o&&(e.type=o),null!=t||null!=n){if(("submit"===o||"reset"===o)&&null==t)return;n=null!=n?""+ut(n):"",t=null!=t?""+ut(t):n,l||t===e.value||(e.value=t),e.defaultValue=t}r="function"!=typeof(r=null!=r?r:a)&&"symbol"!=typeof r&&!!r,e.checked=l?e.checked:!!r,e.defaultChecked=!!r,null!=i&&"function"!=typeof i&&"symbol"!=typeof i&&"boolean"!=typeof i&&(e.name=i)}function bt(e,t,n){"number"===t&&pt(e.ownerDocument)===e||e.defaultValue===""+n||(e.defaultValue=""+n)}function vt(e,t,n,r){if(e=e.options,t){t={};for(var a=0;a=Sn),Cn=String.fromCharCode(32),An=!1;function Tn(e,t){switch(e){case"keyup":return-1!==kn.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function jn(e){return"object"==typeof(e=e.detail)&&"data"in e?e.data:null}var Pn=!1;var Nn={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};function On(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return"input"===t?!!Nn[e.type]:"textarea"===t}function Ln(e,t,n,r){Ot?Lt?Lt.push(r):Lt=[r]:Ot=r,0<(t=Vc(t,"onChange")).length&&(n=new Jt("onChange","change",null,n,r),e.push({event:n,listeners:t}))}var Rn=null,Fn=null;function In(e){Ic(e,0)}function Dn(e){if(ft(He(e)))return e}function Mn(e,t){if("change"===e)return t}var zn=!1;if(Mt){var Bn;if(Mt){var $n="oninput"in document;if(!$n){var Un=document.createElement("div");Un.setAttribute("oninput","return;"),$n="function"==typeof Un.oninput}Bn=$n}else Bn=!1;zn=Bn&&(!document.documentMode||9=t)return{node:r,offset:t-e};e=n}e:{for(;r;){if(r.nextSibling){r=r.nextSibling;break e}r=r.parentNode}r=void 0}r=Zn(r)}}function Jn(e,t){return!(!e||!t)&&(e===t||(!e||3!==e.nodeType)&&(t&&3===t.nodeType?Jn(e,t.parentNode):"contains"in e?e.contains(t):!!e.compareDocumentPosition&&!!(16&e.compareDocumentPosition(t))))}function er(e){for(var t=pt((e=null!=e&&null!=e.ownerDocument&&null!=e.ownerDocument.defaultView?e.ownerDocument.defaultView:window).document);t instanceof e.HTMLIFrameElement;){try{var n="string"==typeof t.contentWindow.location.href}catch(r){n=!1}if(!n)break;t=pt((e=t.contentWindow).document)}return t}function tr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&("text"===e.type||"search"===e.type||"tel"===e.type||"url"===e.type||"password"===e.type)||"textarea"===t||"true"===e.contentEditable)}var nr=Mt&&"documentMode"in document&&11>=document.documentMode,rr=null,ar=null,or=null,ir=!1;function lr(e,t,n){var r=n.window===n?n.document:9===n.nodeType?n:n.ownerDocument;ir||null==rr||rr!==pt(r)||("selectionStart"in(r=rr)&&tr(r)?r={start:r.selectionStart,end:r.selectionEnd}:r={anchorNode:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection()).anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset},or&&Qn(or,r)||(or=r,0<(r=Vc(ar,"onSelect")).length&&(t=new Jt("onSelect","select",null,t,n),e.push({event:t,listeners:r}),t.target=rr)))}function sr(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit"+e]="webkit"+t,n["Moz"+e]="moz"+t,n}var ur={animationend:sr("Animation","AnimationEnd"),animationiteration:sr("Animation","AnimationIteration"),animationstart:sr("Animation","AnimationStart"),transitionrun:sr("Transition","TransitionRun"),transitionstart:sr("Transition","TransitionStart"),transitioncancel:sr("Transition","TransitionCancel"),transitionend:sr("Transition","TransitionEnd")},cr={},dr={};function fr(e){if(cr[e])return cr[e];if(!ur[e])return e;var t,n=ur[e];for(t in n)if(n.hasOwnProperty(t)&&t in dr)return cr[e]=n[t];return e}Mt&&(dr=document.createElement("div").style,"AnimationEvent"in window||(delete ur.animationend.animation,delete ur.animationiteration.animation,delete ur.animationstart.animation),"TransitionEvent"in window||delete ur.transitionend.transition);var pr=fr("animationend"),gr=fr("animationiteration"),hr=fr("animationstart"),mr=fr("transitionrun"),yr=fr("transitionstart"),br=fr("transitioncancel"),vr=fr("transitionend"),wr=new Map,kr="abort auxClick beforeToggle cancel canPlay canPlayThrough click close contextMenu copy cut drag dragEnd dragEnter dragExit dragLeave dragOver dragStart drop durationChange emptied encrypted ended error gotPointerCapture input invalid keyDown keyPress keyUp load loadedData loadedMetadata loadStart lostPointerCapture mouseDown mouseMove mouseOut mouseOver mouseUp paste pause play playing pointerCancel pointerDown pointerMove pointerOut pointerOver pointerUp progress rateChange reset resize seeked seeking stalled submit suspend timeUpdate touchCancel touchEnd touchStart volumeChange scroll toggle touchMove waiting wheel".split(" ");function xr(e,t){wr.set(e,t),Ye(t,[e])}kr.push("scrollEnd");var Sr=new WeakMap;function _r(e,t){if("object"==typeof e&&null!==e){var n=Sr.get(e);return void 0!==n?n:(t={value:e,source:t,stack:st(t)},Sr.set(e,t),t)}return{value:e,source:t,stack:st(t)}}var Er=[],Cr=0,Ar=0;function Tr(){for(var e=Cr,t=Ar=Cr=0;t>=i,a-=i,Zr=1<<32-pe(t)+a|n<o?o:8;var i,l,s,u=R.T,c={};R.T=c,$i(e,!1,t,n);try{var d=a(),f=R.S;if(null!==f&&f(c,d),null!==d&&"object"==typeof d&&"function"==typeof d.then)Bi(e,t,(i=r,l=[],s={status:"pending",value:null,reason:null,then:function(e){l.push(e)}},d.then(function(){s.status="fulfilled",s.value=i;for(var e=0;eg?(h=d,d=null):h=d.sibling;var m=p(a,d,l[g],s);if(null===m){null===d&&(d=h);break}e&&d&&null===m.alternate&&t(a,d),i=o(m,i,g),null===c?u=m:c.sibling=m,c=m,d=h}if(g===l.length)return n(a,d),oa&&Jr(a,g),u;if(null===d){for(;gh?(m=g,g=null):m=g.sibling;var v=p(a,g,b.value,u);if(null===v){null===g&&(g=m);break}e&&g&&null===v.alternate&&t(a,g),l=o(v,l,h),null===d?c=v:d.sibling=v,d=v,g=m}if(b.done)return n(a,g),oa&&Jr(a,h),c;if(null===g){for(;!b.done;h++,b=s.next())null!==(b=f(a,b.value,u))&&(l=o(b,l,h),null===d?c=b:d.sibling=b,d=b);return oa&&Jr(a,h),c}for(g=r(g);!b.done;h++,b=s.next())null!==(b=y(g,a,h,b.value,u))&&(e&&null!==b.alternate&&g.delete(null===b.key?h:b.key),l=o(b,l,h),null===d?c=b:d.sibling=b,d=b);return e&&g.forEach(function(e){return t(a,e)}),oa&&Jr(a,h),c}(s,u,c=v.call(c),d)}if("function"==typeof c.then)return b(s,u,Zi(c),d);if(c.$$typeof===k)return b(s,u,Aa(s,c),d);Ji(s,c)}return"string"==typeof c&&""!==c||"number"==typeof c||"bigint"==typeof c?(c=""+c,null!==u&&6===u.tag?(n(s,u.sibling),(d=a(u,c)).return=s,s=d):(n(s,u),(d=Ur(c,s.mode,d)).return=s,s=d),l(s)):n(s,u)}return function(e,t,n,r){try{Qi=0;var a=b(e,t,n,r);return Ki=null,a}catch(i){if(i===Wa||i===Ga)throw i;var o=Ir(29,i,null,e.mode);return o.lanes=r,o.return=e,o}}}var nl=tl(!0),rl=tl(!1),al=z(null),ol=null;function il(e){var t=e.alternate;$(cl,1&cl.current),$(al,e),null===ol&&(null===t||null!==go.current||null!==t.memoizedState)&&(ol=e)}function ll(e){if(22===e.tag){if($(cl,cl.current),$(al,e),null===ol){var t=e.alternate;null!==t&&null!==t.memoizedState&&(ol=e)}}else sl()}function sl(){$(cl,cl.current),$(al,al.current)}function ul(e){B(al),ol===e&&(ol=null),B(cl)}var cl=z(0);function dl(e){for(var t=e;null!==t;){if(13===t.tag){var n=t.memoizedState;if(null!==n&&(null===(n=n.dehydrated)||"$?"===n.data||md(n)))return t}else if(19===t.tag&&void 0!==t.memoizedProps.revealOrder){if(128&t.flags)return t}else if(null!==t.child){t.child.return=t,t=t.child;continue}if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}function fl(e,t,n,r){n=null==(n=n(r,t=e.memoizedState))?t:f({},t,n),e.memoizedState=n,0===e.lanes&&(e.updateQueue.baseState=n)}var pl={enqueueSetState:function(e,t,n){e=e._reactInternals;var r=Ru(),a=ao(r);a.payload=t,null!=n&&(a.callback=n),null!==(t=oo(e,a,r))&&(Iu(t,e,r),io(t,e,r))},enqueueReplaceState:function(e,t,n){e=e._reactInternals;var r=Ru(),a=ao(r);a.tag=1,a.payload=t,null!=n&&(a.callback=n),null!==(t=oo(e,a,r))&&(Iu(t,e,r),io(t,e,r))},enqueueForceUpdate:function(e,t){e=e._reactInternals;var n=Ru(),r=ao(n);r.tag=2,null!=t&&(r.callback=t),null!==(t=oo(e,r,n))&&(Iu(t,e,n),io(t,e,n))}};function gl(e,t,n,r,a,o,i){return"function"==typeof(e=e.stateNode).shouldComponentUpdate?e.shouldComponentUpdate(r,o,i):!t.prototype||!t.prototype.isPureReactComponent||(!Qn(n,r)||!Qn(a,o))}function hl(e,t,n,r){e=t.state,"function"==typeof t.componentWillReceiveProps&&t.componentWillReceiveProps(n,r),"function"==typeof t.UNSAFE_componentWillReceiveProps&&t.UNSAFE_componentWillReceiveProps(n,r),t.state!==e&&pl.enqueueReplaceState(t,t.state,null)}function ml(e,t){var n=t;if("ref"in t)for(var r in n={},t)"ref"!==r&&(n[r]=t[r]);if(e=e.defaultProps)for(var a in n===t&&(n=f({},n)),e)void 0===n[a]&&(n[a]=e[a]);return n}var yl="function"==typeof reportError?reportError:function(e){if("object"==typeof window&&"function"==typeof window.ErrorEvent){var t=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:"object"==typeof e&&null!==e&&"string"==typeof e.message?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if("object"==typeof process&&"function"==typeof process.emit)return void process.emit("uncaughtException",e);console.error(e)};function bl(e){yl(e)}function vl(e){console.error(e)}function wl(e){yl(e)}function kl(e,t){try{(0,e.onUncaughtError)(t.value,{componentStack:t.stack})}catch(n){setTimeout(function(){throw n})}}function xl(e,t,n){try{(0,e.onCaughtError)(n.value,{componentStack:n.stack,errorBoundary:1===t.tag?t.stateNode:null})}catch(r){setTimeout(function(){throw r})}}function Sl(e,t,n){return(n=ao(n)).tag=3,n.payload={element:null},n.callback=function(){kl(e,t)},n}function _l(e){return(e=ao(e)).tag=3,e}function El(e,t,n,r){var a=n.type.getDerivedStateFromError;if("function"==typeof a){var o=r.value;e.payload=function(){return a(o)},e.callback=function(){xl(t,n,r)}}var i=n.stateNode;null!==i&&"function"==typeof i.componentDidCatch&&(e.callback=function(){xl(t,n,r),"function"!=typeof a&&(null===_u?_u=new Set([this]):_u.add(this));var e=r.stack;this.componentDidCatch(r.value,{componentStack:null!==e?e:""})})}var Cl=Error(i(461)),Al=!1;function Tl(e,t,n,r){t.child=null===e?rl(t,null,n,r):nl(t,e.child,n,r)}function jl(e,t,n,r,a){n=n.render;var o=t.ref;if("ref"in r){var i={};for(var l in r)"ref"!==l&&(i[l]=r[l])}else i=r;return Ea(t),r=Oo(e,t,n,i,o,a),l=Io(),null===e||Al?(oa&&l&&ta(t),t.flags|=1,Tl(e,t,r,a),t.child):(Do(e,t,a),Kl(e,t,a))}function Pl(e,t,n,r,a){if(null===e){var o=n.type;return"function"!=typeof o||Dr(o)||void 0!==o.defaultProps||null!==n.compare?((e=Br(n.type,null,r,t,t.mode,a)).ref=t.ref,e.return=t,t.child=e):(t.tag=15,t.type=o,Nl(e,t,o,r,a))}if(o=e.child,!Ql(e,a)){var i=o.memoizedProps;if((n=null!==(n=n.compare)?n:Qn)(i,r)&&e.ref===t.ref)return Kl(e,t,a)}return t.flags|=1,(e=Mr(o,r)).ref=t.ref,e.return=t,t.child=e}function Nl(e,t,n,r,a){if(null!==e){var o=e.memoizedProps;if(Qn(o,r)&&e.ref===t.ref){if(Al=!1,t.pendingProps=r=o,!Ql(e,a))return t.lanes=e.lanes,Kl(e,t,a);131072&e.flags&&(Al=!0)}}return Fl(e,t,n,r,a)}function Ol(e,t,n){var r=t.pendingProps,a=r.children,o=null!==e?e.memoizedState:null;if("hidden"===r.mode){if(128&t.flags){if(r=null!==o?o.baseLanes|n:n,null!==e){for(a=t.child=e.child,o=0;null!==a;)o=o|a.lanes|a.childLanes,a=a.sibling;t.childLanes=o&~r}else t.childLanes=0,t.child=null;return Ll(e,t,r,n)}if(!(536870912&n))return t.lanes=t.childLanes=536870912,Ll(e,t,null!==o?o.baseLanes|n:n,n);t.memoizedState={baseLanes:0,cachePool:null},null!==e&&Ha(0,null!==o?o.cachePool:null),null!==o?mo(t,o):yo(),ll(t)}else null!==o?(Ha(0,o.cachePool),mo(t,o),sl(),t.memoizedState=null):(null!==e&&Ha(0,null),yo(),sl());return Tl(e,t,a,n),t.child}function Ll(e,t,n,r){var a=Ua();return a=null===a?null:{parent:Oa._currentValue,pool:a},t.memoizedState={baseLanes:n,cachePool:a},null!==e&&Ha(0,null),yo(),ll(t),null!==e&&Sa(e,t,r,!0),null}function Rl(e,t){var n=t.ref;if(null===n)null!==e&&null!==e.ref&&(t.flags|=4194816);else{if("function"!=typeof n&&"object"!=typeof n)throw Error(i(284));null!==e&&e.ref===n||(t.flags|=4194816)}}function Fl(e,t,n,r,a){return Ea(t),n=Oo(e,t,n,r,void 0,a),r=Io(),null===e||Al?(oa&&r&&ta(t),t.flags|=1,Tl(e,t,n,a),t.child):(Do(e,t,a),Kl(e,t,a))}function Il(e,t,n,r,a,o){return Ea(t),t.updateQueue=null,n=Ro(t,r,n,a),Lo(e),r=Io(),null===e||Al?(oa&&r&&ta(t),t.flags|=1,Tl(e,t,n,o),t.child):(Do(e,t,o),Kl(e,t,o))}function Dl(e,t,n,r,a){if(Ea(t),null===t.stateNode){var o=Rr,i=n.contextType;"object"==typeof i&&null!==i&&(o=Ca(i)),o=new n(r,o),t.memoizedState=null!==o.state&&void 0!==o.state?o.state:null,o.updater=pl,t.stateNode=o,o._reactInternals=t,(o=t.stateNode).props=r,o.state=t.memoizedState,o.refs={},no(t),i=n.contextType,o.context="object"==typeof i&&null!==i?Ca(i):Rr,o.state=t.memoizedState,"function"==typeof(i=n.getDerivedStateFromProps)&&(fl(t,n,i,r),o.state=t.memoizedState),"function"==typeof n.getDerivedStateFromProps||"function"==typeof o.getSnapshotBeforeUpdate||"function"!=typeof o.UNSAFE_componentWillMount&&"function"!=typeof o.componentWillMount||(i=o.state,"function"==typeof o.componentWillMount&&o.componentWillMount(),"function"==typeof o.UNSAFE_componentWillMount&&o.UNSAFE_componentWillMount(),i!==o.state&&pl.enqueueReplaceState(o,o.state,null),co(t,r,o,a),uo(),o.state=t.memoizedState),"function"==typeof o.componentDidMount&&(t.flags|=4194308),r=!0}else if(null===e){o=t.stateNode;var l=t.memoizedProps,s=ml(n,l);o.props=s;var u=o.context,c=n.contextType;i=Rr,"object"==typeof c&&null!==c&&(i=Ca(c));var d=n.getDerivedStateFromProps;c="function"==typeof d||"function"==typeof o.getSnapshotBeforeUpdate,l=t.pendingProps!==l,c||"function"!=typeof o.UNSAFE_componentWillReceiveProps&&"function"!=typeof o.componentWillReceiveProps||(l||u!==i)&&hl(t,o,r,i),to=!1;var f=t.memoizedState;o.state=f,co(t,r,o,a),uo(),u=t.memoizedState,l||f!==u||to?("function"==typeof d&&(fl(t,n,d,r),u=t.memoizedState),(s=to||gl(t,n,s,r,f,u,i))?(c||"function"!=typeof o.UNSAFE_componentWillMount&&"function"!=typeof o.componentWillMount||("function"==typeof o.componentWillMount&&o.componentWillMount(),"function"==typeof o.UNSAFE_componentWillMount&&o.UNSAFE_componentWillMount()),"function"==typeof o.componentDidMount&&(t.flags|=4194308)):("function"==typeof o.componentDidMount&&(t.flags|=4194308),t.memoizedProps=r,t.memoizedState=u),o.props=r,o.state=u,o.context=i,r=s):("function"==typeof o.componentDidMount&&(t.flags|=4194308),r=!1)}else{o=t.stateNode,ro(e,t),c=ml(n,i=t.memoizedProps),o.props=c,d=t.pendingProps,f=o.context,u=n.contextType,s=Rr,"object"==typeof u&&null!==u&&(s=Ca(u)),(u="function"==typeof(l=n.getDerivedStateFromProps)||"function"==typeof o.getSnapshotBeforeUpdate)||"function"!=typeof o.UNSAFE_componentWillReceiveProps&&"function"!=typeof o.componentWillReceiveProps||(i!==d||f!==s)&&hl(t,o,r,s),to=!1,f=t.memoizedState,o.state=f,co(t,r,o,a),uo();var p=t.memoizedState;i!==d||f!==p||to||null!==e&&null!==e.dependencies&&_a(e.dependencies)?("function"==typeof l&&(fl(t,n,l,r),p=t.memoizedState),(c=to||gl(t,n,c,r,f,p,s)||null!==e&&null!==e.dependencies&&_a(e.dependencies))?(u||"function"!=typeof o.UNSAFE_componentWillUpdate&&"function"!=typeof o.componentWillUpdate||("function"==typeof o.componentWillUpdate&&o.componentWillUpdate(r,p,s),"function"==typeof o.UNSAFE_componentWillUpdate&&o.UNSAFE_componentWillUpdate(r,p,s)),"function"==typeof o.componentDidUpdate&&(t.flags|=4),"function"==typeof o.getSnapshotBeforeUpdate&&(t.flags|=1024)):("function"!=typeof o.componentDidUpdate||i===e.memoizedProps&&f===e.memoizedState||(t.flags|=4),"function"!=typeof o.getSnapshotBeforeUpdate||i===e.memoizedProps&&f===e.memoizedState||(t.flags|=1024),t.memoizedProps=r,t.memoizedState=p),o.props=r,o.state=p,o.context=s,r=c):("function"!=typeof o.componentDidUpdate||i===e.memoizedProps&&f===e.memoizedState||(t.flags|=4),"function"!=typeof o.getSnapshotBeforeUpdate||i===e.memoizedProps&&f===e.memoizedState||(t.flags|=1024),r=!1)}return o=r,Rl(e,t),r=!!(128&t.flags),o||r?(o=t.stateNode,n=r&&"function"!=typeof n.getDerivedStateFromError?null:o.render(),t.flags|=1,null!==e&&r?(t.child=nl(t,e.child,null,a),t.child=nl(t,null,n,a)):Tl(e,t,n,a),t.memoizedState=o.state,e=t.child):e=Kl(e,t,a),e}function Ml(e,t,n,r){return pa(),t.flags|=256,Tl(e,t,n,r),t.child}var zl={dehydrated:null,treeContext:null,retryLane:0,hydrationErrors:null};function Bl(e){return{baseLanes:e,cachePool:Va()}}function $l(e,t,n){return e=null!==e?e.childLanes&~n:0,t&&(e|=mu),e}function Ul(e,t,n){var r,a=t.pendingProps,o=!1,l=!!(128&t.flags);if((r=l)||(r=(null===e||null!==e.memoizedState)&&!!(2&cl.current)),r&&(o=!0,t.flags&=-129),r=!!(32&t.flags),t.flags&=-33,null===e){if(oa){if(o?il(t):sl(),oa){var s,u=aa;if(s=u){e:{for(s=u,u=la;8!==s.nodeType;){if(!u){u=null;break e}if(null===(s=yd(s.nextSibling))){u=null;break e}}u=s}null!==u?(t.memoizedState={dehydrated:u,treeContext:null!==Qr?{id:Zr,overflow:Xr}:null,retryLane:536870912,hydrationErrors:null},(s=Ir(18,null,null,0)).stateNode=u,s.return=t,t.child=s,ra=t,aa=null,s=!0):s=!1}s||ua(t)}if(null!==(u=t.memoizedState)&&null!==(u=u.dehydrated))return md(u)?t.lanes=32:t.lanes=536870912,null;ul(t)}return u=a.children,a=a.fallback,o?(sl(),u=Vl({mode:"hidden",children:u},o=t.mode),a=$r(a,o,n,null),u.return=t,a.return=t,u.sibling=a,t.child=u,(o=t.child).memoizedState=Bl(n),o.childLanes=$l(e,r,n),t.memoizedState=zl,a):(il(t),Hl(t,u))}if(null!==(s=e.memoizedState)&&null!==(u=s.dehydrated)){if(l)256&t.flags?(il(t),t.flags&=-257,t=Wl(e,t,n)):null!==t.memoizedState?(sl(),t.child=e.child,t.flags|=128,t=null):(sl(),o=a.fallback,u=t.mode,a=Vl({mode:"visible",children:a.children},u),(o=$r(o,u,n,null)).flags|=2,a.return=t,o.return=t,a.sibling=o,t.child=a,nl(t,e.child,null,n),(a=t.child).memoizedState=Bl(n),a.childLanes=$l(e,r,n),t.memoizedState=zl,t=o);else if(il(t),md(u)){if(r=u.nextSibling&&u.nextSibling.dataset)var c=r.dgst;r=c,(a=Error(i(419))).stack="",a.digest=r,ha({value:a,source:null,stack:null}),t=Wl(e,t,n)}else if(Al||Sa(e,t,n,!1),r=0!==(n&e.childLanes),Al||r){if(null!==(r=ru)&&(0!==(a=0!==((a=42&(a=n&-n)?1:Te(a))&(r.suspendedLanes|n))?0:a)&&a!==s.retryLane))throw s.retryLane=a,Nr(e,a),Iu(r,e,a),Cl;"$?"===u.data||Gu(),t=Wl(e,t,n)}else"$?"===u.data?(t.flags|=192,t.child=e.child,t=null):(e=s.treeContext,aa=yd(u.nextSibling),ra=t,oa=!0,ia=null,la=!1,null!==e&&(Yr[Kr++]=Zr,Yr[Kr++]=Xr,Yr[Kr++]=Qr,Zr=e.id,Xr=e.overflow,Qr=t),(t=Hl(t,a.children)).flags|=4096);return t}return o?(sl(),o=a.fallback,u=t.mode,c=(s=e.child).sibling,(a=Mr(s,{mode:"hidden",children:a.children})).subtreeFlags=65011712&s.subtreeFlags,null!==c?o=Mr(c,o):(o=$r(o,u,n,null)).flags|=2,o.return=t,a.return=t,a.sibling=o,t.child=a,a=o,o=t.child,null===(u=e.child.memoizedState)?u=Bl(n):(null!==(s=u.cachePool)?(c=Oa._currentValue,s=s.parent!==c?{parent:c,pool:c}:s):s=Va(),u={baseLanes:u.baseLanes|n,cachePool:s}),o.memoizedState=u,o.childLanes=$l(e,r,n),t.memoizedState=zl,a):(il(t),e=(n=e.child).sibling,(n=Mr(n,{mode:"visible",children:a.children})).return=t,n.sibling=null,null!==e&&(null===(r=t.deletions)?(t.deletions=[e],t.flags|=16):r.push(e)),t.child=n,t.memoizedState=null,n)}function Hl(e,t){return(t=Vl({mode:"visible",children:t},e.mode)).return=e,e.child=t}function Vl(e,t){return(e=Ir(22,e,null,t)).lanes=0,e.stateNode={_visibility:1,_pendingMarkers:null,_retryCache:null,_transitions:null},e}function Wl(e,t,n){return nl(t,e.child,null,n),(e=Hl(t,t.pendingProps.children)).flags|=2,t.memoizedState=null,e}function ql(e,t,n){e.lanes|=t;var r=e.alternate;null!==r&&(r.lanes|=t),ka(e.return,t,n)}function Gl(e,t,n,r,a){var o=e.memoizedState;null===o?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:r,tail:n,tailMode:a}:(o.isBackwards=t,o.rendering=null,o.renderingStartTime=0,o.last=r,o.tail=n,o.tailMode=a)}function Yl(e,t,n){var r=t.pendingProps,a=r.revealOrder,o=r.tail;if(Tl(e,t,r.children,n),2&(r=cl.current))r=1&r|2,t.flags|=128;else{if(null!==e&&128&e.flags)e:for(e=t.child;null!==e;){if(13===e.tag)null!==e.memoizedState&&ql(e,n,t);else if(19===e.tag)ql(e,n,t);else if(null!==e.child){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;null===e.sibling;){if(null===e.return||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}switch($(cl,r),a){case"forwards":for(n=t.child,a=null;null!==n;)null!==(e=n.alternate)&&null===dl(e)&&(a=n),n=n.sibling;null===(n=a)?(a=t.child,t.child=null):(a=n.sibling,n.sibling=null),Gl(t,!1,a,n,o);break;case"backwards":for(n=null,a=t.child,t.child=null;null!==a;){if(null!==(e=a.alternate)&&null===dl(e)){t.child=a;break}e=a.sibling,a.sibling=n,n=a,a=e}Gl(t,!0,n,null,o);break;case"together":Gl(t,!1,null,null,void 0);break;default:t.memoizedState=null}return t.child}function Kl(e,t,n){if(null!==e&&(t.dependencies=e.dependencies),pu|=t.lanes,0===(n&t.childLanes)){if(null===e)return null;if(Sa(e,t,n,!1),0===(n&t.childLanes))return null}if(null!==e&&t.child!==e.child)throw Error(i(153));if(null!==t.child){for(n=Mr(e=t.child,e.pendingProps),t.child=n,n.return=t;null!==e.sibling;)e=e.sibling,(n=n.sibling=Mr(e,e.pendingProps)).return=t;n.sibling=null}return t.child}function Ql(e,t){return 0!==(e.lanes&t)||!(null===(e=e.dependencies)||!_a(e))}function Zl(e,t,n){if(null!==e)if(e.memoizedProps!==t.pendingProps)Al=!0;else{if(!(Ql(e,n)||128&t.flags))return Al=!1,function(e,t,n){switch(t.tag){case 3:q(t,t.stateNode.containerInfo),va(0,Oa,e.memoizedState.cache),pa();break;case 27:case 5:Y(t);break;case 4:q(t,t.stateNode.containerInfo);break;case 10:va(0,t.type,t.memoizedProps.value);break;case 13:var r=t.memoizedState;if(null!==r)return null!==r.dehydrated?(il(t),t.flags|=128,null):0!==(n&t.child.childLanes)?Ul(e,t,n):(il(t),null!==(e=Kl(e,t,n))?e.sibling:null);il(t);break;case 19:var a=!!(128&e.flags);if((r=0!==(n&t.childLanes))||(Sa(e,t,n,!1),r=0!==(n&t.childLanes)),a){if(r)return Yl(e,t,n);t.flags|=128}if(null!==(a=t.memoizedState)&&(a.rendering=null,a.tail=null,a.lastEffect=null),$(cl,cl.current),r)break;return null;case 22:case 23:return t.lanes=0,Ol(e,t,n);case 24:va(0,Oa,e.memoizedState.cache)}return Kl(e,t,n)}(e,t,n);Al=!!(131072&e.flags)}else Al=!1,oa&&1048576&t.flags&&ea(t,Gr,t.index);switch(t.lanes=0,t.tag){case 16:e:{e=t.pendingProps;var r=t.elementType,a=r._init;if(r=a(r._payload),t.type=r,"function"!=typeof r){if(null!=r){if((a=r.$$typeof)===x){t.tag=11,t=jl(null,t,r,e,n);break e}if(a===E){t.tag=14,t=Pl(null,t,r,e,n);break e}}throw t=O(r)||r,Error(i(306,t,""))}Dr(r)?(e=ml(r,e),t.tag=1,t=Dl(null,t,r,e,n)):(t.tag=0,t=Fl(null,t,r,e,n))}return t;case 0:return Fl(e,t,t.type,t.pendingProps,n);case 1:return Dl(e,t,r=t.type,a=ml(r,t.pendingProps),n);case 3:e:{if(q(t,t.stateNode.containerInfo),null===e)throw Error(i(387));r=t.pendingProps;var o=t.memoizedState;a=o.element,ro(e,t),co(t,r,null,n);var l=t.memoizedState;if(r=l.cache,va(0,Oa,r),r!==o.cache&&xa(t,[Oa],n,!0),uo(),r=l.element,o.isDehydrated){if(o={element:r,isDehydrated:!1,cache:l.cache},t.updateQueue.baseState=o,t.memoizedState=o,256&t.flags){t=Ml(e,t,r,n);break e}if(r!==a){ha(a=_r(Error(i(424)),t)),t=Ml(e,t,r,n);break e}if(9===(e=t.stateNode.containerInfo).nodeType)e=e.body;else e="HTML"===e.nodeName?e.ownerDocument.body:e;for(aa=yd(e.firstChild),ra=t,oa=!0,ia=null,la=!0,n=rl(t,null,r,n),t.child=n;n;)n.flags=-3&n.flags|4096,n=n.sibling}else{if(pa(),r===a){t=Kl(e,t,n);break e}Tl(e,t,r,n)}t=t.child}return t;case 26:return Rl(e,t),null===e?(n=Td(t.type,null,t.pendingProps,null))?t.memoizedState=n:oa||(n=t.type,e=t.pendingProps,(r=rd(V.current).createElement(n))[Oe]=t,r[Le]=e,ed(r,n,e),We(r),t.stateNode=r):t.memoizedState=Td(t.type,e.memoizedProps,t.pendingProps,e.memoizedState),null;case 27:return Y(t),null===e&&oa&&(r=t.stateNode=wd(t.type,t.pendingProps,V.current),ra=t,la=!0,a=aa,pd(t.type)?(bd=a,aa=yd(r.firstChild)):aa=a),Tl(e,t,t.pendingProps.children,n),Rl(e,t),null===e&&(t.flags|=4194304),t.child;case 5:return null===e&&oa&&((a=r=aa)&&(null!==(r=function(e,t,n,r){for(;1===e.nodeType;){var a=n;if(e.nodeName.toLowerCase()!==t.toLowerCase()){if(!r&&("INPUT"!==e.nodeName||"hidden"!==e.type))break}else if(r){if(!e[ze])switch(t){case"meta":if(!e.hasAttribute("itemprop"))break;return e;case"link":if("stylesheet"===(o=e.getAttribute("rel"))&&e.hasAttribute("data-precedence"))break;if(o!==a.rel||e.getAttribute("href")!==(null==a.href||""===a.href?null:a.href)||e.getAttribute("crossorigin")!==(null==a.crossOrigin?null:a.crossOrigin)||e.getAttribute("title")!==(null==a.title?null:a.title))break;return e;case"style":if(e.hasAttribute("data-precedence"))break;return e;case"script":if(((o=e.getAttribute("src"))!==(null==a.src?null:a.src)||e.getAttribute("type")!==(null==a.type?null:a.type)||e.getAttribute("crossorigin")!==(null==a.crossOrigin?null:a.crossOrigin))&&o&&e.hasAttribute("async")&&!e.hasAttribute("itemprop"))break;return e;default:return e}}else{if("input"!==t||"hidden"!==e.type)return e;var o=null==a.name?null:""+a.name;if("hidden"===a.type&&e.getAttribute("name")===o)return e}if(null===(e=yd(e.nextSibling)))break}return null}(r,t.type,t.pendingProps,la))?(t.stateNode=r,ra=t,aa=yd(r.firstChild),la=!1,a=!0):a=!1),a||ua(t)),Y(t),a=t.type,o=t.pendingProps,l=null!==e?e.memoizedProps:null,r=o.children,id(a,o)?r=null:null!==l&&id(a,l)&&(t.flags|=32),null!==t.memoizedState&&(a=Oo(e,t,Fo,null,null,n),Yd._currentValue=a),Rl(e,t),Tl(e,t,r,n),t.child;case 6:return null===e&&oa&&((e=n=aa)&&(null!==(n=function(e,t,n){if(""===t)return null;for(;3!==e.nodeType;){if((1!==e.nodeType||"INPUT"!==e.nodeName||"hidden"!==e.type)&&!n)return null;if(null===(e=yd(e.nextSibling)))return null}return e}(n,t.pendingProps,la))?(t.stateNode=n,ra=t,aa=null,e=!0):e=!1),e||ua(t)),null;case 13:return Ul(e,t,n);case 4:return q(t,t.stateNode.containerInfo),r=t.pendingProps,null===e?t.child=nl(t,null,r,n):Tl(e,t,r,n),t.child;case 11:return jl(e,t,t.type,t.pendingProps,n);case 7:return Tl(e,t,t.pendingProps,n),t.child;case 8:case 12:return Tl(e,t,t.pendingProps.children,n),t.child;case 10:return r=t.pendingProps,va(0,t.type,r.value),Tl(e,t,r.children,n),t.child;case 9:return a=t.type._context,r=t.pendingProps.children,Ea(t),r=r(a=Ca(a)),t.flags|=1,Tl(e,t,r,n),t.child;case 14:return Pl(e,t,t.type,t.pendingProps,n);case 15:return Nl(e,t,t.type,t.pendingProps,n);case 19:return Yl(e,t,n);case 31:return r=t.pendingProps,n=t.mode,r={mode:r.mode,children:r.children},null===e?((n=Vl(r,n)).ref=t.ref,t.child=n,n.return=t,t=n):((n=Mr(e.child,r)).ref=t.ref,t.child=n,n.return=t,t=n),t;case 22:return Ol(e,t,n);case 24:return Ea(t),r=Ca(Oa),null===e?(null===(a=Ua())&&(a=ru,o=La(),a.pooledCache=o,o.refCount++,null!==o&&(a.pooledCacheLanes|=n),a=o),t.memoizedState={parent:r,cache:a},no(t),va(0,Oa,a)):(0!==(e.lanes&n)&&(ro(e,t),co(t,null,null,n),uo()),a=e.memoizedState,o=t.memoizedState,a.parent!==r?(a={parent:r,cache:r},t.memoizedState=a,0===t.lanes&&(t.memoizedState=t.updateQueue.baseState=a),va(0,Oa,r)):(r=o.cache,va(0,Oa,r),r!==a.cache&&xa(t,[Oa],n,!0))),Tl(e,t,t.pendingProps.children,n),t.child;case 29:throw t.pendingProps}throw Error(i(156,t.tag))}function Xl(e){e.flags|=4}function Jl(e,t){if("stylesheet"!==t.type||4&t.state.loading)e.flags&=-16777217;else if(e.flags|=16777216,!$d(t)){if(null!==(t=al.current)&&((4194048&ou)===ou?null!==ol:(62914560&ou)!==ou&&!(536870912&ou)||t!==ol))throw Xa=Ya,qa;e.flags|=8192}}function es(e,t){null!==t&&(e.flags|=4),16384&e.flags&&(t=22!==e.tag?Se():536870912,e.lanes|=t,yu|=t)}function ts(e,t){if(!oa)switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;null!==t;)null!==t.alternate&&(n=t),t=t.sibling;null===n?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var r=null;null!==n;)null!==n.alternate&&(r=n),n=n.sibling;null===r?t||null===e.tail?e.tail=null:e.tail.sibling=null:r.sibling=null}}function ns(e){var t=null!==e.alternate&&e.alternate.child===e.child,n=0,r=0;if(t)for(var a=e.child;null!==a;)n|=a.lanes|a.childLanes,r|=65011712&a.subtreeFlags,r|=65011712&a.flags,a.return=e,a=a.sibling;else for(a=e.child;null!==a;)n|=a.lanes|a.childLanes,r|=a.subtreeFlags,r|=a.flags,a.return=e,a=a.sibling;return e.subtreeFlags|=r,e.childLanes=n,t}function rs(e,t,n){var r=t.pendingProps;switch(na(t),t.tag){case 31:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:case 1:return ns(t),null;case 3:return n=t.stateNode,r=null,null!==e&&(r=e.memoizedState.cache),t.memoizedState.cache!==r&&(t.flags|=2048),wa(Oa),G(),n.pendingContext&&(n.context=n.pendingContext,n.pendingContext=null),null!==e&&null!==e.child||(fa(t)?Xl(t):null===e||e.memoizedState.isDehydrated&&!(256&t.flags)||(t.flags|=1024,ga())),ns(t),null;case 26:return n=t.memoizedState,null===e?(Xl(t),null!==n?(ns(t),Jl(t,n)):(ns(t),t.flags&=-16777217)):n?n!==e.memoizedState?(Xl(t),ns(t),Jl(t,n)):(ns(t),t.flags&=-16777217):(e.memoizedProps!==r&&Xl(t),ns(t),t.flags&=-16777217),null;case 27:K(t),n=V.current;var a=t.type;if(null!==e&&null!=t.stateNode)e.memoizedProps!==r&&Xl(t);else{if(!r){if(null===t.stateNode)throw Error(i(166));return ns(t),null}e=U.current,fa(t)?ca(t):(e=wd(a,r,n),t.stateNode=e,Xl(t))}return ns(t),null;case 5:if(K(t),n=t.type,null!==e&&null!=t.stateNode)e.memoizedProps!==r&&Xl(t);else{if(!r){if(null===t.stateNode)throw Error(i(166));return ns(t),null}if(e=U.current,fa(t))ca(t);else{switch(a=rd(V.current),e){case 1:e=a.createElementNS("http://www.w3.org/2000/svg",n);break;case 2:e=a.createElementNS("http://www.w3.org/1998/Math/MathML",n);break;default:switch(n){case"svg":e=a.createElementNS("http://www.w3.org/2000/svg",n);break;case"math":e=a.createElementNS("http://www.w3.org/1998/Math/MathML",n);break;case"script":(e=a.createElement("div")).innerHTML=" - + + - + \ No newline at end of file diff --git a/doc/build/blog/authors/index.html b/doc/build/blog/authors/index.html index 87fc766..291a341 100644 --- a/doc/build/blog/authors/index.html +++ b/doc/build/blog/authors/index.html @@ -5,13 +5,13 @@ Authors | StatePulse.NET - - + + -

    Authors

    +

    Authors

    \ No newline at end of file diff --git a/doc/build/blog/authors/mshimshon/index.html b/doc/build/blog/authors/mshimshon/index.html index 87e829d..59c620d 100644 --- a/doc/build/blog/authors/mshimshon/index.html +++ b/doc/build/blog/authors/mshimshon/index.html @@ -5,13 +5,13 @@ Maksim Shimshon - One post | StatePulse.NET - - + + -
    Maksim Shimshon
    CTO of MiniChemist Technologies, Inc. .NET Veteran.
    View all authors

    +
    Maksim Shimshon
    CTO of MiniChemist Technologies, Inc. .NET Veteran.
    View all authors

    \ No newline at end of file diff --git a/doc/build/blog/first-blog-post/index.html b/doc/build/blog/first-blog-post/index.html index 2cb4cc7..244a894 100644 --- a/doc/build/blog/first-blog-post/index.html +++ b/doc/build/blog/first-blog-post/index.html @@ -5,14 +5,14 @@ First Blog Post | StatePulse.NET - - + +

    First Blog Post

    Β· One min read
    Maksim Shimshon
    CTO of MiniChemist Technologies, Inc. .NET Veteran.

    Lorem ipsum dolor sit amet...

    -

    ...consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

    +

    ...consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

    \ No newline at end of file diff --git a/doc/build/blog/index.html b/doc/build/blog/index.html index 473bc0d..9e18e68 100644 --- a/doc/build/blog/index.html +++ b/doc/build/blog/index.html @@ -5,13 +5,13 @@ Blog | StatePulse.NET - - + + -
    +
    \ No newline at end of file diff --git a/doc/build/blog/tags/docusaurus/index.html b/doc/build/blog/tags/docusaurus/index.html index c2c7609..d3ecab3 100644 --- a/doc/build/blog/tags/docusaurus/index.html +++ b/doc/build/blog/tags/docusaurus/index.html @@ -5,13 +5,13 @@ One post tagged with "Docusaurus" | StatePulse.NET - - + + -

    One post tagged with "Docusaurus"

    Docusaurus tag description

    View All Tags
    +

    One post tagged with "Docusaurus"

    Docusaurus tag description

    View All Tags
    \ No newline at end of file diff --git a/doc/build/blog/tags/hola/index.html b/doc/build/blog/tags/hola/index.html index 8d11261..51129cf 100644 --- a/doc/build/blog/tags/hola/index.html +++ b/doc/build/blog/tags/hola/index.html @@ -5,13 +5,13 @@ One post tagged with "Hola" | StatePulse.NET - - + + -

    One post tagged with "Hola"

    Hola tag description

    View All Tags
    +

    One post tagged with "Hola"

    Hola tag description

    View All Tags
    \ No newline at end of file diff --git a/doc/build/blog/tags/index.html b/doc/build/blog/tags/index.html index 0c1753c..581dc9a 100644 --- a/doc/build/blog/tags/index.html +++ b/doc/build/blog/tags/index.html @@ -5,13 +5,13 @@ Tags | StatePulse.NET - - + + - + \ No newline at end of file diff --git a/doc/build/gs-state/index.html b/doc/build/gs-state/index.html index 77922e2..09c9a22 100644 --- a/doc/build/gs-state/index.html +++ b/doc/build/gs-state/index.html @@ -5,8 +5,8 @@ The States | StatePulse.NET - - + + @@ -51,22 +51,23 @@

    πŸ› οΈ Example: Zero-Boilerplate State Hook​

    -
    Counter.razor.cs
    public partial class Counter : ComponentBase
    {
    [Inject] IStatePulse Pulse { get; set; }
    private CounterState State => Pulse.StateOf<CounterState>(() => this, ShouldUpdate);
    [Inject] private IDispatcher Dispatcher { get; set; }
    public Task ShouldUpdate() => InvokeAsync(StateHasChanged);
    private async Task Increment()
    {
    await Dispatcher.Prepare<IncrementCounterAction>()
    .With(p => p.Delay, 1)
    .DispatchAsync();
    }
    }
    +
    Counter.razor.cs
    public partial class Counter : ComponentBase
    {
    [Inject] IStatePulse Pulse { get; set; }
    private CounterState State => Pulse.StateOf<CounterState>(() => this, ShouldUpdate);
    public Task ShouldUpdate() => InvokeAsync(StateHasChanged);
    private async Task Increment()
    {
    await Pulse.Dispatcher.Prepare<IncrementCounterAction>()
    .With(p => p.Delay, 1)
    .DispatchAsync();
    }
    }
    +

    Note: when injecting IStatePulse, you do not need to inject IDispatcher.

    πŸ“ Note on StateOf() Usage

    You might notice that Pulse.StateOf<CounterState>(() => this, ShouldUpdate) is called during every render.
    -At first glance, this may seem inefficient β€” but it’s actually intentional and necessary.

    -

    This method guarantees that the component is correctly bound to the state and always get latest state.
    -Without using this shorthand, you’d be forced to call StateOf(...).Property directly in your Razor markup, which becomes less readable and harder to maintain.

    +At first glance, this may seem inefficient or even odd syntax but it’s actually intentional, efficient and necessary.

    When StateOf() is called:

    • StatePulse checks whether the component (identified by ()=> this) is already being tracked.
    • -
    • If not, it sets up the binding and associates the provided ShouldUpdate method as a re-render callback.
    • -
    • If it is already tracked, the call becomes a fast property access with near-zero overhead.
    • +
    • If not, it sets up the binding and associates the provided ShouldUpdate method as a re-render callback (Slow first hit).
    • +
    • If it is already tracked, the call becomes a fast property access with near-zero overhead (subsequent accesses are fast).
    -

    ⚑ The only cost is during the initial setup.
    -All future calls are optimized and safe to run on every render.

    -

    This design ensures you always have up-to-date, reactive state with no boilerplate and minimal performance impact.

    +

    Mandatory Syntax +As of v2.0+ compiler will generate an error when ()=> this is not exactly that and when ShouldUpdate is a lambda which is forbidden and has to be named method to avoid runtime issues.

    +

    The only cost is during the initial setup.
    +All future calls are optimized, cached and safe to run on every render, on every line.

    +

    This design ensures you always have up-to-date, reactive state with no boilerplate and minimal performance impact.

    \ No newline at end of file diff --git a/doc/build/gs-the-action/index.html b/doc/build/gs-the-action/index.html index 65117e2..5708494 100644 --- a/doc/build/gs-the-action/index.html +++ b/doc/build/gs-the-action/index.html @@ -5,8 +5,8 @@ The Actions | StatePulse.NET - - + + @@ -49,6 +49,6 @@

    +

    Use it only when necessary, especially for actions where result timing and state consistency matter (like network requests).

    \ No newline at end of file diff --git a/doc/build/gs-the-dispatcher/index.html b/doc/build/gs-the-dispatcher/index.html index 5249f85..9b13442 100644 --- a/doc/build/gs-the-dispatcher/index.html +++ b/doc/build/gs-the-dispatcher/index.html @@ -1,12 +1,12 @@ - + The Dispatcher | StatePulse.NET - - + + @@ -84,6 +84,6 @@

    Counter.razor.cs
    public partial class Counter : ComponentBase
    {
    [Inject] private IDispatcher Dispatcher { get; set; }
    private async Task Increment()
    {
    await Dispatcher.Prepare<IncrementCounterAction>()
    .With(p => p.Delay, 1)
    .Await() // <- Block Execution until all tasks are done.
    .DispatchAsync();
    }
    }
    +
    Counter.razor.cs
    public partial class Counter : ComponentBase
    {
    [Inject] private IDispatcher Dispatcher { get; set; }
    private async Task Increment()
    {
    await Dispatcher.Prepare<IncrementCounterAction>()
    .With(p => p.Delay, 1)
    .Await() // <- Block Execution until all tasks are done.
    .DispatchAsync();
    }
    }
    \ No newline at end of file diff --git a/doc/build/gs-the-effect/index.html b/doc/build/gs-the-effect/index.html index eaa193e..4e476ed 100644 --- a/doc/build/gs-the-effect/index.html +++ b/doc/build/gs-the-effect/index.html @@ -5,8 +5,8 @@ The Effects | StatePulse.NET - - + + @@ -56,6 +56,22 @@

    Benefits
    IncrementEffectValidator.cs
    internal class IncrementEffectValidator : IEffectValidator<IncrementCounterAction, IncrementCounterEffect>
    {
    public Task<bool> Validate(IncrementCounterAction action)
    {
    if (action.Delay > 1000) return Task.FromResult(false);
    return Task.FromResult(true);
    }
    }

    +
    IncrementEffectValidator.cs
    internal class IncrementEffectValidator : IEffectValidator<IncrementCounterAction, IncrementCounterEffect>
    {
    public Task<bool> Validate(IncrementCounterAction action)
    {
    if (action.Delay > 1000) return Task.FromResult(false);
    return Task.FromResult(true);
    }
    }

    +

    βš™οΈ What are Effect Middlewares?​

    +

    StatePulse uses middleware interfaces to tap into the lifecycle of effects, reducers, and dispatches.
    +These middleware hooks are useful for logging, metrics, analytics, or debugging β€” but should never alter behavior or mutate state.

    +
    +

    ❗ Middleware is observational only β€” do not use it to change logic or outcomes.

    +
    +

    IEffectMiddleware allows you to hook into the execution of any effect.

    +

    Available Hooks​

    +
      +
    • BeforeEffect(object action) – called before the effects run
    • +
    • AfterEffect(object action) – called after the effects completed
    • +
    • WhenEffectValidationFailed(object action, object effectValidator) – called when a validator fails.
    • +
    • WhenEffectValidationSucceed(object action, object effectValidator) – called when a validator passes
    • +
    +

    Example: Effect Middleware​

    +
    LoggingMiddleware.cs
    internal class LoggingMiddleware : IEffectMiddleware
    {
    private readonly ILogger _logger;

    public LoggingMiddleware(ILogger<LoggingMiddleware> logger)
    {
    _logger = logger;
    }
    public Task AfterEffect(object action)
    {
    string message = $"{action.GetType()} finished execution.";
    _logger.LogDebug(message);
    return Task.CompletedTask;
    }
    public Task BeforeEffect(object action) => Task.CompletedTask;
    public Task WhenEffectValidationFailed(object action, object effectValidator) => Task.CompletedTask;
    public Task WhenEffectValidationSucceed(object action, object effectValidator) => Task.CompletedTask;
    }

    \ No newline at end of file diff --git a/doc/build/gs-the-middlewares/index.html b/doc/build/gs-the-middlewares/index.html index e6e7b5a..28bc9ac 100644 --- a/doc/build/gs-the-middlewares/index.html +++ b/doc/build/gs-the-middlewares/index.html @@ -5,8 +5,8 @@ The Middlewares | StatePulse.NET - - + + @@ -50,6 +50,6 @@

    🧼 Use CasesπŸ“Š Tracking user behavior
  • ⏱️ Measuring performance metrics
  • πŸ“ˆ Collecting analytics without mutating state or logic
  • -
    +
    \ No newline at end of file diff --git a/doc/build/gs-the-reducer/index.html b/doc/build/gs-the-reducer/index.html index e25b822..099a434 100644 --- a/doc/build/gs-the-reducer/index.html +++ b/doc/build/gs-the-reducer/index.html @@ -5,8 +5,8 @@ The Reducers | StatePulse.NET - - + + @@ -24,6 +24,20 @@

    ✨ Key Prin

    🚫 Async Tips​

    Reducers may return Task<TState>, but should avoid unnecessary await.

    -
    IncrementReducer.cs
    internal class IncrementReducer : IReducer<CounterState, IncrementCounterResultAction>
    {
    public Task<CounterState> ReduceAsync(CounterState state, IncrementCounterResultAction action)
    => Task.FromResult(state with
    {
    Count = action.Count
    });
    }
    +
    IncrementReducer.cs
    internal class IncrementReducer : IReducer<CounterState, IncrementCounterResultAction>
    {
    public Task<CounterState> ReduceAsync(CounterState state, IncrementCounterResultAction action)
    => Task.FromResult(state with
    {
    Count = action.Count
    });
    }
    +

    βš™οΈ What are Reducer Middlewares?​

    +

    StatePulse uses middleware interfaces to tap into the lifecycle of effects, reducers, and dispatches.
    +These middleware hooks are useful for logging, metrics, analytics, or debugging β€” but should never alter behavior or mutate state.

    +
    +

    ❗ Middleware is observational only β€” do not use it to change logic or outcomes.

    +
    +

    IReducerMiddleware allows you to hook into the execution of any effect.

    +

    Available Hooks​

    +
      +
    • BeforeReducing(object state, object action) – called before the reducer runs
    • +
    • AfterReducing(object state, object action) – called after the reducer runs
    • +
    +

    Example: Reducer Middleware​

    +
    LoggingReducerMiddleware.cs
    internal class LoggingReducerMiddleware : IReducerMiddleware
    {
    public Task AfterReducing(object state, object action)
    {
    Console.WriteLine($"{action.GetType().Name} Executed.");
    return Task.CompletedTask;
    }

    public Task BeforeReducing(object state, object action)
    {
    Console.WriteLine($"{state.GetType().Name} {action.GetType().Name} Executed.");
    return Task.CompletedTask;
    }
    }
    \ No newline at end of file diff --git a/doc/build/index.html b/doc/build/index.html index c4c1f2f..ff6014b 100644 --- a/doc/build/index.html +++ b/doc/build/index.html @@ -5,8 +5,8 @@ Get Started | StatePulse.NET - - + + @@ -14,21 +14,35 @@

    License: MIT NuGet Version -

    + +Build +Deploy

    StatePulse.NET

    Official Documentation​

    -

    StatePulse.NET is a precision-tuned state and action management system that balances high-performance fire-and-forget operations with optional, internally controlled execution order when explicitly required. -It enables anti-duplication chaining for critical flows, preventing race conditions and ensuring consistent outcomes even under rapid user input or concurrent triggers. -Its internal tracking infrastructure provides near-zero overhead cancellation and dispatch control, drastically reducing inconsistency. -At the same time, it preserves the flexibility of traditional untracked state management, letting developers selectively enforce order and reliability without compromising overall responsiveness or introducing global locks.

    -

    ✨ Features​

    -
      -
    • ⚑ Fast Fire-and-Forget β€” Executes actions immediately even tracked action are fire-and-forget.
    • -
    • πŸ›‘ Anti-Duplicate Dispatching β€” Prevents redundant or overlapping actions that can cause race condition state inconsistency.
    • -
    • πŸ” Effect Validator System β€” Supports multiple effect validators for modular and reusable rule enforcement.
    • -
    • πŸ§ͺ Synchronous Debug Mode β€” Optional lockstep mode for testing, diagnostics, and Task.WhenAll pipelines.
    • -
    • 🧡 DispatchTracker β€” High-performance cancellation and deduplication logic via optimized concurrent tracking.
    • -
    +

    StatePulse.NET is a precision‑engineered state and action management system designed for high‑performance fire‑and‑yield workflows. It supports optional, internally controlled execution ordering when deterministic sequencing is explicitly required. +Its multi‑layer anti‑duplication pipeline eliminates redundant dispatches, prevents race conditions, and maintains consistent outcomes even under rapid input or concurrent triggers. +A lightweight internal tracking core provides near‑zero‑overhead cancellation and dispatch control, minimizing inconsistency without sacrificing throughput. +Despite these guarantees, StatePulse.NET preserves the flexibility of traditional untracked state management, allowing developers to selectively enforce ordering and reliability without introducing global locks or compromising responsiveness.

    +

    Features​

    +

    Fast Fire-and-Yield
    +Executes actions immediately, including tracked actions, while preserving fire-and-yield semantics.

    +

    Multi-Layer Anti-Duplicate Dispatching +Layer 1: Cancels previously dispatched duplicates before effects, between effects, or after effects, ensuring no redundant action progresses through the pipeline. +Layer 2: Uses a global state-change ticker enforcing a strict β€œlatest action wins” rule so outdated or superseded actions cannot update state.

    +

    Effect Validator System
    +Supports multiple, composable validators for modular and reusable rule enforcement.

    +

    Synchronous Debug Mode
    +Provides an optional lockstep execution mode ideal for testing, diagnostics, and Task.WhenAll based pipelines.

    +

    DispatchTracker
    +Offers high-performance cancellation, deduplication, and concurrency control through an optimized tracking mechanism.

    +

    Short-Lived Middlewares +Provides lightweight, disposable middleware hooks that run only during the lifetime of a single dispatch cycle.

    +

    Dispatch Middlewares +Runs Before, After, and WhenDispatchFails. In asynchronous dispatch modes, failures are silently discarded unless handled internally, so DEC logic should manage its own errors; a logging middleware can also capture unhandled pipeline failures.

    +

    Effect Middlewares +Runs Before, After, WhenValidationFails, and WhenValidationSucceed, allowing fine‑grained control and instrumentation around effect execution and validation flow.

    +

    Reducer Middlewares +Runs Before and After the reducer, enabling patterns such as event dispatch on state changes, logging, instrumentation, or enforcing reducer‑level invariants.

    πŸš€ State Management with Zero Boilerplate and Zero Compromises​

    • Lazy State Access Model: Inject IStatePulse directly into your Blazor component and call StateOf<TState>(()=>this, TaskMethod) to get scoped state access.
    • @@ -37,18 +51,27 @@

      Benchmark​

      +
      MethodMeanErrorStdDevMedian
      StatePulse_Dispatch2.458 ΞΌs0.0344 ΞΌs0.0322 ΞΌs2.455 ΞΌs
      StatePulse_BusrtDispatch321.243 ΞΌs4.6181 ΞΌs4.3198 ΞΌs322.030 ΞΌs
      StatePulse_BusrtSafeDispatch350.282 ΞΌs4.4814 ΞΌs4.1919 ΞΌs351.182 ΞΌs
      StatePulse_FireYieldDispatch3.193 ΞΌs0.0631 ΞΌs0.0675 ΞΌs3.193 ΞΌs
      StatePulse_FireYield_SequentialEffectsDispatch3.326 ΞΌs0.0661 ΞΌs0.0969 ΞΌs3.303 ΞΌs
      StatePulse_AwaitedDispatch4.420 ΞΌs0.6850 ΞΌs2.0196 ΞΌs3.165 ΞΌs
      +

      StatePulse delivers strong performance given its feature set, but it’s not designed for tight, high‑frequency loops. Long‑term performance improvements are planned, as there are several areas with optimization potential. For now, the priority remains system stability, configuration robustness, and feature completeness.

      πŸ“¦ Installation & Setup​

      Install-Package StatePulse.Net

      dotnet add package StatePulse.Net

      -
      services.AddStatePulseServices(o =>
      {
      o.ScanAssemblies = new Type[] { typeof(Program) };
      });
      +

      3 Ways to Register Services​

      +

      Method 1
      +The most deterministic and explicit registration approach. This method avoids β€œmagic” and one‑liners by requiring you to manually add all Reducers, Effects, Middlewares, Validators, and Actions. It provides full clarity and control over what the system loads.

      +
          ServiceCollection.AddStatePulseServices(o =>
      {
      o.AutoRegisterTypes = [
      typeof(MainMenuLoaderStartAction),
      typeof(MainMenuLoaderStopAction),
      typeof(MainMenuLoadNavigationItemsAction),
      typeof(MainMenuLoadNavigationItemsResultAction),
      typeof(MainMenuOpenAction),
      typeof(ProfileCardDefineAction),
      typeof(ProfileCardDefineResultAction),
      typeof(ProfileCardLoaderStartAction),
      typeof(ProfileCardLoaderStopAction),
      typeof(UpdateCounterAction),
      typeof(ProfileCardDefineEffect),
      typeof(ProfileCardDefineResultAction),
      typeof(MainMenuLoadNavigationItemsEffect),
      typeof(MainMenuOpenEffect),
      typeof(MainMenuOpenEffectValidation),
      typeof(ProfileCardDefineActionValidator),
      typeof(MainMenuLoaderStartReducer),
      typeof(MainMenuLoaderStopReducer),
      typeof(MainMenuLoadNavigationItemsResultReducer),
      typeof(MainMenuOpenReducer),
      typeof(ProfileCardDefineResultReducer),
      typeof(UpdateCounterReducer),
      typeof(ProfileCardState),
      typeof(MainMenuState),
      typeof(CounterState),
      ];
      });
      +

      Method 2
      +This is also very explicit since v2+ we have a single entry AddStatePulseService for all statepulse types (Reducers, Effects, Middlewares, Validators, and Actions).

      +
          ServiceCollection.AddStatePulseServices();
      ServiceCollection.AddStatePulseService<MainMenuLoaderStartAction>();
      ServiceCollection.AddStatePulseService<MainMenuLoaderStopAction>();
      ServiceCollection.AddStatePulseService<MainMenuLoadNavigationItemsAction>();
      ServiceCollection.AddStatePulseService<MainMenuLoadNavigationItemsResultAction>();
      ServiceCollection.AddStatePulseService<MainMenuOpenAction>();
      ServiceCollection.AddStatePulseService<ProfileCardDefineAction>();
      ServiceCollection.AddStatePulseService<ProfileCardDefineResultAction>();
      ServiceCollection.AddStatePulseService<ProfileCardLoaderStartAction>();
      ServiceCollection.AddStatePulseService<ProfileCardLoaderStopAction>();
      ServiceCollection.AddStatePulseService<UpdateCounterAction>();
      ServiceCollection.AddStatePulseService<ProfileCardDefineEffect>();
      ServiceCollection.AddStatePulseService<MainMenuLoadNavigationItemsEffect>();
      ServiceCollection.AddStatePulseService<MainMenuOpenEffect>();

      ServiceCollection.AddStatePulseService<MainMenuOpenEffectValidation>();
      ServiceCollection.AddStatePulseService<ProfileCardDefineActionValidator>();

      ServiceCollection.AddStatePulseService<MainMenuLoaderStartReducer>();
      ServiceCollection.AddStatePulseService<MainMenuLoaderStopReducer>();
      ServiceCollection.AddStatePulseService<MainMenuLoadNavigationItemsResultReducer>();
      ServiceCollection.AddStatePulseService<MainMenuOpenReducer>();
      ServiceCollection.AddStatePulseService<ProfileCardDefineResultReducer>();
      ServiceCollection.AddStatePulseService<UpdateCounterReducer>();
      ServiceCollection.AddStatePulseService<ProfileCardState>();
      ServiceCollection.AddStatePulseService<MainMenuState>();

      ServiceCollection.AddStatePulseService<CounterState>();
      +

      Method 3 +The assembly-scan approach. Convenient but not recommended for most scenarios. While useful for rapid setup, it can introduce problems as system grows.

      +
          ServiceCollection.AddStatePulseServices(o => {
      o.ScanAssemblies = [typeof(TestBase).Assembly];
      });

      🧭 How It Works​

      Define Actions:​


      // IAction { }
      // ISafeAction { } // Cannot be dispatched unsafely

      public record ProfileCardDefineAction : IAction
      {
      public string? TestData { get; set; }
      }

      -

      Define Actions Validator (Optional):​

      -
      /*
      You are not required to create have an action validator but it is very useful when you have business logic that conditionally only contionally fires.
      When validation fails it ignores the dispatch and move on.
      */
      internal class ProfileCardDefineActionValidator : IActionValidator<ProfileCardDefineAction>
      {
      public void Validate(ProfileCardDefineAction action, ref ValidationResult result)
      {
      if (action.TestData == "Error")
      result.AddError("ErrorName", "Name Cannot be Error");
      }
      }

      Define Effect:​

      -

      internal class ProfileCardDefineEffect : IEffect<ProfileCardDefineAction>
      {

      public ProfileCardDefineEffect()
      {
      }
      public async Task EffectAsync(ProfileCardDefineAction action, IDispatcher dispatcher)
      {
      var random = new Random();
      int value = random.Next(100, 1001); // Upper bound is exclusive, so use 1001
      await Task.Delay(value);
      var myProfile = new UserResponse();
      await dispatcher.Prepare(() => new ProfileCardDefineResultAction(action.TestData ?? myProfile.Name, myProfile.Picture, myProfile.Id))
      .DispatchAsync();
      }

      }


      -

      Define Reducer:​

      -
      internal class ProfileCardDefineResultReducer : IReducer<ProfileCardState, ProfileCardDefineResultAction>
      {
      public Task<ProfileCardState> ReduceAsync(ProfileCardState state, ProfileCardDefineResultAction action)
      => Task.FromResult(state with
      {
      LastUpdate = DateTime.UtcNow,
      ProfileId = action.Id,
      ProfileName = action.Name,
      ProfilePicture = action.Picture
      });
      }
      +

      internal class ProfileCardDefineEffect : IEffect<ProfileCardDefineAction>
      {

      public ProfileCardDefineEffect()
      {
      }
      public async Task EffectAsync(ProfileCardDefineAction action, IDispatcher dispatcher)
      {
      var random = new Random();
      int value = random.Next(100, 1001); // Upper bound is exclusive, so use 1001
      await Task.Delay(value);
      var myProfile = new UserResponse();
      await dispatcher.Prepare(() => new ProfileCardDefineResultAction(action.TestData ?? myProfile.Name, myProfile.Picture, myProfile.Id))
      .DispatchAsync();
      }

      }



      ### **Define Effect Validator** (Optional):

      ```csharp
      /*
      * This is the best way to define clean conditional effects, it either run or not... this is not meant for triggering errors.
      * This is meant for optional/condition effects to either run or not base on the action settings...
      */
      internal class ProfileCardDefineActionValidator : IEffectValidator<ProfileCardDefineAction, ProfileCardDefineEffect>
      {
      public Task<bool> Validate(ProfileCardDefineAction action)
      {
      if (action.TestData == "Error")
      return Task.FromResult(false);
      return Task.FromResult(true);
      }
      }
      +

      ### **Define Reducer**:

      ```csharp
      internal class ProfileCardDefineResultReducer : IReducer<ProfileCardState, ProfileCardDefineResultAction>
      {
      public Task<ProfileCardState> ReduceAsync(ProfileCardState state, ProfileCardDefineResultAction action)
      => Task.FromResult(state with
      {
      LastUpdate = DateTime.UtcNow,
      ProfileId = action.Id,
      ProfileName = action.Name,
      ProfilePicture = action.Picture
      });
      }

      Define StateFeature:​

      public record ProfileCardState : IStateFeature
      {
      public string? ProfileName { get; set; }
      public string? ProfilePicture { get; set; }
      public string? ProfileId { get; set; }
      public DateTime LastUpdate { get; set; } = DateTime.UtcNow;
      }

      Trigger Dispatch:​

      @@ -56,12 +79,12 @@

      Tri

      Important Notes​

      • Rule of thumb is always await dispatch calls, avoiding to do so can cause inconsistency for safe dispatch mode..
      • -
      • ISafeAction implementations are always dispatched safely, ignoring unsafe flags.
      • +
      • ISafeAction implementations are always dispatched safely, ignoring unsafe flag.
      • synchronous is an anti-pattern of statemanement use it sparingly; it is primarily for debugging or specific scenarios requiring full completion before continuation.

      Access State:​

      var stateAccessor = ServiceProvider.GetRequiredService<IStateAccessor<ProfileCardState>>();

      Blazor Example Usage​

      -
      using StatePulse.Net;

      public partial class CounterView : ComponentBase
      {

      // METHOD 1:
      [Inject] public IStatePulse PulseState { get; set; } = default!; // Handles State Accessor

      // This is for convienience always use this method or directly PulseState.StateOf<CounterState>(this).Value
      // Never assign State Instance variable as it will not update...
      // Never use lambda it will throw exception as WeakREference is fundamatally flawed and disposes of lambda even when its object is alive.
      private CounterState state => PulseState.StateOf<CounterState>(()=>this, OnUpdate);

      private async Task OnUpdate() => await InvokeAsync(StateHasChanged);

      // METHOD 2:
      // Inject direct state but injecting the state directly requires you to handle onchanged events by sub/unsub in lifecycle
      // Or to create a basecomponent system similar to other state management systems.
      [Inject] public IStateAccessor<CounterState> State { get; set; } = default!;


      }

    +
    using StatePulse.Net;

    public partial class CounterView : ComponentBase
    {

    // METHOD 1:
    [Inject] public IStatePulse PulseState { get; set; } = default!; // Handles State Accessor

    // This is for convienience always use this method or directly PulseState.StateOf<CounterState>(this).Value
    // Never assign State Instance variable as it will not update...
    // Never use lambda it will throw exception as WeakREference is fundamatally flawed and disposes of lambda even when its object is alive.
    private CounterState state => PulseState.StateOf<CounterState>(()=>this, OnUpdate);

    private async Task OnUpdate() => await InvokeAsync(StateHadChanged);

    // METHOD 2:
    // Inject direct state but injecting the state directly requires you to handle onchanged events by sub/unsub in lifecycle
    // Or to create a basecomponent system similar to other state management systems.
    [Inject] public IStateAccessor<CounterState> State { get; set; } = default!;


    }
    \ No newline at end of file diff --git a/doc/build/markdown-page/index.html b/doc/build/markdown-page/index.html index 56f57d7..33f3a7a 100644 --- a/doc/build/markdown-page/index.html +++ b/doc/build/markdown-page/index.html @@ -5,14 +5,14 @@ Markdown page example | StatePulse.NET - - + +

    Markdown page example

    -

    You don't need React to write simple standalone pages.

    +

    You don't need React to write simple standalone pages.

    \ No newline at end of file diff --git a/doc/build/setup-blazor-project/index.html b/doc/build/setup-blazor-project/index.html index 714f104..0571824 100644 --- a/doc/build/setup-blazor-project/index.html +++ b/doc/build/setup-blazor-project/index.html @@ -5,8 +5,8 @@ Setup Blazor Project | StatePulse.NET - - + + @@ -15,18 +15,20 @@

    Setup Blazor Project

    πŸ“¦ Installation & Setup​

    Install-Package StatePulse.Net

    dotnet add package StatePulse.Net

    Add to Program.cs:

    -
    builder.Services.AddStatePulseServices(o => {});
    +
    builder.Services.AddStatePulseServices();

    Create StatePulse common folder structure.

    /Pulses/
    /Pulses/Counter <- Feature
    /Pulses/Counter/Actions
    /Pulses/Counter/Effects
    /Pulses/Counter/Effects/Validators
    /Pulses/Counter/Reducers
    /Pulses/Counter/Stores

    This structure is complete and very common pattern.

    Add Services​

    -

    There are 2 ways to add services for StatePulse.

    -

    Scan Assmblies​

    -

    The easiest way is to scan whatever assembly you have pulses in.

    -
    program.cs
    builder.Services.AddStatePulseServices(o =>
    {
    o.ScanAssemblies = new Type[] { typeof(Program) };
    });
    -

    Manual Registering​

    -

    StatePulse provide extension methods to add type of services and you MUST use them otherwise you face issues.

    -
    program.cs
    builder.Services.AddStatePulseAction<IAction>();
    builder.Services.AddStatePulseEffect<IEffect>();
    builder.Services.AddStatePulseEffectValidator<IEffectValidator>();
    builder.Services.AddStatePulseReducer<IReducer>();
    builder.Services.AddStatePulseStateFeature<IStateFeature>();
    -

    Note: you must manually register all services during unit test... the assembly scan doesn't get along well with unit testing.

    +

    Method 1
    +The most deterministic and explicit registration approach. This method avoids β€œmagic” and one‑liners by requiring you to manually add all Reducers, Effects, Middlewares, Validators, and Actions. It provides full clarity and control over what the system loads.

    +
        ServiceCollection.AddStatePulseServices(o =>
    {
    o.AutoRegisterTypes = [
    typeof(WHATEVER_STATEPULSE_TYPE),
    ];
    });
    +

    Method 2
    +This is also very explicit since v2+ we have a single entry AddStatePulseService for all statepulse types (Reducers, Effects, Middlewares, Validators, and Actions).

    +
        ServiceCollection.AddStatePulseServices(); // Register Base Services
    ServiceCollection.AddStatePulseService<WHATEVER_STATEPULSE_TYPE>();
    +

    Method 3 +The assembly-scan approach. Convenient but not recommended for most scenarios. While useful for rapid setup, it can introduce problems as system grows.

    +
        ServiceCollection.AddStatePulseServices(o => {
    o.ScanAssemblies = [typeof(TestBase).Assembly];
    });
    +

    Note: The assembly scan doesn't get along well with unit testing.

    \ No newline at end of file diff --git a/doc/build/tags/actions/index.html b/doc/build/tags/actions/index.html index 2e85ee2..1e01eef 100644 --- a/doc/build/tags/actions/index.html +++ b/doc/build/tags/actions/index.html @@ -5,13 +5,13 @@ 2 docs tagged with "actions" | StatePulse.NET - - + + -

    2 docs tagged with "actions"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    +

    2 docs tagged with "actions"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    \ No newline at end of file diff --git a/doc/build/tags/async/index.html b/doc/build/tags/async/index.html index d0c2976..904ea85 100644 --- a/doc/build/tags/async/index.html +++ b/doc/build/tags/async/index.html @@ -5,13 +5,13 @@ 4 docs tagged with "async" | StatePulse.NET - - + + -

    4 docs tagged with "async"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    +

    4 docs tagged with "async"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    \ No newline at end of file diff --git a/doc/build/tags/await/index.html b/doc/build/tags/await/index.html index aa56b72..12bd513 100644 --- a/doc/build/tags/await/index.html +++ b/doc/build/tags/await/index.html @@ -5,13 +5,13 @@ One doc tagged with "await" | StatePulse.NET - - + + -

    One doc tagged with "await"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    +

    One doc tagged with "await"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    \ No newline at end of file diff --git a/doc/build/tags/blazor/index.html b/doc/build/tags/blazor/index.html index feb8eed..c6adf20 100644 --- a/doc/build/tags/blazor/index.html +++ b/doc/build/tags/blazor/index.html @@ -5,13 +5,13 @@ 7 docs tagged with "blazor" | StatePulse.NET - - + + -

    7 docs tagged with "blazor"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    +

    7 docs tagged with "blazor"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    \ No newline at end of file diff --git a/doc/build/tags/csharp/index.html b/doc/build/tags/csharp/index.html index 52ed44d..3bb466f 100644 --- a/doc/build/tags/csharp/index.html +++ b/doc/build/tags/csharp/index.html @@ -5,13 +5,13 @@ 6 docs tagged with "csharp" | StatePulse.NET - - + + -

    6 docs tagged with "csharp"

    View all tags
    +

    6 docs tagged with "csharp"

    View all tags
    \ No newline at end of file diff --git a/doc/build/tags/dependency-injection/index.html b/doc/build/tags/dependency-injection/index.html index 1b216d0..34aab7b 100644 --- a/doc/build/tags/dependency-injection/index.html +++ b/doc/build/tags/dependency-injection/index.html @@ -5,13 +5,13 @@ One doc tagged with "dependency-injection" | StatePulse.NET - - + + -

    One doc tagged with "dependency-injection"

    View all tags
    +

    One doc tagged with "dependency-injection"

    View all tags
    \ No newline at end of file diff --git a/doc/build/tags/dispatcher/index.html b/doc/build/tags/dispatcher/index.html index 8595a98..7148c0f 100644 --- a/doc/build/tags/dispatcher/index.html +++ b/doc/build/tags/dispatcher/index.html @@ -5,13 +5,13 @@ One doc tagged with "dispatcher" | StatePulse.NET - - + + -

    One doc tagged with "dispatcher"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    +

    One doc tagged with "dispatcher"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    \ No newline at end of file diff --git a/doc/build/tags/effects/index.html b/doc/build/tags/effects/index.html index a0b99f1..f6e0793 100644 --- a/doc/build/tags/effects/index.html +++ b/doc/build/tags/effects/index.html @@ -5,13 +5,13 @@ One doc tagged with "effects" | StatePulse.NET - - + + -

    One doc tagged with "effects"

    View all tags
    +

    One doc tagged with "effects"

    View all tags
    \ No newline at end of file diff --git a/doc/build/tags/immutable/index.html b/doc/build/tags/immutable/index.html index 9470a8d..84ee5ab 100644 --- a/doc/build/tags/immutable/index.html +++ b/doc/build/tags/immutable/index.html @@ -5,13 +5,13 @@ One doc tagged with "immutable" | StatePulse.NET - - + + -

    One doc tagged with "immutable"

    View all tags
    +

    One doc tagged with "immutable"

    View all tags
    \ No newline at end of file diff --git a/doc/build/tags/index.html b/doc/build/tags/index.html index 32fe97c..1eefd1d 100644 --- a/doc/build/tags/index.html +++ b/doc/build/tags/index.html @@ -5,13 +5,13 @@ Tags | StatePulse.NET - - + + - + \ No newline at end of file diff --git a/doc/build/tags/installation/index.html b/doc/build/tags/installation/index.html index 209bb9c..995302f 100644 --- a/doc/build/tags/installation/index.html +++ b/doc/build/tags/installation/index.html @@ -5,13 +5,13 @@ One doc tagged with "installation" | StatePulse.NET - - + + -

    One doc tagged with "installation"

    View all tags
    +

    One doc tagged with "installation"

    View all tags
    \ No newline at end of file diff --git a/doc/build/tags/isafeaction/index.html b/doc/build/tags/isafeaction/index.html index 5df359d..1ccdb95 100644 --- a/doc/build/tags/isafeaction/index.html +++ b/doc/build/tags/isafeaction/index.html @@ -5,13 +5,13 @@ One doc tagged with "isafeaction" | StatePulse.NET - - + + -

    One doc tagged with "isafeaction"

    View all tags
    +

    One doc tagged with "isafeaction"

    View all tags
    \ No newline at end of file diff --git a/doc/build/tags/net/index.html b/doc/build/tags/net/index.html index 7323be1..52fed15 100644 --- a/doc/build/tags/net/index.html +++ b/doc/build/tags/net/index.html @@ -5,13 +5,13 @@ 6 docs tagged with ".net" | StatePulse.NET - - + + -

    6 docs tagged with ".net"

    View all tags
    +

    6 docs tagged with ".net"

    View all tags
    \ No newline at end of file diff --git a/doc/build/tags/performance/index.html b/doc/build/tags/performance/index.html index 372b181..68ddb89 100644 --- a/doc/build/tags/performance/index.html +++ b/doc/build/tags/performance/index.html @@ -5,13 +5,13 @@ 2 docs tagged with "performance" | StatePulse.NET - - + + -

    2 docs tagged with "performance"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    +

    2 docs tagged with "performance"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    \ No newline at end of file diff --git a/doc/build/tags/pure-functions/index.html b/doc/build/tags/pure-functions/index.html index 2b5703f..3ebacee 100644 --- a/doc/build/tags/pure-functions/index.html +++ b/doc/build/tags/pure-functions/index.html @@ -5,13 +5,13 @@ 2 docs tagged with "pure-functions" | StatePulse.NET - - + + -

    2 docs tagged with "pure-functions"

    View all tags
    +

    2 docs tagged with "pure-functions"

    View all tags
    \ No newline at end of file diff --git a/doc/build/tags/reducer/index.html b/doc/build/tags/reducer/index.html index 30c51ec..c32b737 100644 --- a/doc/build/tags/reducer/index.html +++ b/doc/build/tags/reducer/index.html @@ -5,13 +5,13 @@ 2 docs tagged with "reducer" | StatePulse.NET - - + + -

    2 docs tagged with "reducer"

    View all tags
    +

    2 docs tagged with "reducer"

    View all tags
    \ No newline at end of file diff --git a/doc/build/tags/redux/index.html b/doc/build/tags/redux/index.html index 84ad310..1772388 100644 --- a/doc/build/tags/redux/index.html +++ b/doc/build/tags/redux/index.html @@ -5,13 +5,13 @@ One doc tagged with "redux" | StatePulse.NET - - + + -

    One doc tagged with "redux"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    +

    One doc tagged with "redux"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    \ No newline at end of file diff --git a/doc/build/tags/safedispatch/index.html b/doc/build/tags/safedispatch/index.html index 099015f..2eba759 100644 --- a/doc/build/tags/safedispatch/index.html +++ b/doc/build/tags/safedispatch/index.html @@ -5,13 +5,13 @@ One doc tagged with "safedispatch" | StatePulse.NET - - + + -

    One doc tagged with "safedispatch"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    +

    One doc tagged with "safedispatch"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    \ No newline at end of file diff --git a/doc/build/tags/setup/index.html b/doc/build/tags/setup/index.html index 1a37dd2..f6d661a 100644 --- a/doc/build/tags/setup/index.html +++ b/doc/build/tags/setup/index.html @@ -5,13 +5,13 @@ One doc tagged with "setup" | StatePulse.NET - - + + -

    One doc tagged with "setup"

    View all tags
    +

    One doc tagged with "setup"

    View all tags
    \ No newline at end of file diff --git a/doc/build/tags/side-effects/index.html b/doc/build/tags/side-effects/index.html index 509ce46..3166ce6 100644 --- a/doc/build/tags/side-effects/index.html +++ b/doc/build/tags/side-effects/index.html @@ -5,13 +5,13 @@ One doc tagged with "side-effects" | StatePulse.NET - - + + -

    One doc tagged with "side-effects"

    View all tags
    +

    One doc tagged with "side-effects"

    View all tags
    \ No newline at end of file diff --git a/doc/build/tags/state-management/index.html b/doc/build/tags/state-management/index.html index c477572..0ddb845 100644 --- a/doc/build/tags/state-management/index.html +++ b/doc/build/tags/state-management/index.html @@ -5,13 +5,13 @@ 6 docs tagged with "state-management" | StatePulse.NET - - + + -

    6 docs tagged with "state-management"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    +

    6 docs tagged with "state-management"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    \ No newline at end of file diff --git a/doc/build/tags/state/index.html b/doc/build/tags/state/index.html index a57410b..4052ece 100644 --- a/doc/build/tags/state/index.html +++ b/doc/build/tags/state/index.html @@ -5,13 +5,13 @@ One doc tagged with "state" | StatePulse.NET - - + + -

    One doc tagged with "state"

    View all tags
    +

    One doc tagged with "state"

    View all tags
    \ No newline at end of file diff --git a/doc/build/tags/statepulse/index.html b/doc/build/tags/statepulse/index.html index b601ca9..412ccc1 100644 --- a/doc/build/tags/statepulse/index.html +++ b/doc/build/tags/statepulse/index.html @@ -5,13 +5,13 @@ 7 docs tagged with "statepulse" | StatePulse.NET - - + + -

    7 docs tagged with "statepulse"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    +

    7 docs tagged with "statepulse"

    View all tags

    The Dispatcher

    πŸš€ Dispatcher – Executing Actions in StatePulse

    \ No newline at end of file diff --git a/doc/build/versions/index.html b/doc/build/versions/index.html index b69f626..91ccb49 100644 --- a/doc/build/versions/index.html +++ b/doc/build/versions/index.html @@ -3,78 +3,159 @@ -Updates | StatePulse.NET +Updates | StatePulse.NET - - + + -

    Updates

    πŸ“¦ v2.0.0​

    -

    ✨ BREAKING CHANGES​

    +

    Updates

    v2.0.0​

    +

    BREAKING CHANGES​

      -
    • The signature of interfaces changed so any plugin-based system could potentially break if core updates and plugins don't unless plugin isolation is respected.
    • -
    • The REDUCERS now run before the effects! so any pipelines relying on post-effect reducers should configure StatePulse to execute reducers post effect (simple config flip) Configure.DispatchOrderBehavior = DispatchOrdering.EffectsFirst;.
    • +
    • +

      Interface signatures have changed.
      +Core interface updates may break plugin‑based systems if the core updates while plugins do not.
      +This is only safe when proper plugin isolation is respected.

      +
    • +
    • +

      Reducers now run before effects.
      +The default dispatch order has changed.
      +Pipelines that rely on reducers running after effects must update their configuration to restore the previous behavior.

      +
    • +
    • +

      Middleware between individual effects has been removed.
      +Per‑effect middleware proved unreliable and is no longer supported.
      +All effects now run as a batch, followed by a single AfterEffect phase.
      +Middleware can still be awaited before the BeforeEffect phase and after the AfterEffect phase. +Middlewares for effects if not awaited they are still ganrantueed to be running sequentially BeforeEffect Parallel with Effects then AfterEffects.

      +
    • +
    • +

      Actions can never be singleton.
      +Action are essentially data contract and should remain at the scope level which in blazor server case is circuit bound.

      +
    • +
    • +

      Effects, Reducers, Middleware, EffectValidators no long transient
      +Transient lifetime for those is unecessary as none of them should ever hold state of their own therefore they act like static method filled with logic alone... let's eliminate transient overhead and put scoped as default and singleton with the singleton interfaces.

      +
    • +
    • +

      Configuration Scan Assembly Type Changed
      +The property ConfigureOptions.ScanAssemblies is now taking a Assembly[] instead of Type[].

      +
    • +
    • +

      IPulseGlobalTracker registration changed
      +The IPulseGlobalTracker is now registered as Scoped instead of singleton... issues were occuring with some blazor server projects.

      +
    • +
    • +

      Removed .AddStatePulse<Action,Effect,Reducer,State>
      +the extension method were removed from public access... now you use .AddStatePulseService<Implementation>() which will auto detect from action to effect to reducers to middlewares. +Reason: Better dev experience less confusing and annoying when having to register stuff manually instead of by scanning. +Alternative: You can also add types into .AddStatePulseServices(o=>{ o.AutoRegisterTypes = [typeof(AAA)];}); which will perform manual registration automatically without scanning assemblies.

      +
    • +
    • +

      Added to IDispatchMiddleware +OnDispatchFailure(Exception exception, object action) is now available to middleware hit is receive on any dispatch failure...

      +
    • +
    • +

      Removed Throw for Dispatch Failure +Re-Throw only occurs when using Synchronous Await() otherwise dispatch will swallow any uncaught exception thrown at it.

      +
    • +
    • +

      Reducers are no longer Tasks +With the full introduction of middlewares it is no longer justifiable to have reducers as Task... nothing should be in the reducers to the exception of generating a new state.

      +
    • +
    • +

      ReducerExt is removed +ReducerExt is no longer available as it was used as helper for Task return.

      +
    • +
    • +

      IDispatcherPrepper<TAction> Prepare<TAction>(Func<TAction> createInstance) deprecated +Use Prepared(instance).DispatchAsync() instead;

      +
    -

    ✨ New Features​

    +

    New Features​

      -
    • βš™οΈ Enhanced Configuration Options - New global configuration properties: +
    • Enhanced Configuration Options - New global configuration properties:
      • DispatchOrderBehavior - Set default ordering (EffectsFirst/ReducersFirst)
      • DispatchEffectExecutionBehavior - Set default execution mode (YieldAndFire/FireAndForget)
    • -
    • πŸŽ›οΈ Configurable Dispatch Ordering - Choose between EffectsFirst (default) or ReducersFirst execution order globally or per-dispatch
    • -
    • ⚑ True Fire-and-Forget Execution Mode - New DispatchEffectExecutionBehavior.FireAndForget for true background execution without yielding and awaiting effects
    • -
    • πŸ”§ Per-Dispatch Execution Control - Override global settings per dispatch with fluent API: +
    • Configurable Dispatch Ordering - Choose between EffectsFirst (default) or ReducersFirst execution order globally or per-dispatch
    • +
    • Configurable Dispatch Ordering - The Middleware BeforeReducers will run before the AfterReducer as garantueed...
    • +
    • The reducer will however run in parallel with BeforeReducing if settings is to not await for middlewares.
    • +
    • True Fire-and-Forget Execution Mode - New DispatchEffectExecutionBehavior.FireAndForget for true background execution without yielding and awaiting effects
    • +
    • Per-Dispatch Execution Control - Override global settings per dispatch with fluent API:
        -
      • .ExecFireAndForget() - Fully detached background execution
      • -
      • .ExecYieldAndFire() - Yield to caller but await until all effects are done to move down the pipeline
      • .EffectsFirst() - Run effects before reducers
      • .ReducersFirst() - Run reducers before effects
      • .SequentialEffects() - Force effects to run in sequence
      • .ParallelEffects() - Force effects to run in parallel
    • -
    • πŸ›‘οΈ Invalid Configuration Detection - New InvalidDispatchCombinationException thrown at dispatch time for incompatible configuration combinations (Plan to generate compiler errors later)
    • -
    • ♻️ Recursive Dispatch Support - Fire-and-forget mode enables safe recursive dispatch patterns without deadlocks
    • -
    -

    πŸ“¦ v1.1.0​

    -

    ✨ Minor Change​

    +
  • Invalid Configuration Detection - New InvalidDispatchCombinationException thrown at dispatch time for incompatible configuration combinations (Plan to generate compiler errors later)
  • +
  • Recursive Dispatch Support - Fire-and-forget mode enables safe recursive dispatch patterns without deadlocks
  • +
  • PulseTrackingModel - Clear option for the tracking model! Either Thread-Safe (Default) or Single Threaded Fast Application... WASM/Blazor Server.
  • +
  • GlobalTrackerLifetime - Define clearly lifetime scope for the Global Tracker singleton or scoped. BlazorServer, WASM, Scoped (Default) or Singleton.
  • +
  • IStateFeatureSingleton - Define a singleton state across your app... not useful in WASM but very useful in Blazor Server... where one can share the state across client each client run their own action but the state update spread across all circuits.
  • +
  • IReducer, IEffect, IEffectValidation, IEffectMiddleware, IReducerMiddleware - Are ALWAYS transient from now on.
  • +
  • StateVersioning long global ticker used to calculate version of a state... this will help prevent further race conditions related to multi-threading (blazor server singleton).
  • +
  • State update will automatically discard stale states. you can also acces the information using IStateAccessor
  • +
  • Roslyn Analyzer will now trigger error .Prepare<OBJECT>(entity) if constructor object does not match the underlying object's constructor type and it supports overload.
  • +
  • Roslyn Analyzer will now trigger error .Prepare<OBJECT>().With(p => p.PROP, data) when PROP is init; or get; only... this will eleminate runtime issues.
  • + +

    Security​

    +
      +
    • Roslyn will now enforce _statePulse.StateOf<StateMe>(() => this, OnUpdate); on the two arguments this will avoid runtime errors and potential memory leaks.
    • +
    • Fixed All Configure Internal...
    • +
    +

    Fixes​

    +
      +
    • Fixed Various Warnings
    • +
    • Fixed All Configure Internal...
    • +
    • Fixed Middleware are now added via Scanned Assemblies.
    • +
    • Fixed some issues where Await() was not respected.
    • +
    • Fixed major issue where all race condition elements where cancelled leading to full chain cancellation including the last action.
    • +
    • Fixed inconsistence with race conditions.
    • +
    • Fixed StateOf<TState>() throwing inability to cast to IStateAccessor<object>.
    • +
    • Fixed AddStatePulseServices() configuration not optional.
    • +
    +

    v1.1.0​

    +

    Minor Change​

    • Upgraded to .NET 10
    -

    πŸ“¦ v1.0.2​

    -

    🐞 Fixes​

    +

    v1.0.2​

    +

    Fixes​

    • Added StatePulse.Net.Abstractions package reference instead of project reference to fix IL trimming issues.
    -

    πŸ“¦ v1.0.1​

    -

    ✨ Minor Change​

    +

    v1.0.1​

    +

    Minor Change​

    • Splited Abstractions into StatePulse.Net.Abstractions (Will not break anything Namespace is the same)
    -

    πŸ“¦ v1.0.0​

    -

    ✨ New Features​

    +

    v1.0.0​

    +

    New Features​

      -
    • βœ… Action Effect Validator: Allows effects to run conditionally by validating them before execution.
    • -
    • 🧩 Middleware Support: +
    • Action Effect Validator: Allows effects to run conditionally by validating them before execution.
    • +
    • Middleware Support:
      • IEffectMiddleware
      • IReducerMiddleware
      • IDispatchMiddleware
    • -
    • βš™οΈ Behavior Configuration: You can configure execution behaviors via: +
    • Behavior Configuration: You can configure execution behaviors via:
      • DispatchEffectBehavior
      • MiddlewareEffectBehavior
      • MiddlewareTaskBehavior
    • -
    • πŸ› οΈ Strict Manual Registration: Manual service registration must use extension methods: +
    • Strict Manual Registration: Manual service registration must use extension methods:
      • AddStatePulse()
      • AddStatePulseEffect<>()
      • @@ -85,10 +166,10 @@

        ✨ New Feat

    -

    πŸ’₯ Breaking Changes​

    +

    πŸ’₯ Breaking Changes​

      -
    • ❌ Removed Action Validator – validating action data is not the responsibility of the state management layer.
    • -
    • πŸ”„ Renamed: +
    • Removed Action Validator – validating action data is not the responsibility of the state management layer.
    • +
    • Renamed:
      • IStateAccessor<>.StateChanged β†’ OnStateChanged
      • UsingSynchronousMode β†’ Removed
      • @@ -98,18 +179,18 @@

        πŸ’₯ Bre

      πŸš€ Performance Improvements​

        -
      • 🧠 Improved dispatcher caching
      • -
      • ⚑ Enhanced type cache in StatePulseRegistry
      • -
      • 🧬 Replaced reflection with dynamic method caching for faster dispatching
      • +
      • Improved dispatcher caching
      • +
      • Enhanced type cache in StatePulseRegistry
      • +
      • Replaced reflection with dynamic method caching for faster dispatching

      🧼 Clean Code Improvements​

        -
      • 🧹 Refactored DispatchPrepper for cleaner and lighter internal logic
      • +
      • Refactored DispatchPrepper for cleaner and lighter internal logic
      -

      🐞 Fixes​

      +

      🐞 Fixes​

        -
      • πŸ› οΈ Resolved several null reference warnings
      • -
      • 🧽 Removed leftover internal artifacts
      • +
      • Resolved several null reference warnings
      • +
      • Removed leftover internal artifacts

      v0.9.41​

        @@ -131,6 +212,6 @@

        v0.9.2
        • Deprecated now part of StatePulse regular since we have removed the dependencies to blazor component. ... that was quick!
        • -

    +
    \ No newline at end of file diff --git a/doc/docs/0.Versions.md b/doc/docs/0.Versions.md index f05e2c2..45c618c 100644 --- a/doc/docs/0.Versions.md +++ b/doc/docs/0.Versions.md @@ -34,7 +34,7 @@ sidebar_position: 0 The IPulseGlobalTracker is now registered as Scoped instead of singleton... issues were occuring with some blazor server projects. -- **Removed .AddStatePulse** +- **Removed `.AddStatePulse`** the extension method were removed from public access... now you use `.AddStatePulseService()` which will auto detect from action to effect to reducers to middlewares. Reason: Better dev experience less confusing and annoying when having to register stuff manually instead of by scanning. Alternative: You can also add types into `.AddStatePulseServices(o=>{ o.AutoRegisterTypes = [typeof(AAA)];});` which will perform manual registration automatically without scanning assemblies. @@ -51,7 +51,7 @@ sidebar_position: 0 - **ReducerExt is removed** ReducerExt is no longer available as it was used as helper for Task return. -- **IDispatcherPrepper Prepare(Func createInstance) deprecated** +- **`IDispatcherPrepper Prepare(Func createInstance)` deprecated** Use Prepared(instance).DispatchAsync() instead; ### New Features diff --git a/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs b/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs index 74d0891..2cfb573 100644 --- a/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs +++ b/src/StatePulse.NET/Engine/Implementations/DispatcherPrepper.cs @@ -71,6 +71,7 @@ public async Task DispatchSafeAsync() private static MethodInfo? _cachedEffectMethod; private static MethodInfo? _cachedActionValidatorMethod; + private static readonly object _lock = new(); protected async Task ProcessDispatch(bool entryPoint, Guid nextId) { // we are tracking next chain key only when there is an entry point to avoid tracker during fast dispatch. @@ -173,8 +174,10 @@ private async Task RunEffects(DispatchTrackingIdentity? nextChain, DispatchFacto continue; // skip - if (_cachedEffectMethod == default) - _cachedEffectMethod = effectType.GetMethod(nameof(IEffect.EffectAsync))!; + lock (_lock) + if (_cachedEffectMethod == default) + _cachedEffectMethod = effectType.GetMethod(nameof(IEffect.EffectAsync))!; + var del = (Func)Delegate.CreateDelegate(typeof(Func), effectService, _cachedEffectMethod); if (del(_action, dispatcherService.Dispatcher) is Task effectTask) From 59c6211ef9236a12c88b3ae764650125ec5588a8 Mon Sep 17 00:00:00 2001 From: "m.samson" Date: Wed, 28 Jan 2026 16:13:08 +0200 Subject: [PATCH 27/27] - updated Version --- src/Directory.Packages.props | 2 +- src/StatePulse.NET/StatePulse.NET.csproj | 2 +- .../StatePulse.Net.Abstractions.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index bfd7e2d..3555e5d 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -1,6 +1,6 @@ - 2.0.537 + 2.0.0 Maksim Shimshon Β© 2026 diff --git a/src/StatePulse.NET/StatePulse.NET.csproj b/src/StatePulse.NET/StatePulse.NET.csproj index 0792ac8..90c55a3 100644 --- a/src/StatePulse.NET/StatePulse.NET.csproj +++ b/src/StatePulse.NET/StatePulse.NET.csproj @@ -18,7 +18,7 @@ $(GlobalCopyright) LICENSE True - StatePulse.NET enables fast, consistent state/action dispatch with optional tracking and anti-duplicate flow control. It supports ordered chaining when needed, while maintaining high-performance fire-and-forget behavior for general use cases. + StatePulse.NET delivers fast, consistent state and action dispatch with optional tracking and anti‑duplicate flow control. It supports ordered chaining when required, while preserving high‑performance fire‑and‑yield behavior for everyday scenarios. icon.png blazor;state management;flux;dotnet;redux;components;webassembly diff --git a/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj b/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj index b29a94b..8e79b3f 100644 --- a/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj +++ b/src/StatePulse.Net.Abstractions/StatePulse.Net.Abstractions.csproj @@ -18,7 +18,7 @@ $(GlobalCopyright) LICENSE True - StatePulse.NET enables fast, consistent state/action dispatch with optional tracking and anti-duplicate flow control. It supports ordered chaining when needed, while maintaining high-performance fire-and-forget behavior for general use cases. + StatePulse.NET delivers fast, consistent state and action dispatch with optional tracking and anti‑duplicate flow control. It supports ordered chaining when required, while preserving high‑performance fire‑and‑yield behavior for everyday scenarios. icon.png blazor;state management;flux;dotnet;redux;components;webassembly